diff --git a/.github/workflows/cicdDeploy.yml b/.github/workflows/cicdDeploy.yml deleted file mode 100644 index 182ff34..0000000 --- a/.github/workflows/cicdDeploy.yml +++ /dev/null @@ -1,94 +0,0 @@ -name: Deploy to EC2 - -on: - push: - branches: - - 2-chore-cicd - workflow_dispatch: - inputs: - name: - description: 'admin' - required: true - default: 'user' - message: - description: 'message' - required: false - default: '수동 워크플로우 트리거' - -permissions: - contents: read - -jobs: - build: - runs-on: ubuntu-latest - steps: - # 기본 체크아웃 - - name: Checkout - uses: actions/checkout@v3 - - - name: Make application-secret.yml without env - run: | - touch ./src/main/resources/application.yml - echo "${{ secrets.APPLICATION }}" > ./src/main/resources/application.yml - touch ./src/main/resources/application-prod.yml - echo "${{ secrets.APPLICATION_PROD }}" > ./src/main/resources/application-prod.yml - - # JDK version 설정 - - name: Set up JDK 17 - uses: actions/setup-java@v3 - with: - java-version: '17' - distribution: 'temurin' - - - name: Grant execute permission for gradlew - run: chmod +x ./gradlew - - ## gradle build - - name: Build with Gradle - run: ./gradlew bootJar - - - name: Login to DockerHub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Docker app build & push - uses: docker/build-push-action@v5 - with: - context: . - file: ./Dockerfile - platforms: linux/amd64 - push: true - tags: ${{ secrets.DOCKER_USERNAME }}/backend - - - name: Docker nginx build & push - uses: docker/build-push-action@v5 - with: - context: . - file: ./config/nginx/Dockerfile - platforms: linux/amd64 - push: true - tags: ${{ secrets.DOCKER_USERNAME }}/nginx - - # ssh 접근 후 docker 이미지 pull 및 컨테이너 재시작 - - name: executing remote ssh commands using password - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.EC2_HOST }} - username: ubuntu # ec2-user 에서 변경 - key: ${{ secrets.EC2_KEY }} - script: | - cd /home/ubuntu/ceos - - sudo touch .env - echo "${{ secrets.ENV }}" | sudo tee .env > /dev/null - - sudo curl -o docker-compose.yml https://raw.githubusercontent.com/ewha-exhibition/Backend/2-chore-cicd/docker-compose.yml - - sudo chmod 666 /var/run/docker.sock - sudo docker rm -f $(docker ps -qa) - sudo docker pull ${{ secrets.DOCKER_USERNAME }}/backend - sudo docker pull ${{ secrets.DOCKER_USERNAME }}/nginx - docker compose -f docker-compose.yml --env-file .env up -d - docker image prune -f diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index f203b05..0aee0bc 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -71,6 +71,29 @@ jobs: push: true tags: ${{ secrets.DOCKER_USERNAME }}/nginx + - name: set target IP + run: | + STATUS=$(curl -o /dev/null -w "%{http_code}" "http://${{ secrets.EC2_HOST }}/actuator/health") + echo $STATUS + if [ $STATUS = 200 ]; then + CURRENT_UPSTREAM=$(curl -s "http://${{ secrets.EC2_HOST }}/env") + else + CURRENT_UPSTREAM=green + fi + echo CURRENT_UPSTREAM=$CURRENT_UPSTREAM >> $GITHUB_ENV + if [ $CURRENT_UPSTREAM = blue ]; then + echo "CURRENT_PORT=8080" >> $GITHUB_ENV + echo "STOPPED_PORT=8081" >> $GITHUB_ENV + echo "TARGET_UPSTREAM=green" >> $GITHUB_ENV + elif [ $CURRENT_UPSTREAM = green ]; then + echo "CURRENT_PORT=8081" >> $GITHUB_ENV + echo "STOPPED_PORT=8080" >> $GITHUB_ENV + echo "TARGET_UPSTREAM=blue" >> $GITHUB_ENV + else + echo "error" + exit 1 + fi + # ssh 접근 후 docker 이미지 pull 및 컨테이너 재시작 - name: executing remote ssh commands using password uses: appleboy/ssh-action@master @@ -85,10 +108,50 @@ jobs: echo "${{ secrets.ENV }}" | sudo tee .env > /dev/null sudo curl -o docker-compose.yml https://raw.githubusercontent.com/ewha-exhibition/Backend/main/docker-compose.yml + sudo curl -o docker-compose-blue.yml https://raw.githubusercontent.com/ewha-exhibition/Backend/main/docker-compose-blue.yml + sudo curl -o docker-compose-green.yml https://raw.githubusercontent.com/ewha-exhibition/Backend/main/docker-compose-green.yml sudo chmod 666 /var/run/docker.sock - sudo docker rm -f $(docker ps -qa) + sudo docker pull ${{ secrets.DOCKER_USERNAME }}/backend - sudo docker pull ${{ secrets.DOCKER_USERNAME }}/nginx - docker compose -f docker-compose.yml --env-file .env up -d + docker compose -f docker-compose-${{env.TARGET_UPSTREAM}}.yml --env-file .env up -d docker image prune -f + + - name: Check deploy server URL + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.EC2_HOST }} + username: ubuntu + key: ${{ secrets.EC2_KEY }} + script: | + set -e + for i in {1..10}; do + echo "[$i] health check..." + if curl -f http://localhost:${{ env.STOPPED_PORT }}/actuator/health > /dev/null 2>&1; then + echo "health check success" + exit 0 + fi + echo "health check failed, retrying in 5s..." + sleep 5 + done + echo "health check failed after 10 attempts" + exit 1 + + - name: Change nginx upstream + uses: appleboy/ssh-action@master + with: + username: ubuntu + host: ${{ secrets.EC2_HOST }} + key: ${{ secrets.EC2_KEY }} + script: | + sudo docker exec -i nginx bash -c 'echo "set \$service_url ${{ env.TARGET_UPSTREAM }};" > /etc/nginx/conf.d/service-env.inc && nginx -s reload' + + - name: Stop current server + uses: appleboy/ssh-action@master + with: + username: ubuntu + host: ${{ secrets.EC2_HOST }} + key: ${{ secrets.EC2_KEY }} + script: | + sudo docker stop ${{env.CURRENT_UPSTREAM}} + sudo docker rm ${{env.CURRENT_UPSTREAM}} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 80f3d1f..679be8e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ FROM eclipse-temurin:17-jdk +WORKDIR /app # (중요) cgroup 리소스 감지 비활성화 ENV JAVA_TOOL_OPTIONS="-XX:-UseContainerSupport" @@ -8,7 +9,12 @@ ENV SPRING_AUTOCONFIGURE_EXCLUDE="org.springframework.boot.actuate.autoconfigure # (중요) ProcessorMetrics 바인더 비활성화 ENV MANAGEMENT_METRICS_BINDERS_PROCESSOR_ENABLED="false" +WORKDIR /app + EXPOSE 80 -ARG JAR_FILE=/build/libs/*.jar +ARG JAR_FILE=build/libs/*.jar +ARG PROFILES +ARG ENV COPY ${JAR_FILE} app.jar -ENTRYPOINT ["java","-jar","-Duser.timezone=Asia/Seoul","-Dspring.profiles.active=prod","/app.jar"] \ No newline at end of file + +ENTRYPOINT ["java","-jar","-Duser.timezone=Asia/Seoul","-Dspring.profiles.active=prod","/app/app.jar"] \ No newline at end of file diff --git a/config/nginx/default.conf b/config/nginx/default.conf index 22b378a..07aab9f 100644 --- a/config/nginx/default.conf +++ b/config/nginx/default.conf @@ -1,12 +1,38 @@ -server { - listen 80; - listen [::]:80; +upstream blue { + server blue:8080; +} + +upstream green { + server green:8080; +} - location / { - proxy_set_header Host $host; - proxy_pass http://backend:8080/; - proxy_read_timeout 90; +server { + listen 80; + listen [::]:80; + + include /etc/nginx/conf.d/service-env.inc; - ## try_files $uri $uri/ =404; + location = /env { + default_type text/plain; + return 200 "service_url"; } -} \ No newline at end of file + + location / { + proxy_pass http://$service_url; + + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + + root /usr/share/nginx/html; + index index.html index.htm; + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} + + + \ No newline at end of file diff --git a/docker-compose-blue.yml b/docker-compose-blue.yml new file mode 100644 index 0000000..3aac587 --- /dev/null +++ b/docker-compose-blue.yml @@ -0,0 +1,19 @@ +version: '3.8' + +services: + blue: + image: nokmaster/backend + container_name: blue + ports: + - "8080:8080" + env_file: + - .env + environment: + - PROFILES=blue + - ENV=blue + networks: + - nok-network + +networks: + nok-network: + external: true diff --git a/docker-compose-green.yml b/docker-compose-green.yml new file mode 100644 index 0000000..5bfab32 --- /dev/null +++ b/docker-compose-green.yml @@ -0,0 +1,19 @@ +version: '3.8' + +services: + green: + image: nokmaster/backend + container_name: green + ports: + - "8081:8080" + env_file: + - .env + environment: + - PROFILES=green + - ENV=green + networks: + - nok-network + +networks: + nok-network: + external: true \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 0f62ccb..c35a259 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,19 +1,16 @@ -version: "3" - +version: '3.8' services: - backend: - image: nokmaster/backend - container_name: backend - hostname: backend - env_file: - - .env - expose: - - "8080" - nginx: image: nokmaster/nginx - depends_on: - - backend + container_name: nginx restart: always ports: - - "80:80" \ No newline at end of file + - "80:80" + volumes: + - ./nginx/conf.d:/etc/nginx/conf.d + networks: + - nok-network + +networks: + nok-network: + name: nok-network diff --git a/src/main/java/com/example/tikitaka/global/config/SecurityConfig.java b/src/main/java/com/example/tikitaka/global/config/SecurityConfig.java index 435706d..0503392 100644 --- a/src/main/java/com/example/tikitaka/global/config/SecurityConfig.java +++ b/src/main/java/com/example/tikitaka/global/config/SecurityConfig.java @@ -54,7 +54,7 @@ public PasswordEncoder passwordEncoder() { }; private final String[] ActuatorPatterns = { - "/actuator/health" + "/actuator/health", "/env" }; private final String[] GetPermittedPatterns = { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 2145267..e5ea707 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -4,7 +4,12 @@ spring: max-file-size: 10MB max-request-size: 10MB profiles: - active: prod + active: blue + group: + local: local + blue: blue, prod + green: green, prod + security: oauth2: client: @@ -67,7 +72,26 @@ logging: org.hibernate.orm.jdbc.bind: trace com.zaxxer.hikari: DEBUG -app: - cookie: - secure: false - same-site: Lax \ No newline at end of file +--- +spring: + config: + activate: + on-profile: blue + +server: + port: 8080 + serverAddress: \${SERVER_PROD_URL} + +serverName: blue_server +--- +spring: + config: + activate: + on-profile: green + +server: + port: 8080 + serverAddress: \${SERVER_PROD_URL} + +serverName: green_server +---