1+ name : Deploy to OCI
2+
3+ on :
4+ push :
5+ branches :
6+ - develop
7+ # GitHub Actions 탭에서 수동으로 실행 가능
8+ workflow_dispatch :
9+
10+ # 워크플로우 전체에서 사용할 환경 변수 설정
11+ env :
12+ # 사용할 컨테이너 레지스트리(GitHub Container Registry)
13+ REGISTRY : ghcr.io
14+ IMAGE_NAME : ${{ github.repository_owner }}/global-nomad
15+
16+ jobs :
17+ # Job 1: Docker 이미지 빌드를 빌드하고 GHCR에 푸시
18+ build :
19+ name : Build and Push Docker Image
20+ runs-on : ubuntu-latest
21+ # 해당 Job이 사용할 권한 설정
22+ permissions :
23+ contents : read
24+ # GHCR에 이미지를 쓰기(푸시) 위한 권한
25+ packages : write
26+
27+ # Job의 결과를 다른 Job에서 사용할 수 있도록 출력 설정
28+ outputs :
29+ # 정확한 이미지 태그 전달 (SHA 기반) - 배포할 정확한 이미지 주소, 버전 확인을 위한 커밋 해시
30+ image-url : ${{ steps.image.outputs.image-url }}
31+ git-sha : ${{ steps.vars.outputs.sha-short }}
32+
33+ steps :
34+ # 코드 체크아웃
35+ - name : Checkout code
36+ uses : actions/checkout@v4
37+
38+ # Docker Buildx 설정
39+ - name : Set up Docker Buildx
40+ uses : docker/setup-buildx-action@v3
41+
42+ # GHCR 로그인
43+ # - secrets.GITHUB_TOKEN: 워크플로우 실행 시 GitHub이 자동으로 생성해주는 임시 토큰
44+ - name : Log in to GitHub Container Registry
45+ uses : docker/login-action@v3
46+ with :
47+ registry : ${{ env.REGISTRY }}
48+ username : ${{ github.actor }}
49+ password : ${{ secrets.GITHUB_TOKEN }}
50+
51+ # 빌드에 사용할 변수 생성 (짧은 커밋 해시, 빌드 날짜)
52+ - name : Generate build vars
53+ id : vars
54+ run : |
55+ echo "sha-short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
56+ echo "build-date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
57+
58+ # 도커 이미지 빌드 및 푸시 (불변 태그 사용)
59+ - name : Build and push Docker image
60+ id : build
61+ uses : docker/build-push-action@v5
62+ with :
63+ # 현재 디렉토리를 빌드 컨텍스트로 사용
64+ context : .
65+ # 빌드 후 레지스트리에 푸시
66+ push : true
67+ # 이미지에 여러 태그를 부여
68+ tags : |
69+ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:develop
70+ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:develop-${{ steps.vars.outputs.sha-short }}
71+ # 이미지에 메타 데이터 라벨 추가
72+ labels : |
73+ org.opencontainers.image.revision=${{ github.sha }}
74+ org.opencontainers.image.created=${{ steps.vars.outputs.build-date }}
75+ # GitHub Actions 캐시를 사용하여 빌드 속도 향상
76+ cache-from : type=gha
77+ cache-to : type=gha,mode=max
78+ # 빌드할 플랫폼 지정
79+ platforms : linux/amd64
80+
81+ # Job으로 전달할 정확한 이미지 URL 출력으로 설정
82+ - name : Set image output
83+ id : image
84+ run : |
85+ echo "image-url=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:develop-${{ steps.vars.outputs.sha-short }}" >> $GITHUB_OUTPUT
86+
87+ # Job 2: OCI 서버에 배포
88+ deploy :
89+ name : Deploy to OCI Server
90+ runs-on : ubuntu-latest
91+ # 빌드 Job이 성공해야만 실행
92+ needs : build
93+
94+ steps :
95+ - name : Setup SSH
96+ run : |
97+ mkdir -p ~/.ssh
98+ echo "${{ secrets.OCI_SSH_KEY }}" > ~/.ssh/id_rsa
99+ chmod 600 ~/.ssh/id_rsa
100+ ssh-keyscan -t rsa ${{ secrets.OCI_HOST }} >> ~/.ssh/known_hosts
101+
102+ # 서버에 배포 스크립트 실행
103+ - name : Deploy to server
104+ env :
105+ IMAGE_URL : ${{ needs.build.outputs.image-url }}
106+ GIT_SHA : ${{ needs.build.outputs.git-sha }}
107+ run : |
108+ ssh -i ~/.ssh/id_rsa ${{ secrets.OCI_USERNAME }}@${{ secrets.OCI_HOST }} << 'ENDSSH'
109+ set -e
110+
111+ echo "📦 Starting deployment..."
112+ echo "🏷️ Image: ${IMAGE_URL}"
113+ echo "🔖 Version: ${GIT_SHA}"
114+
115+ # 프로젝트 디렉토리로 이동
116+ cd ~/projects/GlobalNomad
117+
118+ # 최신 코드 가져오기
119+ echo "🔄 Pulling latest code..."
120+ git pull origin develop
121+
122+ # GHCR 로그인 (PAT 사용)
123+ echo "🔐 Logging in to GHCR..."
124+ echo "${{ secrets.GHCR_PAT }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
125+
126+ # 현재 실행 중인 이미지 태그 저장 (롤백용)
127+ echo "💾 Saving current version..."
128+ CURRENT_IMAGE=$(docker-compose ps -q nextjs | xargs docker inspect -f '{{.Config.Image}}' 2>/dev/null || echo "none")
129+ echo "Current: $CURRENT_IMAGE" > ~/deployments/previous-version.txt
130+
131+ # 기존 컨테이너 중지
132+ echo "🛑 Stopping existing containers..."
133+ docker-compose down || true
134+
135+ # PM2 정리(환경 테스트를 하기 위해 사용했던 이전 배포 방식 정리 )
136+ pm2 stop global-nomad || true
137+ pm2 delete global-nomad || true
138+
139+ # 최신 이미지 pull (정확한 버전)
140+ echo "📥 Pulling image: ${IMAGE_URL}"
141+ docker pull ${IMAGE_URL}
142+
143+ # 환경 변수로 이미지 지정하여 실행
144+ echo "🚀 Starting containers..."
145+ export NEXTJS_IMAGE="${IMAGE_URL}"
146+ docker-compose up -d
147+
148+ # 헬스 체크
149+ echo "❤️ Health check..."
150+ for i in {1..30}; do
151+ if curl -f http://localhost:3000 > /dev/null 2>&1; then
152+ echo "✅ Service is healthy!"
153+ break
154+ fi
155+ echo "⏳ Waiting for service... ($i/30)"
156+ sleep 2
157+ done
158+
159+ # 최종 확인
160+ if ! curl -f http://localhost:3000 > /dev/null 2>&1; then
161+ echo "❌ Service health check failed after 60 seconds!"
162+ docker-compose logs --tail 50 nextjs
163+ exit 1
164+ fi
165+
166+ # 배포 정보 기록
167+ echo "📝 Recording deployment..."
168+ mkdir -p ~/deployments
169+ echo "${IMAGE_URL}" > ~/deployments/current-version.txt
170+ echo "$(date -u +'%Y-%m-%d %H:%M:%S UTC') - ${GIT_SHA}" >> ~/deployments/history.log
171+
172+ # 오래된 이미지 정리 (최근 3개만 유지)
173+ echo "🧹 Cleaning up old images..."
174+ docker images | grep global-nomad | tail -n +4 | awk '{print $3}' | xargs -r docker rmi || true
175+
176+ echo "✅ Deployment completed successfully!"
177+ echo "📊 Deployed version: ${GIT_SHA}"
178+ ENDSSH
179+
180+ # 배포 결과 알림 (Slack, Discord 등 추가 가능)
181+ - name : Notify deployment status
182+ if : always()
183+ run : |
184+ if [ ${{ job.status }} == 'success' ]; then
185+ echo "✅ 배포 성공!"
186+ echo "🏷️ Image: ${{ needs.build.outputs.image-url }}"
187+ echo "🔖 Version: ${{ needs.build.outputs.git-sha }}"
188+ else
189+ echo "❌ 배포 실패!"
190+ fi
0 commit comments