ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • docker-compose 무중단 배포 1편 (blue, green)
    💻 프로그래밍/K8s & Docker 2022. 5. 29. 01:54

    안녕하세요! 개발자 Jay입니다!

    오늘은 CI/CD를 위한 docker-compose 무중단 배포에 대해서 정리해봤습니다!

     

    다들 로컬에서 테스트를 하거나 서버에서 docker-compose up, down 등으로 새로 컨테이너를 띄우는 과정들을 해보셨을 겁니다! 만약 production 환경에서 이렇게 하게된다면 어떻게 될까요?

     

    정답은 컨테이너가 재시작 되는 시점 동안 사용자들이 오류를 겪게 되겠죠?? 혹은 배포하면서 문제가 생겨서 컨테이너가 뜨지 않는다면 동일하게 오류를 겪게 되겠죠? ㅎㅎ

     

    그렇기 때문에 production환경에서는 무중단 배포를 해야 합니다! 

     

     

    1. 무중단 배포 종류


    무중단 배포는 크게 두가지 종류로 나뉜다고 합니다. 

    - rolling update 배포
    새로 배포되어야 하는 버전을 하나씩 순차적으로 적용시키면서 배포하는 방식입니다. 한 번에 모두 배포되는 게 아니기 때문에 배포가 되는 과정에서 옛날 버전과 새로운 버전이 공존합니다. 그렇기 때문에 잘못하면 배포하는 과정 중에 호환성 문제가 생길 수 있습니다

    - Blue,Green 배포
    Blue 혹은 Green 버전 둘 중 하나로 배포되어 있는 상태에서 새로운 버전을 동시에 띄우고 로드밸런서를 통해서 스위칭하는 방식이며, 한 번에 두 개의 버전을 동시에 띄우기 때문에 시스템 자원이 두배로 든다는 단점이 있습니다.

     

    저는 이 두가지만 알 고 있었는데 Canary(카나리) 배포 라는것도 있네요. 단계적 배포라고 보시면 됩니다. 일부 사용자들에게만 새로운 버전을 배포하고 안전성을 테스트합니다.

     

    이번 포스팅은 Blue, Green 무중단 배포에 대해서 실습하려고 합니다!

     

     

    2.  Blue, Green 배포 과정


    Blue, Green 배포 과정을 아래에 이미지로 정리해봤습니다

     

    8080 포트로 연결된 컨테이너
    8081포트로 다른 다른 버전의 컨테이너 띄우기
    nginx.conf 수정후 reload (업스트립 8081 수정)
    8080 컨테이너 제거

     

    개념은 정말 간단합니다.

    새로 배포할 때마다 새로운 컨테이너들을 띄우고
    nginx 연결(upstream)을 새로 띄운 컨테이너 포트로 연결한 뒤
    이전 컨테이너는 내립니다.

     

    이제 docker-compose.yaml를 직접 작성해 보면서 무중단 배포를 구현해보겠습니다.

     

     

    3. blue, green docker-compose 작성


    docker-compose.green.yaml, docker-compose.blue.yaml를 아래와 같이 작성합니다.

    version: '3.1'
     
    services:
     
      api:
        image: ${DOCKER_REGISTRY}/${DOCKER_APP_NAME}:${IMAGE_TAG}
     
        container_name: ${DOCKER_APP_NAME}-green
     
        environment:
          - LANG=ko_KR.UTF-8
          - UWSGI_PORT=8000
     
        ports:
          - '8080:8000'
     
    cs

     

    version: '3.1'
     
    services:
     
      api:
        image: ${DOCKER_REGISTRY}/${DOCKER_APP_NAME}:${IMAGE_TAG}
     
        container_name: ${DOCKER_APP_NAME}-blue
     
        environment:
          - LANG=ko_KR.UTF-8
          - UWSGI_PORT=8000
     
        ports:
          - '8081:8000'
     
    cs

     

    docker-compose.yaml 모두 포트만 다를 뿐 띄워는 컨테이너 정보는 동일합니다. 다만 IMAGE_TAG라는 환경변수를 통해서 도커 이미지 버전을 다르게 사용할 것입니다.

    (이 부분은 젠킨스, 깃헙액션등으로 배포 파이프라인을 구성하여 배포 시 변경해줍니다.)

     

    이제 이 두 개의 docker-compose.yaml을 번갈아가며 띄울 수 있는 deploy.sh를 작성해보겠습니다.

     

    4. deploy.sh 작성


    #!/bin/bash
     
    # Blue 를 기준으로 현재 떠있는 컨테이너를 체크한다.
    EXIST_BLUE=$(docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yaml ps | grep Up)
     
    # 컨테이너 스위칭
    if [ -"$EXIST_BLUE" ]; then
        echo "blue up"
        docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yaml up -d
        BEFORE_COMPOSE_COLOR="green"
        AFTER_COMPOSE_COLOR="blue"
    else
        echo "green up"
        docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.green.yaml up -d
        BEFORE_COMPOSE_COLOR="blue"
        AFTER_COMPOSE_COLOR="green"
    fi
     
    sleep 10
     
    # 새로운 컨테이너가 제대로 떴는지 확인
    EXIST_AFTER=$(docker-compose -p ${DOCKER_APP_NAME}-${AFTER_COMPOSE_COLOR} -f docker-compose.${AFTER_COMPOSE_COLOR}.yaml ps | grep Up)
    if [ -"$EXIST_AFTER" ]; then
        # 이전 컨테이너 종료
        docker-compose -p ${DOCKER_APP_NAME}-${BEFORE_COMPOSE_COLOR} -f docker-compose.${BEFORE_COMPOSE_COLOR}.yaml down
        echo "$BEFORE_COMPOSE_COLOR down"
    fi
     
    cs

    일단 blue, green 스위칭을 할 수 있게 deploy.sh를 작성해봤습니다.

    실제로 동작이 잘 되는지 확인해보겠습니다.

     

    처음 deploy.sh 를 실행한 경우 이미지 pulling을 진행
    다시 deploy.sh를 실행후 blue에서 green으로 스위칭 된 걸 확인

    매우 잘 동작합니다 ㅋㅋㅋ

    여기서 끝이 아니죠! 컨테이너뿐만 아니라 각 컨테이너 포트로 연결해주는 nginx의 config를 수정해야 합니다!

    뭐 어려운 건 없고, 배포 시 nginx.conf 내부의 upstream 세팅만 바꿔줘서 변경하면 됩니다!

     

    user www-data;
    worker_processes auto;
    pid /run/nginx.pid;
     
    events {
        worker_connections 768;
    }
     
    http {
        upstream backend {
            server localhost:8081# green
        }
     
        access_log /var/log/nginx/access.log;
     
        server {
            listen 80;
     
            location / {
                include /etc/nginx/uwsgi_params;
                proxy_pass http://backend;
            }
     
        }
    }
    cs

    nginx.blue.conf, nginx.green.conf 두 가지 파일을 /etc/nginx/ 에 추가합니다. upstream내용에서 portblue, green 맞춰서 추가해주면 됩니다!

     

    이제 deploy.sh를 추가 수정해보면 아래와 같습니다.

    #!/bin/bash
     
    # Blue 를 기준으로 현재 떠있는 컨테이너를 체크한다.
    EXIST_BLUE=$(docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yaml ps | grep Up)
     
    # 컨테이너 스위칭
    if [ -"$EXIST_BLUE" ]; then
        echo "blue up"
        docker-compose -p ${DOCKER_APP_NAME}-blue -f docker-compose.blue.yaml up -d
        BEFORE_COMPOSE_COLOR="green"
        AFTER_COMPOSE_COLOR="blue"
    else
        echo "green up"
        docker-compose -p ${DOCKER_APP_NAME}-green -f docker-compose.green.yaml up -d
        BEFORE_COMPOSE_COLOR="blue"
        AFTER_COMPOSE_COLOR="green"
    fi
     
    sleep 10
     
    # 새로운 컨테이너가 제대로 떴는지 확인
    EXIST_AFTER=$(docker-compose -p ${DOCKER_APP_NAME}-${AFTER_COMPOSE_COLOR} -f docker-compose.${AFTER_COMPOSE_COLOR}.yaml ps | grep Up)
    if [ -"$EXIST_AFTER" ]; then
      # nginx.config를 컨테이너에 맞게 변경해주고 reload 한다
      cp /etc/nginx/nginx.${AFTER_COMPOSE_COLOR}.conf /etc/nginx/nginx.conf
      nginx -s reload
     
      # 이전 컨테이너 종료
      docker-compose -p ${DOCKER_APP_NAME}-${BEFORE_COMPOSE_COLOR} -f docker-compose.${BEFORE_COMPOSE_COLOR}.yaml down
      echo "$BEFORE_COMPOSE_COLOR down"
    fi
     
    cs

    새로운 컨테이너가 제대로 떴는지 확인 후, nginx.conf의 내용을 blue, green에 맞게 변경 후 재시작해주는 로직이 추가되었습니다.

    이제 배포하면 nginx.conf도 함께 잘 변경되어 외부에서도 스위칭된 컨테이너 포트로 연결이 되는 걸 확인할 수 있습니다.

     

     

    5. 정리


    최근 회사에서 신규 서비스를 처음부터 만드는 과정에서 CI/CD부터 모든 걸 처음 혼자 해보다 보니 무중단 배포까지 관심을 가지게 되었습니다. 이미 기존 서비스들도 동일하게 무중단 배포를 하고 있었는데 대충 이럴 거다라고만 알고 있었는데 직접 해보니까 재밌기도 하고 무중단 배포에 대해서 좀 더 알게 되었네요 ㅎㅎ

     

    다음에는 롤링 업데이트도 한번 스터디 후 정리해보겠습니다! 여러분들도 평소에 회사에서 이미 만들어져 있는 배포 방식, 서비스 등을 그냥 사용하지 마시고 한번 스터디해보시면서 혼자 만들어보시길 바라요! 확실히 처음부터 혼자 해보니까 더 자세히 알게 되는 것 같습니다!

     

    그럼 오늘도 즐거운 코딩 하시길 바래요~아디오스~

     

     

     

    댓글

운동하는 개발자 JAY-JI