▶︎ 개요
도커 스웜으로 간단한 서비스를 배포해보자.
▶︎ 사설 레지스트리 서버 구축
퍼블릭 레지스트리 서버로 도커 허브등을 사용하는 방법이 있지만
오늘 포스팅에서는 개발 서버에서 이미지 레지스트리 서버를 도커를 사용하여 self-hosted 할 것이다.
그렇게해서 개발중인 애플리케이션을 도커라이징하여 구축한 이미지 레지스트리 서버에 배포하고
도커 스웜 클러스터에서 해당 이미지를 pull
받아 배포하면 된다.
도커를 이용한 사설 레지스트리 서버 구축 방법에 대해서는 링크된 게시글을 참고하도록 하자.
▶︎ 사전 준비
docker swarm에 참여한 서버간 Port를 오픈해줘야 한다.
docker swarm은 ingress network로 각각의 트래픽을 조절하고 각 노드를 관리하는데, 이 때 필요한 Port들이 존재한다.
(참고: 도커스웜 사전준비)
- TCP
- 2377
- 클러스터 관리 통신용
- TCP/UDP
- 7946
- 노드 간 통신
- UDP
- 4789
- 오버레이 네트워크 트래픽용
▶︎ 서비스 배포
- 실습에서 구현할 서비스는 fastapi 백엔드 기반 간단한 유저명 출력 서비스이다.
해당 서비스는 아래와 같이 매우 간단한 코드를 가진다.
from fastapi import FastAPI
import socket
app : FastAPI = FastAPI()
@app.get('/hostname')
def get_hostname() -> dict[str,str]:
hostname = socket.gethostname()
return {'hostname': hostname}
‣ 이미지 파일 배포
작성된 서비스를 도커 이미지로 만들어보자.
FROM python:3.10-slim-buster
WORKDIR /usr/src/app
COPY ./requirements.txt .
RUN pip install --upgrade pip && pip install -r requirements.txt
COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
dockerfile
작성이 끝났다면 해당 이미지를 빌드하고 사설 레지스트리 서버 구축에서 구축해놨던 레지스트리 url로 배포를 해보도록 하자.
# 이미지 빌드
docker build --tag yshrim12/swarm-fastapi .
# 빌드된 이미지 태깅
docker tag yshrim12/swarm-fastapi <registry 서버 도메인>/yshrim12/swarm-fastapi
# 레지스트리 서버로 이미지 배포
docker push <registry 서버 도메인>/yshrim12/swarm-fastapi
‣ docker compose 작성
- 배포할 YAML을 정의해주기
services:
api:
image: yshrim12/swarm-fastapi
hostname: fastapi
ports:
- "8000:8000"
stop_grace_period: 30s
stop_signal: SIGTERM
healthcheck:
test: ["CMD", "curl", "-l", "http://localhost:8000/hostname"]
timeout: 5s
deploy:
mode: replicated
replicas: 3
resources:
limits:
memory: '1g'
cpus: '1'
update_config:
order: start-first
delay: 5s
failure_action: rollback
rollback_config:
order: stop-first
parallelism: 0
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
networks:
- "api-net"
networks:
api-net:
external: false
주요 설정은 아래와 같습니다.
속성 | 설명 |
---|---|
stop_grace_period |
graceful한 종료 시, 최대 timeout 시간 설정 |
stop_signal |
컨테이너 종료 전 signal 설정. SIGKILL은 바로 컨테이너를 종료하는 반면 SIGTERM 은 프로세스에게 종료를 맡기기 때문에 graceful한 종료가 가능. |
healthcheck |
test에 포함된 명령어가 정상적으로 수행되어야 healthy 상태가 될 수 있음. 해당 상태가 되어야 트래픽 요청 처리가 가능함. |
deploy.mode |
배포 상태 설정. global의 경우 각 노드마다 한 개의 replica를 만들어 냄. 반면에 replicated는 replica를 무작위로 배포 가능 |
deploy.replicas |
replica 개수 설정. 이 개수만큼 docker swarm이 replica 개수를 유지해준다. |
deploy.resources |
컨테이너 자원 관련 설정. limit으로 제한을 걸고 memory 1GB, cpu 1 core로 제한을 두었음. |
deploy.update_config |
롤링 업데이트 설정. 현재 순서는 새로운 컨테이너를 먼저 띄우고 배포 성공 후 5s 의 지연 후 새 컨테이너를 이어서 배포함. 또한 실패 시 이전 컨테이너로 rollback |
deploy.rollback_config |
배포 실패시 rollback 설정. 실패 시 손상된 컨테이너를 바로 종료하여 손상된 컨테이너에 트래픽이 몰리지 않도록 함. 또한 모든 실패 컨테이너를 병렬로 rollback 하여 최대한 배포 실패로 인한 문제가 없도록 함. |
deploy.restart_policy |
배포 실패 시, 재시도 횟수와 지연시간 설정 |
여기서 핵심은 health-check
와 deploy
속성이라고 할 수 있겠다.
health-check
가 성공해야지만 컨테이너에 트래픽 요청이 가능해지기 때문에
안정적으로 새로운 컨테이너 배포가 가능해지고, update 시 start_first
로 되어있기 때문에 health-check
가 성공해야만 기존 컨테이너의 트래픽이 끊기게 된다.
만약 배포에 실패한다면? 기존 컨테이너는 종료되지 않고 계속 운영될 것이다.
또한, 배포 실패 시 빠르게 손상된 컨테이너를 복구시켜주기 때문에 무중단 운영도 가능해진다.
‣ stack 명령으로 배포
그럼 이제 작성한 docker-compose.yaml
파일을 stack
명령어를 사용하여 배포해보도록 하자.
docker stack deploy -c <docker-compose.yaml> --with-registry-auth <stack_name>
--with-registry-auth
- 레지스트리 서버에서 이미지를 가져올 때 인증 정보를 사용하도록 설정하는 옵션
- 이 옵션 사용 시 도커 스웜 매니저가 워커 노드에게 레지스트리 인증 정보를 전파하여, 모든 노드가 해당 레지스트리에서 이미지를
pull
받아오도록 함.
‣ rolling update
이미지의 태그를 변경하여 다시 배포해준 뒤, service만 업데이트하면 롤링 업데이트가 된다.
docker service update --image <registry 서버 도메인>/yshrim12/swarm-fastapi