CD #26
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CD | |
| on: | |
| workflow_run: | |
| workflows: ["CI"] | |
| types: | |
| - completed | |
| jobs: | |
| deploy: | |
| if: ${{ github.event.workflow_run.conclusion == 'success' }} | |
| runs-on: ubuntu-latest | |
| name: Deploy to EC2 (blue/green) | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v3 | |
| # CD 배포 | |
| - name: Deploy to remote EC2 Server | |
| uses: appleboy/ssh-action@master | |
| with: | |
| host: ${{ secrets.AWS_EC2_IP }} | |
| username: ${{ secrets.AWS_EC2_USERNAME }} | |
| key: ${{ secrets.AWS_EC2_KEY }} | |
| port: ${{ secrets.AWS_EC2_PORT }} | |
| script: | | |
| cd /home/ubuntu | |
| APP_NAME=${{ secrets.DOCKER_REPO }} | |
| IMAGE=${{ secrets.DOCKER_USERNAME }}/${{secrets.DOCKER_REPO}} | |
| COLOR_FILE=/home/ubuntu/deploy_color | |
| # 현재 색 / 다음 색/ 포트 결정 | |
| if [ -f "$COLOR_FILE" ] && [ "$(cat $COLOR_FILE)" = "blue" ]; then | |
| CURRENT_COLOR=blue | |
| NEW_COLOR=green | |
| CURRENT_PORT=8080 | |
| NEW_PORT=8081 | |
| else | |
| CURRENT_COLOR=green | |
| NEW_COLOR=blue | |
| CURRENT_PORT=8081 | |
| NEW_PORT=8080 | |
| fi | |
| echo "Current color: $CURRENT_COLOR" | |
| echo "New color: $NEW_COLOR" | |
| docker pull $IMAGE | |
| NEW_CONTAINER_NAME=${APP_NAME}-${NEW_COLOR} | |
| OLD_CONTAINER_NAME=${APP_NAME}-${CURRENT_COLOR} | |
| # 새 컨테이너 자리에 기존 게 있으면 정리 | |
| if [ "$(docker ps -aq -f name=$NEW_CONTAINER_NAME)" ]; then | |
| docker stop $NEW_CONTAINER_NAME || true | |
| docker rm $NEW_CONTAINER_NAME || true | |
| fi | |
| # 새 컨테이너 먼저 실행 | |
| docker run -d \ | |
| --name $NEW_CONTAINER_NAME \ | |
| --env SPRING_PROFILES_ACTIVE=prod \ | |
| --env JAVA_TOOL_OPTIONS="-Duser.timezone=Asia/Seoul" \ | |
| --env 'MYSQL_URL=${{ secrets.MYSQL_URL }}' \ | |
| --env MYSQL_USERNAME=${{ secrets.MYSQL_USERNAME }} \ | |
| --env MYSQL_PASSWORD=${{ secrets.MYSQL_PASSWORD }} \ | |
| --env JWT_SECRET=${{ secrets.JWT_SECRET }} \ | |
| --env KAKAO_CLIENT_ID=${{ secrets.KAKAO_CLIENT_ID }} \ | |
| --env KAKAO_CLIENT_SECRET=${{ secrets.KAKAO_CLIENT_SECRET }} \ | |
| --env KAKAO_REDIRECT_URI=${{ secrets.KAKAO_REDIRECT_URI }} \ | |
| --env KAKAO_CLIENT_REDIRECT_URI=${{ secrets.KAKAO_CLIENT_REDIRECT_URI }} \ | |
| --env GEMINI_API_KEY=${{ secrets.GEMINI_API_KEY }} \ | |
| --env GEMINI_MODEL=${{ secrets.GEMINI_MODEL }} \ | |
| -p ${NEW_PORT}:8080 \ | |
| $IMAGE | |
| HEALTH_PATH="/api/test/jwt" | |
| # 새 컨테이너 상태 확인 | |
| echo "Health check for new container..." | |
| for i in {1..20}; do | |
| sleep 5 | |
| STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" "http://localhost:${NEW_PORT}${HEALTH_PATH}" || echo "000") | |
| echo "Health check status: $STATUS_CODE" | |
| if [ "$STATUS_CODE" = "200" ]; then | |
| echo "New version is healthy!" | |
| break | |
| fi | |
| if [ "$i" -eq 20 ]; then | |
| echo "New version did not become healthy in time. Aborting." | |
| docker logs $NEW_CONTAINER_NAME || true | |
| exit 1 | |
| fi | |
| done | |
| # 캐디 포트 전환 | |
| echo "Switching traffic to new container..." | |
| sudo sed -i "s/reverse_proxy localhost:[0-9]\\+/reverse_proxy localhost:${NEW_PORT}/" /etc/caddy/Caddyfile | |
| sudo systemctl reload caddy | |
| if [ "$(docker ps -q -f name=$OLD_CONTAINER_NAME)" ]; then | |
| echo "Stopping old container..." | |
| docker stop $OLD_CONTAINER_NAME || true | |
| docker rm $OLD_CONTAINER_NAME || true | |
| fi | |
| docker image prune -f | |
| echo $NEW_COLOR > $COLOR_FILE |