kimyu0218
  • [CD] 블루/그린 무중단 배포 구현하기 1편 (NGINX/Docker Compose)
    2024년 01월 07일 18시 20분 00초에 업로드 된 글입니다.
    작성자: @kimyu0218
    야 너두 무중단 배포 할 수 있어 🫵

    이 글은 도커, 엔진엑스, 깃헙 액션을 한 번도 써본 적 없고, 무중단 배포라는 용어도 처음 들어본 사람의 무모한 무중단 배포 도전기다. 제발 나처럼 고생하는 사람이 없길 바라며 삽질을 거름으로 완성한 블루/그린 무중단 배포 도전기를 풀어보겠다.


     

    무중단 배포란?

    신규 버전의 어플리케이션을 새롭게 배포하는 과정을 가정해보자. 로컬에서는 신규 어플리케이션을 빌드하고, 서버에서는 현재 실행중인 버전을 종료한다. 기존 버전의 종료되면 빌드한 결과물을 서버에서 실행하고, 그 결과 신규 어플리케이션이 배포된다.
    하지만 해당 방법은 구버전이 종료되고 신규 버전이 실행되기 전까지 사용자가 서비스를 이용할 수 없다는 치명적인 단점이 있다. 이를 보완하고자 서비스의 중단없이 업데이트를 수행하는 무중단 배포가 등장했다.
     
    무중단 배포 전략에는 롤링, 블루/그린, 카나리 배포 전략이 있다. (배포 전략에 대한 비교는 구글에 검색하면 아주 잘 나오니 생략하겠다ㅎㅎ) 나는 인스턴스를 하나만 사용하고 있기 때문에 블루/그린 배포 전략을 선택했다.


    블루/그린 배포를 위한 컴포즈 파일 작성하기

    이번 포스팅에서는 도커 컴포즈와 엔진엑스를 이용하여 블루/그린 배포를 구현하는 방법을 알아볼 것이다. 블루/그린 배포 전략은 기존 버전을 종료하지 않고 신규 버전을 실행한다. 신규 버전이 실행되고 나면 기존 버전으로 가는 트래픽을 신규 버전을 향하도록 전환한다. 트래픽을 전환하기 위해 엔진엑스를 사용할 것이다.

    내 프로젝트를 기준으로 흐름을 정리해봤다. 먼저, 서버에서 실행중인 버전이 블루인지 그린인지 확인한다. 현재 실행중인 버전이 블루인 경우, 그린 버전에서 신규 어플리케이션을 실행한다. 새로운 버전의 어플리케이션이 실행되면 엔진엑스를 이용하여 트래픽이 새로운 버전을 향하도록 만든다. 마지막으로 필요없어진 기존 버전을 종료시키면 된다. (말은 정말 쉽다!!)
     

    NGINX란?

    엔진엑스를 사용하기 전에 해당 기술이 뭔지 간단히 짚고 넘어가자. 엔진엑스는 웹 서버 소프트웨어로 다양한 기능을 제공한다.

    • 웹 서버 : 정적인 콘텐츠를 캐시하여 동일한 요청에 대해 캐시된 콘텐츠를 제공하여 서버의 부하를 줄이고 응답시간을 개선한다.
    • 로드 밸런싱 : 클라이언트의 요청을 여러 대의 서버에 분산시켜 서버의 부하를 줄인다.
    • 경로 기반 라우팅 : 클라이언트의 요청 URL에 따라 서로 다른 엔드포인트로 라우팅한다. 이를 통해 하나의 웹 서버에서 여러 어플리케이션을 호스팅할 수 있다.

    나는 경로 기반 라우팅을 사용하여 클라이언트의 요청이 기존 버전에서 신규 버전을 향하도록 수정할 것이다.
     

    Docker Compose와 Docker Hub를 활용한 배포

    이제 도커 컴포즈와 도커 허브를 활용하여 블루/그린 버전의 이미지를 만들어보자. 여러 개의 컨테이너를 실행해야 하기 때문에 도커 컴포즈를 활용하여 간편하게 멀티 컨테이너 환경을 구축할 것이다.
     
    그리고 도커 허브를 이용하여 이식성과 일관성을 보장할 것이다. 도커 이미지를 빌드하여 허브에 푸시하고, 원격 서버에서는 도커 허브에서 이미지를 가져와 실행만 하기 때문에 동일한 이미지를 다양한 환경에서 사용할 수 있다.
     

    필요한 Docker Compose 파일

    🚨 build와 image 옵션을 같이 사용하면 이미지를 다시 빌드한다.

    빌드 환경과 실행 환경이 다르기 때문에 빌드 버전과 실행 버전 컴포즈를 별도로 작성해줘야 한다. 빌드 컴포즈에서는 build 옵션을 이용하여 이미지를 빌드하고, 실행 컴포즈에서는 image 옵션을 이용하여 도커 허브에서 이미지를 pull 받아오도록 구성해야 한다.
     
    그리고 서로 다른 버전(블루/그린)을 동시에 실행하기 위해서는 서로 다른 포트를 사용하는 도커 컴포즈 파일이 필요하다. 따라서 블루 버전의 컴포즈, 그린 버전의 컴포즈 파일이 필요하다.

    만들어야 하는 도커 컴포즈 파일 목록
    • 블루 버전을 빌드하는 컴포즈 파일
    • 블루 버전을 실행하는 컴포즈 파일
    • 그린 버전을 빌드하는 컴포즈 파일
    • 그린 버전을 실행하는 컴포즈 파일

     

    이미지를 빌드하는 컴포즈 파일 작성하기

    🔗 도커 컴포즈 포스팅

    우선 이미지를 빌드하는 컴포즈 파일을 작성해보자. 도커 허브에 푸시할 이미지는 was와 signal이다.

    version: "3.3"
    
    services:
      was-blue:
        container_name: "was-blue"
        build:
          context: .
          dockerfile: Dockerfile.was
        env_file: .env
        environment:
          - PORT=3000
        expose:
          - "3000"
        volumes:
          - /var/log/was:/app/was/logs
          - /var/log/ormlogs.log:/app/was/ormlogs.log
        networks:
          - backend
        image: "${DOCKER_USERNAME}/magicconch:was-blue-${GITHUB_SHA}"
    
      signal-blue:
        container_name: "signal-blue"
        build:
          context: .
          dockerfile: Dockerfile.signal
        environment:
          - PORT=3001
        expose:
          - "3001"
        networks:
          - backend
        image: "${DOCKER_USERNAME}/magicconch:signal-blue-${GITHUB_SHA}"
    
    networks:
      backend:
        external: true
        name: backend

    build 옵션을 활용하여 도커 이미지를 빌드하도록 설정했다. 그리고 image 옵션을 활용하여 이미지 이름을 지정했는데 이는 도커 허브에 푸시할 때 사용되는 이름이다. (deploy 컴포즈의 image 옵션과 다른 용도로 사용된다!!)
     
    블루 버전이 3000번과 3001번 포트를 사용하고 있으므로 그린 버전은 3002번, 3003번을 사용하도록 지정해주면 된다. 나머지는 블루 버전과 동일하다.

    🔗 컴포즈 파일 : compose.blue-build.yml  compose.green-build.yml

     

    컨테이너를 실행하는 컴포즈 파일 작성하기

    이제 원격 서버에서 사용할 도커 컴포즈 파일을 작성해보자. 원격 서버는 도커 컴포즈 파일에 명시된 이미지를 허브로부터 가져와서 실행하게 된다.

    version: "3.3"
    
    services:
      was-blue:
        image: "${DOCKER_USERNAME}/magicconch:was-blue-${GITHUB_SHA}"
        container_name: "was-blue"
        env_file: .env
        environment:
          - PORT=3000
        expose:
          - "3000"
        volumes:
          - /var/log/was:/app/was/logs
          - /var/log/ormlogs.log:/app/was/ormlogs.log
        networks:
          - backend
    
      signal-blue:
        image: "${DOCKER_USERNAME}/magicconch:signal-blue-${GITHUB_SHA}"
        container_name: "signal-blue"
        environment:
          - PORT=3001
        expose:
          - "3001"
        networks:
          - backend
    
      ...
    
    networks:
      backend:
        external: true
        name: backend

    이미지를 빌드하는 컴포즈 파일과 거의 유사하지만 build 옵션이 사라졌다. build 옵션이 없기 때문에 도커 허브로부터 image 옵션에서 지정한 이미지를 가져와서 컨테이너를 실행한다.

    🔗 컴포즈 파일 : compose.blue-deploy.yml  compose.green-deploy.yml

    이번 포스팅에서는 블루/그린 배포에 필요한 도커 컴포즈 파일만 작성했다. 다음 포스팅에서 깃헙 액션을 이용하여 배포하는 과정을 다루겠다.

    댓글