도커 compose와 nginx를 통한 Rolling 방식의 무중단 배포

백종현·2023년 5월 3일
0
post-custom-banner

😱 개요

보통 Nginx와 Container를 활용하는 경우 Rolling 방식보다는 Blue-Green 방식을 더 많이 사용한다.

하지만, 무중단 배포의 3가지 방식 중 Rolling 방식을 사용하여 무중단 배포를 시도하였다.

Nginx와 Container를 활용하여 Blue-Green을 하는 경우는 결국 배포를 하는 순간에 Container가 2개 띄워지는 상황이 발생하기 때문에, 필요한 컴퓨팅 파워는 결국 Rolling 방식과 같다고 생각하였고, 그렇다면 굳이 Blue-Green이 아닌, Rolling 방식이 더 나을 것이라고 생각하였다.

또한 Rolling 방식을 사용한 이유는 Rolling 방식이 추후에 A/B 테스트에 유리할 것이라고 판단하였다.

처리 방식

1. Nginx Container와 Server Container를 두 개가 실행 중이다.

  • 여기서 Nginx Container를 만들 때, nginx의 config 파일은 docker volumn을 사용하여 host와 공유할 수 있도록 하였다. 왜냐하면 이후에 이 파일을 변경을 하고 nginx를 reload 할 일이 많이 생길 것이였다.
  • 또한 Server Container의 Image는 Github Action을 통해 Build를 해 둔 상태이다.

2. Docker Volumn을 통하여 Nginx가 한 곳만 가리키도록 설정파일을 변경하고, Nginx를 Reload하였다.

  • 여기서 3초간 sleep 상태를 만들어 Nginx를 Reload 하는 것을 기다리도록 하였다.
    • 사실 이 부분을 3초 간 기다리는 방식이 아닌, container의 로그를 뜯어 Reload가 된 지점을 확인하여 처리할 수는 있었다. 하지만 굉장히 귀찮은 작업이기도 했고, 보통 Reload는 0.5초 내로 굉장히 빠른 시점에 처리되었다.
    • 그렇지만, 이 부분이 변경이 필요한 지점이다.

3~4. 이제 Nginx가 가리키지 않는 지점을 새로운 버젼으로 업데이트 시킨다.

  • docker compose pull 명령어와 docker compose up --force-recreate 명령어를 사용하여 target container만 업데이트 했다.
    • 여기서 docker compose up --force-recreate을 하게 되면, 새로운 버젼의 container가 뜨게 되는데, 여기서 문제가 있었다. 우리 서버는 스프링 서버를 사용하는데, 스프링을 jvm에 실행 가능하게 올리는 데 약 10-20초의 추정 불가능한 시간이 필요했는데, 이를 확인해야 했다.
    • 따라서, curl 명령어와 while문을 통해 스프링 서버가 실제로 잘 띄워졌는지 확인해보고, 잘 띄워졌다면 다음 단계를 실행할 수 있도록 하였다.

5. 다른 container도 위와 같은 방식으로 업데이트를 하고, 마지막에 nginx가 모든 컨테이너를 가리키도록 변경한다.

docker compose yml 파일

version: '3'
services:
  nginx:
    image: nginx:latest
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    container_name: backend-nginx
  web1 :
    image: username/xxx:latest
    ports:
      - "8080:8080"
    container_name: api-server1
  web2 :
    image: username/xxx:latest
    ports:
      - "8081:8080"
    container_name: api-server2

docker compose nginx 파일

echo "nginx가 api-server1만 가리키도록 변경"
sed -i 's/server api-server2:8080/# server api-server2:8080/g' nginx/default.conf
docker exec backend-nginx nginx -s reload > /dev/null 2>&1
sleep 3

echo "api-server2을 새로운 버젼으로 배포하고, 정상적으로 돌아가는지 확인"
docker compose pull web2 -q
docker compose up --force-recreate -d web2
curl --silent --head --fail http://localhost:8081/swagger-ui/index.html >> /dev/null
while [ $? -ne 0 ];
do 
    sleep 1
    curl --silent --head --fail http://localhost:8081/swagger-ui/index.html >> /dev/null
done
echo -e "\033[32m"api-server2 배포 성공"\033[0m" 

echo "nginx가 api-server2만 가리키도록 변경"
sed -i 's/# server api-server2:8080/server api-server2:8080/g' nginx/default.conf
sed -i 's/server api-server1:8080/# server api-server1:8080/g' nginx/default.conf
docker exec backend-nginx nginx -s reload > /dev/null 2>&1
sleep 3

echo "api-server1을 새로운 버젼으로 배포하고, 정상적으로 돌아가는지 확인"
docker compose pull web1 -q
docker compose up --force-recreate -d web1
curl --silent --head --fail http://localhost:8080/swagger-ui/index.html >> /dev/null
while [ $? -ne 0 ];
do 
    sleep 1
    curl --silent --head --fail http://localhost:8080/swagger-ui/index.html >> /dev/null
done
echo -e "\033[32m"api-server1 배포 성공"\033[0m" 

echo "nginx가 모든 컨테이너를 가리키도록 변경"
sed -i 's/# server api-server1:8080/server api-server1:8080/g' nginx/default.conf
docker exec backend-nginx nginx -s reload > /dev/null 2>&1
echo -e "\033[32m"배포 성공!"\033[0m" 
profile
노력하는 사람
post-custom-banner

0개의 댓글