Docker 배포 : 쉽게 시작하기
🐋 Docker를 서버에 배포하는 방법을 알아보겠습니다. 수동 배포 부터 시작해 봅시다!
도커 이미지 생성
API 코드
배포 할 API 서버 코드를 먼적 작성하겠습니다. FastAPI로 작성된 문자열을 반환하는 간단한 코드 입니다. run.py
파일에 코드를 작성하겠습니다.
project/
└── run.py (추가 파일)
from fastapi import FastAPI
from fastapi.responses import PlainTextResponse
app = FastAPI()
@app.get("/")
def health(response_class=PlainTextResponse):
return "Hello Docker Container"
Dockerfile 작성
Docker 이미지를 생성할 때 사용하는 Dockerfile
을 작성하겠습니다.
project/
├── Dockerfile (추가 파일)
└── run.py
FROM python:3.12-alpine
RUN pip install "fastapi[standard]"
WORKDIR /app
COPY . .
EXPOSE 8000
CMD ["uvicorn", "run:app", "--host", "0.0.0.0", "--port", "8000"]
docker 이미지 생성
작성한 도커 파일(Dockerfile)을 사용하여 이미지를 빌드합니다. 이때 해당 이미지에 대한 tag를 -t
옵션으로 부여하고, 이후 도커 허브에 이미지를 push 할 때 사용합니다.
$ docker build -t tiaz0128/fast-api .
docker.com 가입
docker.com에 가입하고 로그인 합니다. 가입 할때 생성하는 Username
은 도커 이미지를 저장하는 도커 허브(Docker Hub)에 사용 됩니다.
> GitHub와 유사한 형태의 Docker Hub
Docker Hub : 이미지 push
Docker Hub는 빌드한 도커 이미지를 저장하는 레포지토리 입니다. repositories탭에서 Username을 네임스페이스로 Repository Name으로 레포지토리를 생성합니다.
비결제 계정당 하나의 Private 레포지토리를 사용 할 수 있습니다. 여기서는 Public 레포지토리를 fast-api
라는 이름으로 만들도록 하겠습니다.
> Docker Hub : 이미지를 저장하는 원격 저장소
docker login
빌드한 이미지를 도커 허브에 push 하겠습니다. 우선 docker.io에 등록한 이메일이나 Username으로 로그인 가능합니다.
$ docker login docerk.io
Username: tiaz0128.dev@gmail.com
Password: ****
Login Succeeded
빌드한 이미지 push
이미지를 Docker Hub에 push 하기 위해서는 docker.io에서 등록된 Username와 repository 이름을 기반으로 push 할 수 있습니다.
Docker Hub를 사용할 때는 일반적으로 Username/repository
형식을 따라야 합니다.
이는 Docker Hub가 사용자별로 네임스페이스를 관리하기 때문입니다.
$ docker push <Username>/<repository>[:tag]
$ docker push tiaz0128/fast-api
docker tag
docker tag
명령어는 Docker 이미지에 태그를 추가하거나 변경하는 데 사용됩니다. 기본 사용법은 다음과 같습니다.
$ docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
$ docker tag fast-api:1.0 tiaz0128/fast-api
SOURCE_IMAGE
: 태그를 변경하려는 원본 이미지의 이름과 태그TARGET_IMAGE
: 새로 지정할 이미지 이름과 태그[:TAG]
: 선택사항, 특정 태그를 지정. 생략하면 기본값으로 latest 적용
Docker 수동 배포
어떤 환경이던 서버 환경이든 상관없습니다. 여기서는 EC2(Amazon Linux 2023 AMI)에서 진행했습니다.
docker 설치
가장 먼저 서버에 docker
를 설치합니다.
$ sudo yum update -y
$ sudo yum -y install docker
데몬 & 권한 추가
설치 후에는 데몬을 켜 줍니다. 필요시 사용자 그룹 권한을 수정 해줍니다. 사용자(ec2-user)를 docker 그룹에 추가합니다. 이를 통해 ec2-user는 sudo 없이 docker
명령어를 실행할 수 있게 됩니다.
$ sudo systemctl restart docker
$ sudo usermod -a -G docker ec2-user
Docker pull
도커 허브에 로그인 하고 빌드 한 이미지를 받습니다.
$ docker login
Username: tiaz0128.dev@gmail.com
Password:
$ docker pull tiaz0128/fast-api
docker run & stop
pull 받은 이미지로 컨테이너를 실행 합니다. 실행 중인 컨테이너가 있다면 정지 후, 새로운 컨네이터를 실행하는 방식으로 수동으로 배포가 가능합니다.
$ docker run -it -d --name fast-api --rm tiaz0128/fast-api
수동 배포의 문제점
여기까지 수동으로 도커 컨테이너를 배포해보았습니다. 그렇다면 여기서 이런 생각이 듭니다.
코드가 수정되고 이미지가 새로 만들어지면 어떻게 하지?
앞서 했던 것처럼 매번 수동으로 이미지를 풀(pull)받고 컨테이터를 재시작해야 할 것입니다.
이런 문제를 해결하기 위한 여러가지 방법이 있지만, 여기서는 간단한 Watchtower
를 사용해 보겠습니다.
Watchtower
Watchtower는 정기적으로 이미지 업데이트를 확인하고, 새 버전이 있으면 자동으로 컨테이너를 업데이트합니다. Watchtower 컨테이너를 실행 시켜 놓기만 하면 이미지를 가져와서 기존 컨테이너를 정상적으로 종료한 후, 처음 배포될 때 사용된 것과 동일한 옵션으로 재시작합니다.
Watchtower 기본 사용법
아래의 명령을 통해 EC2 내부에 동작 중인 fast-api
라는 컨테이너를 모니터링 합니다. 여러개 컨테이너를 한번에 모니터링 또한 가능 합니다.
$ docker ps
CONTAINER ID IMAGE NAMES
dad54e31fb2b tiaz0128/fast-api:latest fast-api
$ docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
fast-api
Watchtower 주요 옵션
--interval
: 업데이트 확인 주기 설정. 초단위, default: 86400(24H)--schedule
: 6개 필드 Cron 표현식 설정. --interval 중에 하나만 사용 가능--run-once
: 컨테이너 이름 목록에 대해 업데이트를 한 번만 시도하고 Watchtower 종료
남은 과제와 GitOps
git 배포와 docker 이미지 배포를 각각 수행해야 하는 불편함이 남아있습니다. 이러한 문제를 해결 하기 위해 GitOps
라는 방법론이 등장 합니다.
이 방법론의 핵심 아이디어는 단일 진실 원천(single source of truth)으로 Git 레포지토리를 모든 것의 기준점으로 삼는 것입니다.
> 따배 : [따배GitOps] 0. 강의 소개
마무리
빌드한 이미지를 도커 허브에 push 하고 빌드된 이미지를 Docker EC2에 처음에는 수동으로 배포해보고, Watchtower를 이용하여 자동으로 배포까지 해보았습니다. 다만 이 방식도 몇가지 문제점이 존재했습니다.
항상 문제를 해결할 수 있는 방법을 찾고, 이 방식은 어떤 장단점이 있는지? 또 다른 좋은 방법은 없는지.
우선은 수동 배포부터 시작해서, 하나씩 배워가며 단순 배포에서 복잡한 CI / CD 까지. 직접 해보는게 가장 중요한거 같습니다! 😊