프로그래밍/개발 일지

[CD/CI] blue-green 배포 공부해보기 1

jtw7977 2026. 1. 13. 02:06

1. 글의 목적

이번 글에서는 직접 웹서버를 해보고 싶어서 배포에 대해서 공부하다가 blue-green 배포가 있다고 해서 직접 실습을 해보고 정리하려고 한다.

 

2. blue-green 배포가 무엇일까?

Blue-Green 배포는 운영 중인 서버와 동일한 사양의 새로운 서버 세트를 하나 더 구축하여, 배포 시점에 트래픽을 한꺼번에 전환하는 방식입니다. 구 버전과 신 버전을 각각 BlueGreen이라는 이름의 환경으로 정의하고 번갈아 가며 서비스를 제공합니다.

✅ 핵심 동작 원리

  1. Blue(기존): 현재 실제 사용자가 접속하여 서비스가 운영되고 있는 환경 (v1)
  2. Green(신규): 새롭게 배포할 코드가 설치된 환경 (v2). 사용자 트래픽이 아직 유입되지 않은 상태.
  3. 검증: Green 환경에서 내부 테스트를 진행하여 신규 버전에 문제가 없는지 최종 확인합니다.
  4. 전환(Switch): 로드 밸런서(Load Balancer)나 라우터 설정을 변경하여 사용자 트래픽을 Blue에서 Green으로 일시에 옮깁니다.
  5. 대기 및 롤백: 배포가 완료된 후 Blue는 즉시 삭제하지 않고 대기시킵니다. 만약 Green에서 치명적인 버그가 발견되면 즉시 트래픽을 다시 Blue로 돌려 원상복구합니다.

📊 Blue-Green 배포의 장단점

구분 장점 단점
가용성 Zero Downtime: 트래픽 전환이 순식간에 일어나 서비스 중단이 거의 없습니다. 비용 부담: 동일한 사양의 서버 인프라가 2배로 필요하여 비용이 많이 듭니다.
안정성 빠른 롤백: 문제 발생 시 라우팅만 다시 바꾸면 즉시 이전 버전으로 복구됩니다. DB 동기화: 신구 버전이 동일한 DB를 바라볼 때 데이터 스키마 변경 시 관리가 어렵습니다.
테스트 환경 격리: 운영 환경과 동일한 조건에서 최종 테스트 후 배포할 수 있습니다. 복잡한 설정: 로드 밸런서와 네트워크 전환 설정에 대한 자동화가 필요합니다.

 

(설명 by gemini)

 

3. 사용한 기술스택 & 디렉토리 경로

서버: lightsnail Ubuntu 24.04.3 LTS

Docker 29.1.4

Docker Compose version v5.0.1

CI: github Actions

간단한 웹서버: nodejs 22, express ^5.2.1

 

디렉터리 구조

blue-green-test/
├──.github/workflows/deploy.yml
├── Dockerfile
├── app.js
└── package.json

 

4. 서버 초기 설정

sudo apt update
curl -fsSL https://get.docker.com | sudo sh
sudo apt install docker-compose-plugin -y
sudo apt install nginx -y

sudo usermod -aG docker ubuntu
exit

SSH 재접속 필수

groups

sudo mkdir -p /srv/blue-green
sudo chown ubuntu:ubuntu /srv/blue-green

groups에 docker가 있어야 함

 

 

sudo nano /etc/nginx/sites-available/bluegreen

nano 를 쓰던 vim을 쓰던 마음대로!

 

server {
    listen 80;

    location / {
        proxy_pass http://localhost:3001; # blue
    }
}

이렇게 적고

sudo ln -s /etc/nginx/sites-available/bluegreen /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl restart nginx

실행

 

4-1. github Actions에서 접속할 SSH 키 만들기

ssh-keygen -t ed25519 -f lightsail_ci
cat lightsail_ci.pub >> ~/.ssh/authorized_keys

를 통해 ssh키를 등록해둔다. 주의할점은 SSH 키를 만들때 passphrase는 입력하지 않으면 된다.

cat lightsail_ci

 

를 입력하여 -----BEGIN OPENSSH PRIVATE KEY----- 로 시작하여 -----END OPENSSH PRIVATE KEY-----로 끝나는 값을 전체 복사하여 안전하게 보관해두자. 반드시 -----BEGIN OPENSSH PRIVATE KEY----- 같은 구문도 포함해야 한다!

 

5. docker hub / github Acions 기초 설정

https://hub.docker.com/

 

Docker Hub Container Image Library | App Containerization

Software supply chain Secure Your Supply Chain with Docker Hardened Images Use Docker's enterprise-grade base images: secure, stable, and backed by SLAs for Ubuntu, Debian, Java, and more. Regularly scanned and maintained with CVE remediation and long-term

hub.docker.com

 

docker hub에 접속해서 계정 만들기.

https://hub.docker.com/repositories 에서 

 

레포지토리를 만들되 이름을 blue-green-test으로 해주기!

생성후 액세스 토큰을 발급받자.

 

오른쪽 위 자신 프로필을 클릭후 Account settings에 들어간후 PAT섹션 클릭후 오른쪽위의 access token만들기를 클릭후 Access permissions을 Read & Write로 만든후 만들어진 토큰을 잘 보관하자.

 

 

그후 github 레포로 이동해서 Setting-Secrets and variables-Actions에 들어가서 다음과 같은 것을 설정해주자.

DOCKER_PASSWORD - 조금 전에 발급받은 PAT

DOCKER_USERNAME - dokcer에 가입할때 입력한 username

SERVER_IP - 서버의 ip주소

SERVER_USER - 서버에서의 user (기본적으로 ubuntu 일 것이다)

SSH_KEY - 4-1에서 만든 ssh키

 

6. 코드 적기

// app.js
const express = require("express");
const app = express();

const COLOR = process.env.COLOR || "unknown";

app.get("/", (req, res) => {
  res.send(`Hello from ${COLOR}`);
});

app.listen(3000, () => {
  console.log(`Server running on ${COLOR}`);
});

app.js에 다음과 같이 적고 (package.json은 알잘딱깔센하게)

 

FROM node:22

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .

EXPOSE 3000
CMD ["node", "app.js"]

Dockerfile에는 다음과 같이 적고

 

name: Deploy

on:
  push:
    branches: [ main ]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Docker build
        run: docker build -t ${{ secrets.DOCKER_USERNAME }}/blue-green-test:latest .

      - name: Docker login
        run: echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin

      - name: Docker push
        run: docker push ${{ secrets.DOCKER_USERNAME }}/blue-green-test:latest

      - name: SSH Deploy
        uses: appleboy/ssh-action@v0.1.6
        with:
          host: ${{ secrets.SERVER_IP }}
          username: ubuntu
          key: ${{ secrets.SSH_KEY }}
          script: |
            cd /srv/blue-green
            docker pull ${{ secrets.DOCKER_USERNAME }}/blue-green-test:latest
            docker compose up -d

.github/workflows/deploy.yml에 이렇게 적자.

 

 

아직 코드는 push하지 말자.

 

7. docker compose 설정

서버에서 /srv/blue-green경로로 이동한 후

nano docker-compose.yml

를 입력하여 파일을 열어 수정모드로 전환후

services:
  blue:
    image: your-id/blue-green-test:latest # 본인의 Docker ID로 수정하세요
    container_name: blue
    environment:
      - COLOR=blue
    ports:
      - "3001:3000"

  green:
    image: your-id/blue-green-test:latest # 본인의 Docker ID로 수정하세요
    container_name: green
    environment:
      - COLOR=green
    ports:
      - "3002:3000"

을 적는다. your-id부분에 자신의 docker id를 적자.

 

저장을 하는것도 잊지 말자.

 

8. 코드 push 및 실행

아까 작성했던 코드를 push하면 github Actions가 실행될것이다. github의 Actions탭에서 확인해보자. 체크표시가 나왔다면 브라우저를 통해 주소창에 자신의 서버 ip주소를 입력하면 Hello from blue가 나올것 이다. 그럼 잘 된 것이다.

이후

curl -f http://localhost:3002

를 통해 헬스체크를 하여 켜져있는지 확인 후

sudo nano /etc/nginx/sites-available/bluegreen

를 사용하여 proxy_pass http://localhost:3001; 부분을 proxy_pass http://localhost:3002; 로 바꿔보자. 그후

sudo systemctl reload nginx

를 하여 nginx를 다시 켜주고 들어가면 Hello from green이 나올것이다. 그럼 잘 된 것이다.

 

 

9. 마무리 

간단하게 blue-green배포가 어떻게 이루어지는 지 실습을 해보았다. 처음해서 많이 서툴고 에러를 보면 당황했지만 한 단계씩 진행할때마다 재밌었다. 다음 편에는 blue-green 버전 나누기, 롤백, 실행 자동화 등을 실습해보며 더 고급 실습을 해보려고 한다.