1. docker-compose green/blue 구성
services:
nextjs-blue: # >>> 이부분 변경 <<<
build:
context: .
dockerfile: Dockerfile
container_name: nextjs-blue
restart: always
env_file:
- .env
networks:
- app-network
nextjs-green: # >>> 이부분 변경 <<<
build:
context: .
dockerfile: Dockerfile
container_name: nextjs-green
restart: always
env_file:
- .env
networks:
- app-network
nginx:
image: nginx:alpine
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./certbot/conf:/etc/letsencrypt:ro
- ./certbot/www:/var/www/certbot
depends_on:
- nextjs-blue # >>> 이부분 변경 <<<
- nextjs-green # >>> 이부분 변경 <<<
networks:
- app-network
command: '/bin/sh -c ''while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g "daemon off;"'''
networks:
app-network:
driver: bridge
docker-compose에서 기존 nextjs로 구성된 서비스를 nextjs-blue, nextjs-green으로 변경 후 nginx에 의존성 추가 해줬다.
2. nginx 설정 변경
# >>> 이부분 추가 <<<
upstream nextjs_upstream {
server nextjs-blue:3000;
}
server {
listen 80;
server_name ~~~~~~~~~~~~~~~~~~
client_max_body_size 100M;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
allow all;
}
location / {
proxy_pass http://nextjs_upstream # >>> 이부분 추가 <<<
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
server {
listen 443 ssl;
server_name ~~~~~~~~~~~~
client_max_body_size 100M;
location / {
proxy_pass http://nextjs_upstream; # >>> 이부분 추가 <<<
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Nginx가 트래픽을 어디로 보낼 지 하는 설정입니다. (기본은 블루로 해줬다.)
3. sh 작성
#!/bin/bash
# 현재 활성화된 서비스 확인
CURRENT_SERVICE=$(grep -v "^#" nginx.conf | grep -o "nextjs-[a-z]*" | head -1)
if [ "$CURRENT_SERVICE" == "nextjs-blue" ]; then
# Blue가 활성화되어 있으면 Green으로 배포
TARGET_SERVICE="nextjs-green"
IDLE_SERVICE="nextjs-blue"
else
# Green이 활성화되어 있으면 Blue로 배포
TARGET_SERVICE="nextjs-blue"
IDLE_SERVICE="nextjs-green"
fi
echo "현재 서비스: $CURRENT_SERVICE"
echo "배포 대상 서비스: $TARGET_SERVICE"
# 대상 서비스 컨테이너와 이미지 제거
docker compose rm -f $TARGET_SERVICE
docker rmi $(docker images | grep $TARGET_SERVICE | awk '{print $3}') 2>/dev/null || true
# Docker 시스템 정리 (캐시된 이미지와 볼륨 정리)
echo "Docker 시스템 정리 중..."
docker system prune -f
# nginx가 실행 중인지 확인하고 실행되지 않았다면 시작
NGINX_RUNNING=$(docker compose ps | grep nginx | grep Up || echo "")
if [ -z "$NGINX_RUNNING" ]; then
echo "nginx 컨테이너 시작 중..."
docker compose up -d nginx
sleep 5
fi
# 대상 서비스 빌드 및 시작
echo "$TARGET_SERVICE 빌드 및 시작 중..."
docker compose up -d --build --force-recreate $TARGET_SERVICE
# 새 서비스가 시작되었는지 확인
echo "새 서비스가 시작되기를 기다리는 중..."
sleep 15 # 시간 증가
CONTAINER_RUNNING=$(docker compose ps | grep $TARGET_SERVICE | grep Up || echo "")
if [ -z "$CONTAINER_RUNNING" ]; then
echo "오류: $TARGET_SERVICE 컨테이너가 시작되지 않았습니다."
echo "로그 확인 중..."
docker compose logs $TARGET_SERVICE
# 오류 발생 시 롤백 로직 추가
echo "이전 서비스로 롤백합니다..."
exit 1
fi
# nginx.conf 업데이트
echo "nginx.conf 업데이트 중..."
sed -i "s/$IDLE_SERVICE/$TARGET_SERVICE/g" nginx.conf
sed -i "s/# server $TARGET_SERVICE/server $TARGET_SERVICE/g" nginx.conf
sed -i "s/server $IDLE_SERVICE/# server $IDLE_SERVICE/g" nginx.conf
# 변경된 설정 확인
echo "변경된 nginx 설정:"
cat nginx.conf
# nginx 컨테이너 재시작 (리로드 대신)
echo "nginx 컨테이너 재시작 중..."
docker compose restart nginx
# 재시작 후 상태 확인
sleep 3
NGINX_RUNNING=$(docker compose ps | grep nginx | grep Up || echo "")
if [ -z "$NGINX_RUNNING" ]; then
echo "오류: nginx 재시작 실패"
exit 1
else
echo "nginx가 성공적으로 재시작되었습니다."
fi
echo "트래픽이 $TARGET_SERVICE로 전환되었습니다."
# 이전 서비스는 일정 시간 후 중지
sleep 30
echo "이전 서비스를 중지합니다..."
docker compose stop $IDLE_SERVICE
주석 참조 바람...
대충 요약하면 Blue일땐 Green으로 배포 Green일 때는 Blue로 배포 후
2에서 설정한 Nginx 트래픽 변경 후 재시작
여기까지 성공하면 Green/Blue 방식의 무중단 배포까진 성공했다.
4. 프로젝트에 .github/workflows/.yml 파일 작성
# deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: SSH and deploy
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /home/여러분의 프로젝트 경로~
git stash
git pull
chmod +x ./deploy.sh
./deploy.sh
Deploy라는 워크플로우를 작성해줬다.
여기서 중요한 건
secrets.HOST
secrets.USERNAME
secrets.SSH_PRIVATE_KEY
세 개와
script: 아래 코드다
main으로 푸시하면 위에 시크릿 정보로 ssh 접속 후 스크립트를 자동 실행한다!
5. github에 Repository secrets 추가
제 서버 기준 SSH_PRIVATE_KEY는 이렇게 생성했습니다.
ssh-keygen -t rsa -b 4096 -C "github-actions"
sudo nano /etc/ssh/sshd_config
SSH 설정 파일에서
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
주석 해제
sudo systemctl restart sshd
SSH 서비스 재시작
cat ~/.ssh/id_rsa
시크릿 키 확인
이 부분을 전부 복사해서 붙여 주면 됩니다.
-----BEGIN OPENSSH PRIVATE KEY-----
SSH PRIVATE KEY~~~~~~~~~~~~~
-----END OPENSSH PRIVATE KEY-----
자 이제 위에 설정한 브런치로 push를 해보면!!!!!!!
'DevOps' 카테고리의 다른 글
[Nginx] 무단 도메인 바인딩, farmming.com , 피싱 사이트? (0) | 2025.05.09 |
---|---|
[Nginx] 413 Request Entity Too Large 오류 (0) | 2025.04.29 |
Next.js + Docker + Nginx SSL 인증서 발급하기 (Let's encrypt , certbot, nip.io) (0) | 2025.04.24 |
Linux 우분투 (ubuntu 22.04) MySQL 8.0 설치 및 대소문자 구분 설정 방법 (0) | 2025.04.16 |