[기록용] 깃허브 액션을 이용한 무중단 배포

728x90

블루서버, 그린서버 

upstream blue_backend { server 127.0.0.1:8081; }
upstream green_backend { server 127.0.0.1:8082; }
upstream active_backend { server 127.0.0.1:8081; } # blue가 live

server {
    listen 80;
    location / {
        proxy_pass http://active_backend;
    }
}

로 바꾸기

name: Docker Build and Deploy via SSH

on:
  push:
    branches:
      - main # 배포할 브랜치 지정

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
            java-version: '17'
            distribution: 'temurin'

      - name: Build with Gradle
        run: ./gradlew clean build -x test

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GHCR_TOKEN }}

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.sha }}

  deploy-via-ssh:
    needs: build-and-push # 이미지 빌드 후 실행
    runs-on: ubuntu-latest
    steps:
      - name: Install SSH key
        uses: shimataro/ssh-key-action@v2
        with:
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          known_hosts: 'just-a-placeholder-so-we-can-disable-strict-host-key-checking'

      - name: Determine current active container name
        run: |
          PORT=$(ssh -o StrictHostKeyChecking=no -p ${{ secrets.REMOTE_SSH_PORT }} \
          ${{ secrets.REMOTE_SSH_USERNAME }}@${{ secrets.REMOTE_SSH_HOST }} \
          "grep -Po 'proxy_pass http://\\K[a-zA-Z0-9\\-]+(?=:8888;)' /home/dev/nginx/conf.d/default.conf")
          echo "CURRENT_CONTAINER=$NAME" >> $GITHUB_ENV

      - name: Set next prot and contatiner
        run: |
          if [ "${{ env.CURRENT_CONTAINER }}" = "demo-app" ]; then
            echo "NEW_CONTAINER=demo-app-green" >> $GITHUB_ENV
            echo "OLD_CONTAINER=demo-app" >> $GITHUB_ENV
            echo "NEW_PORT=8889" >> $GITHUB_ENV
            echo "OLD_PORT=8888" >> $GITHUB_ENV
          else
            echo "NEW_CONTAINER=demo-app" >> $GITHUB_ENV
            echo "OLD_CONTAINER=demo-app-green" >> $GITHUB_ENV
            echo "NEW_PORT=8888" >> $GITHUB_ENV
            echo "OLD_PORT=8889" >> $GITHUB_ENV
          fi

      - name: SSH into server and deploy new container
        run: |
          ssh -o StrictHostKeyChecking=no -p ${{ secrets.REMOTE_SSH_PORT }} ${{ secrets.REMOTE_SSH_USERNAME }}@${{ secrets.REMOTE_SSH_HOST }} << EOF
            echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
          
            docker pull ghcr.io/${{ github.repository }}:${{ github.sha }}
          
            docker run -d \
              --name ${{ env.NEW_CONTAINER }} \
              --network app-network \
              -p ${{ env.NEW_PORT }}:8888 \
              ghcr.io/${{ github.repository }}:${{ github.sha }}
          EOF

      - name: new container check
        run: |
          ssh -o StrictHostKeyChecking=no -p ${{ secrets.REMOTE_SSH_PORT }} ${{ secrets.REMOTE_SSH_USERNAME }}@${{ secrets.REMOTE_SSH_HOST }} << EOF
            for i in {1..30}; do
              sleep 5
              STATUS=\$(curl -s -o /dev/null -w '%{http_code}' http://localhost:${{ env.NEW_PORT }}/health || echo "000")
              if [ "\$STATUS" = "200" ]; then
                echo "Health check passed"
                exit 0
              fi
            done
            echo "Health check failed"
            docker rm -f ${{ env.NEW_CONTAINER }}
            exit 1
          EOF

      - name: Update Nginx configuration
        run: |
          ssh -o StrictHostKeyChecking=no -p ${{ secrets.REMOTE_SSH_PORT }} ${{ secrets.REMOTE_SSH_USERNAME }}@${{ secrets.REMOTE_SSH_HOST }} << EOF
            sed -i "s|proxy_pass http://[a-zA-Z0-9\-]\+:8888;|proxy_pass http://${{ env.NEW_CONTAINER }}:8888;|" /home/dev/nginx/conf.d/default.conf
            docker exec nginx-server nginx -s reload
          EOF

      - name: Remove old container
        run: |
          ssh -o StrictHostKeyChecking=no -p ${{ secrets.REMOTE_SSH_PORT }} \
           ${{ secrets.REMOTE_SSH_USERNAME }}@${{ secrets.REMOTE_SSH_HOST }} \
           "docker rm -f ${{ env.OLD_CONTAINER }} || true"
반응형