From 46cd1b5d959c7b744f45ade8b234bbff6a3f7263 Mon Sep 17 00:00:00 2001 From: Arachne <66822642+Arachneee@users.noreply.github.com> Date: Tue, 15 Oct 2024 14:26:58 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20blue=20green=20=EB=AC=B4=EC=A4=91?= =?UTF-8?q?=EB=8B=A8=20=EB=B0=B0=ED=8F=AC=20=EC=8A=A4=ED=81=AC=EB=A6=BD?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/backend-prod.yml | 165 ++++++++++++++++------------- 1 file changed, 90 insertions(+), 75 deletions(-) diff --git a/.github/workflows/backend-prod.yml b/.github/workflows/backend-prod.yml index 466d6f0e..26b7e6c2 100644 --- a/.github/workflows/backend-prod.yml +++ b/.github/workflows/backend-prod.yml @@ -20,100 +20,115 @@ jobs: contents: read steps: - - name: CheckOut - uses: actions/checkout@v4 - with: - token: ${{secrets.CONFIG_SUBMODULE_TOKEN}} - submodules: true - - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - java-version: '17' - distribution: 'temurin' - - - name: Setup Gradle - uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0 - - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - - name: Test with Gradle Wrapper - run: ./gradlew clean build - - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Set up Docker BuildX - uses: docker/setup-buildx-action@v3 - - - name: Build and push - run: | - docker buildx build --platform linux/arm64 -t \ - ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} --push . + # (Your build steps remain the same) deploy: needs: build strategy: matrix: runner: [ prod-1, prod-2, prod-3 ] - max-parallel: 1 runs-on: [ self-hosted, '${{ matrix.runner }}' ] steps: - - name: Delete existing has to be deleted container gracefully + - name: Docker Image pull + run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} + + - name: Check running container and determine the next port + id: check-port run: | - echo "Stopping existing container if running..." - if sudo docker ps -a --filter "name=haengdong-backend-delete" --format "{{.Names}}" | grep -w haengdong-backend-delete; then - sudo docker rm -f haengdong-backend-delete + echo "Checking if any container is running on ports 8080 or 8081..." + CURRENT_PORT=$(sudo docker ps --format "{{.Names}} {{.Ports}}" | grep "haengdong-backend-" | grep -o '8080\|8081') + + if [ "$CURRENT_PORT" == "8080" ]; then + NEXT_PORT=8081 else - echo "No running container named haengdong-backend-delete found." + NEXT_PORT=8080 fi - - name: Docker Image pull - run: sudo docker pull ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} + if [ -z "$CURRENT_PORT" ]; then + echo "No running container found. Using port 8080." + NEXT_PORT=8080 + fi - - name: Stop existing container gracefully + echo "Next container will run on port $NEXT_PORT." + echo "::set-output name=next_port::$NEXT_PORT" + echo "::set-output name=current_port::$CURRENT_PORT" + + - name: Run new container on the alternate port run: | - echo "Stopping existing container if running..." - if sudo docker ps -a --filter "name=haengdong-backend" --format "{{.Names}}" | grep -w haengdong-backend; then - sudo docker stop haengdong-backend - sudo docker rename haengdong-backend haengdong-backend-delete - else - echo "No running container named haengdong-backend found." - fi + echo "Running new container on port ${{ steps.check-port.outputs.next_port }}..." + sudo docker run -d -p ${{ steps.check-port.outputs.next_port }}:8080 \ + -e SPRING_PROFILES_ACTIVE=prod -v log-volume:/app/logs --name haengdong-backend-${{ steps.check-port.outputs.next_port }} \ + ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} + + - name: Wait for Application Booting 30 seconds + run: sleep 30 - - name: Docker run and Health Check + - name: Health check the new container + id: health-check run: | - echo "Running new container..." - sudo docker run -d -p 80:8080 -e SPRING_PROFILES_ACTIVE=prod -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_PROD }} - - echo "Performing health check..." - # 헬스 체크를 위해 일정 시간 대기 (애플리케이션이 시작될 시간을 확보) - for i in 1 2 3; do - echo "Waiting for application to start... (${i}0초 경과)" - sleep 10 - done - - # 헬스 체크 수행 및 상태 추출 (jq 없이 sed 사용) - HEALTH_STATUS=$(curl -s http://localhost/actuator/health | sed -n 's/.*"status":"\([^"]*\)".*/\1/p') + echo "Performing health check for the new container on port ${{ steps.check-port.outputs.next_port }}..." + HEALTH_STATUS=$(curl -s http://localhost:${{ steps.check-port.outputs.next_port }}/actuator/health | sed -n 's/.*"status":"\([^"]*\)".*/\1/p') echo "Health check status: $HEALTH_STATUS" - if [ "$HEALTH_STATUS" == "UP" ]; then - echo "Health check passed." - echo "Removing old container..." - sudo docker rm haengdong-backend-delete - else - echo "Health check failed. Status: $HEALTH_STATUS" - echo "Rolling back to previous container..." - sudo docker rm -f haengdong-backend - sudo docker rename haengdong-backend-delete haengdong-backend - sudo docker start haengdong-backend + if [ "$HEALTH_STATUS" != "UP" ]; then + echo "Health check failed. Rolling back..." + sudo docker rm -f haengdong-backend-${{ steps.check-port.outputs.next_port }} exit 1 fi + + echo "Health check passed." + + - name: Update or create Nginx container to point to new container port + run: | + NGINX_CONTAINER_NAME="nginx-proxy" + + echo "Checking if Nginx container is running..." + if sudo docker ps --filter "name=$NGINX_CONTAINER_NAME" --format "{{.Names}}" | grep -w $NGINX_CONTAINER_NAME; then + echo "Nginx container is running. Updating configuration..." + + # Copy Nginx config from the running container to the host + sudo docker cp $NGINX_CONTAINER_NAME:/etc/nginx/nginx.conf ./nginx.conf + + # Update the proxy_pass setting in the config file + sudo sed -i "s/proxy_pass http:\/\/127.0.0.1:.*;/proxy_pass http:\/\/127.0.0.1:${{ steps.check-port.outputs.next_port }};/" ./nginx.conf + + # Copy the updated config back into the container + sudo docker cp ./nginx.conf $NGINX_CONTAINER_NAME:/etc/nginx/nginx.conf + + # Reload Nginx inside the container + sudo docker exec $NGINX_CONTAINER_NAME nginx -s reload + + echo "Nginx configuration updated and reloaded." + + else + echo "Nginx container not found. Creating a new Nginx container..." + + # Create a basic Nginx config file with the updated proxy_pass + echo " + server { + listen 80; + location / { + proxy_pass http://127.0.0.1:${{ steps.check-port.outputs.next_port }}; + } + } + " > ./nginx.conf + + # Run a new Nginx container with the updated config + sudo docker run -d --name $NGINX_CONTAINER_NAME -p 80:80 \ + -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro nginx + + echo "New Nginx container created and running." + fi - - name: Waiting for ALB health check - run: sleep 90 + - name: Stop and remove the old container + run: | + CURRENT_PORT=${{ steps.check-port.outputs.current_port }} + if [ -n "$CURRENT_PORT" ]; then + echo "Stopping and removing the container running on port $CURRENT_PORT..." + sudo docker ps --filter "publish=$CURRENT_PORT" --format "{{.ID}}" | xargs sudo docker stop + sleep 5 + sudo docker ps -a --filter "publish=$CURRENT_PORT" --format "{{.ID}}" | xargs sudo docker rm + else + echo "No container to stop and remove." + fi