diff --git a/.github/workflows/be-cd-prod.yml b/.github/workflows/be-cd-prod.yml index 033d0e9f7..688130b48 100644 --- a/.github/workflows/be-cd-prod.yml +++ b/.github/workflows/be-cd-prod.yml @@ -16,114 +16,67 @@ jobs: secrets: secret_yml: ${{ secrets.PROD_SECRET_YML }} - deploy-a: + deploy: needs: [ build ] uses: ./.github/workflows/blue-green.yml with: - self_hosted_runner: prod-a + self_hosted_runner: prod artifact_name: ${{ needs.build.outputs.artifact_name }} jar_name: ${{ needs.build.outputs.jar_name }} profile: prod app_path: ~/app - deploy-b: - needs: [ build ] - uses: ./.github/workflows/blue-green.yml - with: - self_hosted_runner: prod-b - artifact_name: ${{ needs.build.outputs.artifact_name }} - jar_name: ${{ needs.build.outputs.jar_name }} - profile: prod - app_path: ~/app - - rollback-a: - name: "[Failure] Rollback Deploy A" - needs: [ deploy-a, deploy-b ] - if: failure() && (needs.deploy-a.result == 'failure' || needs.deploy-b.result == 'failure') - uses: ./.github/workflows/shutdown.yml - with: - self_hosted_runner: prod-a - port: ${{ needs.deploy-a.outputs.green_port }} - - rollback-b: - name: "[Failure] Rollback Deploy B" - needs: [ deploy-a, deploy-b ] - if: failure() && (needs.deploy-a.result == 'failure' || needs.deploy-b.result == 'failure') + rollback: + name: "[Failure] Rollback Deploy" + needs: deploy + if: failure() && needs.deploy.result == 'failure' uses: ./.github/workflows/shutdown.yml with: - self_hosted_runner: prod-b - port: ${{ needs.deploy-b.outputs.green_port }} + self_hosted_runner: prod + port: ${{ needs.deploy.outputs.green_port }} deploy-failure-notification: name: "[Failure] Deploy Failure Notification" - needs: [ deploy-a, deploy-b ] - if: failure() && (needs.deploy-a.result == 'failure' || needs.deploy-b.result == 'failure') + needs: deploy + if: failure() && needs.deploy.result == 'failure' runs-on: ubuntu-latest steps: - name: Send notification to Discord # todo run: echo "테스트입니다" - configure-nginx-a: - needs: [ deploy-a, deploy-b ] + configure-nginx: + needs: deploy uses: ./.github/workflows/nginx-port-forwarding.yml with: - self_hosted_runner: prod-a + self_hosted_runner: prod app_path: ~/app - old_port: ${{ needs.deploy-a.outputs.blue_port }} - new_port: ${{ needs.deploy-a.outputs.green_port }} + old_port: ${{ needs.deploy.outputs.blue_port }} + new_port: ${{ needs.deploy.outputs.green_port }} - configure-nginx-b: - needs: [ deploy-a, deploy-b ] + rollback-nginx: + name: "[Failure] Rollback Nginx" + needs: configure-nginx + if: failure() && (needs.configure-nginx.result == 'failure') uses: ./.github/workflows/nginx-port-forwarding.yml with: - self_hosted_runner: prod-b + self_hosted_runner: prod app_path: ~/app - old_port: ${{ needs.deploy-b.outputs.blue_port }} - new_port: ${{ needs.deploy-b.outputs.green_port }} - - rollback-nginx-a: - name: "[Failure] Rollback Nginx A" - needs: [ configure-nginx-a, configure-nginx-b ] - if: failure() && (needs.configure-nginx-a.result == 'failure' || needs.configure-nginx-b.result == 'failure') - uses: ./.github/workflows/nginx-port-forwarding.yml - with: - self_hosted_runner: prod-a - app_path: ~/app - old_port: ${{ needs.configure-nginx-a.outputs.new_port }} - new_port: ${{ needs.configure-nginx-a.outputs.old_port }} - old_shutdown: true - - rollback-nginx-b: - name: "[Failure] Rollback Nginx B" - needs: [ configure-nginx-a, configure-nginx-b ] - if: failure() && (needs.configure-nginx-a.result == 'failure' || needs.configure-nginx-b.result == 'failure') - uses: ./.github/workflows/nginx-port-forwarding.yml - with: - self_hosted_runner: prod-b - app_path: ~/app - old_port: ${{ needs.configure-nginx-b.outputs.new_port }} - new_port: ${{ needs.configure-nginx-b.outputs.old_port }} + old_port: ${{ needs.configure-nginx.outputs.new_port }} + new_port: ${{ needs.configure-nginx.outputs.old_port }} old_shutdown: true configure-nginx-faliure-notification: name: "[Failure] Nginx Failure Notification" - needs: [ configure-nginx-a, configure-nginx-b ] - if: failure() && (needs.configure-nginx-a.result == 'failure' || needs.configure-nginx-b.result == 'failure') + needs: configure-nginx + if: failure() && needs.configure-nginx.result == 'failure' runs-on: ubuntu-latest steps: - name: Send notification to Discord # todo run: echo "테스트입니다" - blue-shutdown-a: - needs: [ configure-nginx-a, configure-nginx-b ] - uses: ./.github/workflows/shutdown.yml - with: - self_hosted_runner: prod-a - port: ${{ needs.configure-nginx-a.outputs.old_port }} - - blue-shutdown-b: - needs: [ configure-nginx-a, configure-nginx-b ] + blue-shutdown: + needs: configure-nginx uses: ./.github/workflows/shutdown.yml with: - self_hosted_runner: prod-b - port: ${{ needs.configure-nginx-b.outputs.old_port }} + self_hosted_runner: prod + port: ${{ needs.configure-nginx.outputs.old_port }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2d5ebb699..47b418bfd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -59,7 +59,7 @@ jobs: run: | mkdir -p ${{ inputs.artifact_name }} && \ mv build/libs/*.jar ${{ inputs.artifact_name }}/${{ inputs.jar_name }} && \ - mv scripts/* ${{ inputs.artifact_name }}/ + mv scripts/${{ inputs.profile }}/* ${{ inputs.artifact_name }}/ - name: Upload artifact file uses: actions/upload-artifact@v4 diff --git a/backend/scripts/change_nginx_port_forwarding.sh b/backend/scripts/prod/change_nginx_port_forwarding.sh old mode 100755 new mode 100644 similarity index 100% rename from backend/scripts/change_nginx_port_forwarding.sh rename to backend/scripts/prod/change_nginx_port_forwarding.sh diff --git a/backend/scripts/get_blue_green_port.sh b/backend/scripts/prod/get_blue_green_port.sh old mode 100755 new mode 100644 similarity index 100% rename from backend/scripts/get_blue_green_port.sh rename to backend/scripts/prod/get_blue_green_port.sh diff --git a/backend/scripts/green_health_check.sh b/backend/scripts/prod/green_health_check.sh old mode 100755 new mode 100644 similarity index 89% rename from backend/scripts/green_health_check.sh rename to backend/scripts/prod/green_health_check.sh index d040ebc07..80b57b1fa --- a/backend/scripts/green_health_check.sh +++ b/backend/scripts/prod/green_health_check.sh @@ -3,15 +3,15 @@ GREEN_PORT=$1 health_check_process() { - # 헬스 체크를 최대 5번 시도 (3초 간격) + # 헬스 체크를 최대 5번 시도 (5초 간격) for i in $(seq 1 5); do check_health if [ $? -eq 0 ]; then echo "Health check passed on attempt $i." return 0 fi - echo "Waiting 3 seconds before next check..." - sleep 3 + echo "Waiting 5 seconds before next check..." + sleep 5 done # 5번 시도 후에도 실패하면 종료 diff --git a/backend/src/main/java/ddangkong/config/sql/DataSourceConfig.java b/backend/src/main/java/ddangkong/config/sql/DataSourceConfig.java deleted file mode 100644 index 9c4a29d78..000000000 --- a/backend/src/main/java/ddangkong/config/sql/DataSourceConfig.java +++ /dev/null @@ -1,54 +0,0 @@ -package ddangkong.config.sql; - -import ddangkong.config.sql.type.DataSourceType; -import java.util.HashMap; -import java.util.Map; -import javax.sql.DataSource; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.jdbc.DataSourceBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import org.springframework.context.annotation.Profile; -import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy; - -@Profile("prod") -@Configuration -public class DataSourceConfig { - - @Bean - @ConfigurationProperties(prefix = "spring.datasource.source") - public DataSource sourceDataSource() { - return DataSourceBuilder.create() - .build(); - } - - @Bean - @ConfigurationProperties(prefix = "spring.datasource.replica") - public DataSource replicaDataSource() { - return DataSourceBuilder.create() - .build(); - } - - @Bean - public DataSource routingDataSource( - DataSource sourceDataSource, - DataSource replicaDataSource - ) { - Map dataSources = new HashMap<>(); - dataSources.put(DataSourceType.SOURCE, sourceDataSource); - dataSources.put(DataSourceType.REPLICA, replicaDataSource); - - RoutingDataSource routingDataSource = new RoutingDataSource(); - routingDataSource.setDefaultTargetDataSource(dataSources.get(DataSourceType.SOURCE)); - routingDataSource.setTargetDataSources(dataSources); - - return routingDataSource; - } - - @Primary - @Bean - public DataSource dataSource() { - return new LazyConnectionDataSourceProxy(routingDataSource(sourceDataSource(), replicaDataSource())); - } -} diff --git a/backend/src/main/java/ddangkong/config/sql/RoutingDataSource.java b/backend/src/main/java/ddangkong/config/sql/RoutingDataSource.java deleted file mode 100644 index 8a73602c0..000000000 --- a/backend/src/main/java/ddangkong/config/sql/RoutingDataSource.java +++ /dev/null @@ -1,18 +0,0 @@ -package ddangkong.config.sql; - -import ddangkong.config.sql.type.DataSourceType; -import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; -import org.springframework.transaction.support.TransactionSynchronizationManager; - -public class RoutingDataSource extends AbstractRoutingDataSource { - - @Override - protected Object determineCurrentLookupKey() { - boolean isReadOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly(); - if (isReadOnly) { - return DataSourceType.REPLICA; - } else { - return DataSourceType.SOURCE; - } - } -} diff --git a/backend/src/main/java/ddangkong/config/sql/type/DataSourceType.java b/backend/src/main/java/ddangkong/config/sql/type/DataSourceType.java deleted file mode 100644 index c46a4a559..000000000 --- a/backend/src/main/java/ddangkong/config/sql/type/DataSourceType.java +++ /dev/null @@ -1,7 +0,0 @@ -package ddangkong.config.sql.type; - -public enum DataSourceType { - SOURCE, - REPLICA, - ; -} diff --git a/backend/src/main/resources/application-prod.yml b/backend/src/main/resources/application-prod.yml index 57effdc74..cb8e17aa6 100644 --- a/backend/src/main/resources/application-prod.yml +++ b/backend/src/main/resources/application-prod.yml @@ -2,16 +2,10 @@ spring: config: import: prod-secret.yml datasource: - source: - driver-class-name: com.mysql.cj.jdbc.Driver - username: ${secret.datasource.source.username} - password: ${secret.datasource.source.password} - jdbc-url: jdbc:mysql://${secret.datasource.source.host}:${secret.datasource.source.port}/${secret.datasource.database}?serverTimezone=Asia/Seoul&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&useSSL=false - replica: - driver-class-name: com.mysql.cj.jdbc.Driver - username: ${secret.datasource.replica.username} - password: ${secret.datasource.replica.password} - jdbc-url: jdbc:mysql://${secret.datasource.replica.host}:${secret.datasource.replica.port}/${secret.datasource.database}?serverTimezone=Asia/Seoul&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&useSSL=false + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://${secret.datasource.host}:${secret.datasource.port}/${secret.datasource.database}?useUnicode=true&characterEncoding=utf8&allowPublicKeyRetrieval=true&autoReconnect=true&serverTimezone=Asia/Seoul&useLegacyDatetimeCode=false + username: ${secret.datasource.username} + password: ${secret.datasource.password} sql: init: @@ -20,7 +14,7 @@ spring: jpa: database-platform: org.hibernate.dialect.MySQLDialect hibernate: - ddl-auto: none + ddl-auto: validate properties: hibernate: jdbc: