From 5c7b4ffdf8a1561bbd3720f40c21e68ec5a5467d Mon Sep 17 00:00:00 2001 From: 3uomlkh <3uomlkh@gmail.com> Date: Sun, 30 Mar 2025 00:05:49 +0900 Subject: [PATCH 1/4] =?UTF-8?q?chore(cd):=20CD=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=B0=8F=20=EB=AA=A8=EB=8B=88=ED=84=B0=EB=A7=81=20=EC=A4=80?= =?UTF-8?q?=EB=B9=84=20#18?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GitHub Actions용 cd.yml 작성 - Dockerfile 생성 - actuator 의존성 추가 - SecurityConfig에 actuator 접근 허용 설정 --- .github/workflows/cd.yml | 86 +++++++++++++++++++ Dockerfile | 12 +++ build.gradle | 2 + .../global/config/SecurityConfig.java | 1 + 4 files changed, 101 insertions(+) create mode 100644 .github/workflows/cd.yml create mode 100644 Dockerfile diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 0000000..ba0cfd5 --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,86 @@ +name: Deploy to EC2 + +on: + push: + branches: [ "main", "test/deploy" ] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Docker Build + run: docker build -t eightyage . + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }} + aws-region: ap-northeast-2 + + - name: ECR Login + run: | + aws ecr get-login-password | \ + docker login --username AWS --password-stdin ${{ secrets.ECR_URI }} + + - name: Docker Images Check + run: docker images + + - name: ECR Push + run: | + docker tag eightyage:latest ${{ secrets.ECR_URI }} + docker push ${{ secrets.ECR_URI }} + + - name: Deploy on EC2 + uses: appleboy/ssh-action@v1 + with: + host: ${{ secrets.EC2_HOST }} + username: ubuntu + key: ${{ secrets.EC2_SSH_KEY }} + envs: ECR_URI,DB_URL,DB_USER,DB_PASSWORD,JWT_SECRET_KEY,AWS_ACCESS_KEY,AWS_SECRET_KEY,REDIS_HOST + + script: | + export ECR_URI=${{ secrets.ECR_URI }} + export DB_URL=${{ secrets.DB_URL }} + export DB_USER=${{ secrets.DB_USER }} + export DB_PASSWORD=${{ secrets.DB_PASSWORD }} + export JWT_SECRET_KEY=${{ secrets.JWT_SECRET_KEY }} + export AWS_ACCESS_KEY=${{ secrets.AWS_ACCESS_KEY }} + export AWS_SECRET_KEY=${{ secrets.AWS_SECRET_KEY }} + export REDIS_HOST=${{ secrets.REDIS_HOST }} + + docker ps -q --filter ancestor=$ECR_URI | xargs -r docker stop + docker ps -aq --filter ancestor=$ECR_URI | xargs -r docker rm + + aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $ECR_URI + docker pull $ECR_URI + docker run -d -p 8080:8080 \ + -e DB_URL=$DB_URL \ + -e DB_USER=$DB_USER \ + -e DB_PASSWORD=$DB_PASSWORD \ + -e JWT_SECRET_KEY=$JWT_SECRET_KEY \ + -e AWS_ACCESS_KEY=$AWS_ACCESS_KEY \ + -e AWS_SECRET_KEY=$AWS_SECRET_KEY \ + -e REDIS_HOST=$REDIS_HOST \ + $ECR_URI + + - name: Health Check + uses: appleboy/ssh-action@v1 + with: + host: ${{ secrets.EC2_HOST }} + username: ubuntu + key: ${{ secrets.EC2_SSH_KEY }} + script: | + for i in {1..10}; do + echo "⏳ Health check attempt $i..." + if curl -f http://localhost:8080/actuator/health; then + echo "✅ Health check succeeded!" + exit 0 + fi + sleep 5 + done + echo "❌ Health check failed after multiple attempts" + exit 1 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2b62ead --- /dev/null +++ b/Dockerfile @@ -0,0 +1,12 @@ +FROM gradle:8.6-jdk17 AS build +WORKDIR /app +COPY . . +RUN gradle clean build -x test + +FROM eclipse-temurin:17-jdk-alpine +WORKDIR /app + +COPY --from=build /app/build/libs/*.jar app.jar +EXPOSE 8080 + +ENTRYPOINT ["java", "-Dspring.profiles.active=prod", "-jar", "app.jar"] \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7bfe89d..6d882b4 100644 --- a/build.gradle +++ b/build.gradle @@ -59,6 +59,8 @@ dependencies { implementation 'org.redisson:redisson:3.23.5' testImplementation 'org.mockito:mockito-inline:5.2.0' + + implementation 'org.springframework.boot:spring-boot-starter-actuator' } tasks.named('test') { diff --git a/src/main/java/com/example/eightyage/global/config/SecurityConfig.java b/src/main/java/com/example/eightyage/global/config/SecurityConfig.java index 2fe9756..50ee441 100644 --- a/src/main/java/com/example/eightyage/global/config/SecurityConfig.java +++ b/src/main/java/com/example/eightyage/global/config/SecurityConfig.java @@ -42,6 +42,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .rememberMe(AbstractHttpConfigurer::disable) .authorizeHttpRequests(auth -> auth .requestMatchers(request -> request.getRequestURI().startsWith("/api/v1/auth")).permitAll() + .requestMatchers("/actuator/**").permitAll() .anyRequest().authenticated() ) .build(); From 65d6f29291d4cb4372adb582a74774fae63a54c7 Mon Sep 17 00:00:00 2001 From: 3uomlkh <3uomlkh@gmail.com> Date: Sun, 30 Mar 2025 00:09:30 +0900 Subject: [PATCH 2/4] =?UTF-8?q?chore(config):=20S3=EC=99=80=20Redis=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EA=B0=92=20=EC=99=B8=EB=B6=80=20=EC=A3=BC?= =?UTF-8?q?=EC=9E=85=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20#18?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - S3Config accessKey, secretKey 설정값 수정 - RedissonConfig에 하드코딩된 host 값 제거 - @Value를 활용해 application 설정값으로 주입되도록 변경 --- .../example/eightyage/global/config/RedissonConfig.java | 8 ++++++-- .../com/example/eightyage/global/config/S3Config.java | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/example/eightyage/global/config/RedissonConfig.java b/src/main/java/com/example/eightyage/global/config/RedissonConfig.java index 4586fb3..655646c 100644 --- a/src/main/java/com/example/eightyage/global/config/RedissonConfig.java +++ b/src/main/java/com/example/eightyage/global/config/RedissonConfig.java @@ -5,15 +5,19 @@ import org.redisson.config.Config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.beans.factory.annotation.Value; @Configuration public class RedissonConfig { + @Value("${spring.data.redis.host}") + private String redisHost; + @Bean public RedissonClient redisson() { Config config = new Config(); config.useSingleServer() - .setAddress("redis://localhost:6379"); - return Redisson.create(); + .setAddress("redis://" + redisHost + ":6379"); + return Redisson.create(config); } } diff --git a/src/main/java/com/example/eightyage/global/config/S3Config.java b/src/main/java/com/example/eightyage/global/config/S3Config.java index 5d48b01..db42729 100644 --- a/src/main/java/com/example/eightyage/global/config/S3Config.java +++ b/src/main/java/com/example/eightyage/global/config/S3Config.java @@ -13,10 +13,10 @@ public class S3Config { private static final String REGION = "ap-northeast-2"; - @Value("${aws.access-key}") + @Value("${AWS_ACCESS_KEY}") private String accessKey; - @Value("${aws.secret-key}") + @Value("${AWS_SECRET_KEY}") private String secretKey; From ddce9d48f20f3b0e433a34762ee324bc4ab92975 Mon Sep 17 00:00:00 2001 From: 3uomlkh <3uomlkh@gmail.com> Date: Sun, 30 Mar 2025 14:27:27 +0900 Subject: [PATCH 3/4] =?UTF-8?q?chore(cd):=20=EB=B0=B0=ED=8F=AC=20=EC=84=B1?= =?UTF-8?q?=EA=B3=B5=20=EB=B0=8F=20=EC=8B=A4=ED=8C=A8=20=EC=97=AC=EB=B6=80?= =?UTF-8?q?=20=ED=99=95=EC=9D=B8=20=EC=8A=AC=EB=9E=99=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20#18?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### 변경사항 - cd.yml에 배포 성공 및 실패 여부에 따른 슬랙 알림 추가 --- .github/workflows/cd.yml | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index ba0cfd5..45f8d17 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -83,4 +83,40 @@ jobs: sleep 5 done echo "❌ Health check failed after multiple attempts" - exit 1 \ No newline at end of file + exit 1 + + - name: Notify Slack - 배포 성공 + if: success() + run: | + curl -X POST -H 'Content-type: application/json' \ + --data '{ + "text": "✅ *배포 성공!* 🎉", + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "*✅ 배포 성공했습니다!*\n\n*브랜치:* `${{ github.ref_name }}`\n" + } + } + ] + }' \ + ${{ secrets.SLACK_WEBHOOK_URL }} + + - name: Notify Slack - 배포 실패 + if: failure() + run: | + curl -X POST -H 'Content-type: application/json' \ + --data '{ + "text": "❌ *배포 실패!* 🔥", + "blocks": [ + { + "type": "section", + "text": { + "type": "mrkdwn", + "text": "*❌ 배포 실패했습니다!*\n\n*브랜치:* `${{ github.ref_name }}`\n" + } + } + ] + }' \ + ${{ secrets.SLACK_WEBHOOK_URL }} \ No newline at end of file From 60e9bf9fcfc606f138a31c9fd9620d5bb24d9cfa Mon Sep 17 00:00:00 2001 From: 3uomlkh <3uomlkh@gmail.com> Date: Sun, 30 Mar 2025 14:37:48 +0900 Subject: [PATCH 4/4] =?UTF-8?q?chore(cd):=20application-prod.yml=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80=20#18?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### 변경사항 - 운영 환경에 필요한 application-prod.yml 파일 추가 - cd 대상 브랜치 main으로 한정 --- .github/workflows/cd.yml | 2 +- src/main/resources/application-prod.yml | 50 +++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/application-prod.yml diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 45f8d17..9a3f5ae 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -2,7 +2,7 @@ name: Deploy to EC2 on: push: - branches: [ "main", "test/deploy" ] + branches: [ main ] jobs: deploy: diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml new file mode 100644 index 0000000..3006731 --- /dev/null +++ b/src/main/resources/application-prod.yml @@ -0,0 +1,50 @@ +server: + port: 8080 + servlet: + context-path: / + encoding: + charset: UTF-8 + enabled: true + force: true + session: + timeout: 1800 + +spring: + application: + name: eightyage + + data: + redis: + host: ${SPRING_DATA_REDIS_HOST} + port: 6379 + + datasource: + url: ${DB_URL} + username: ${DB_USER} + password: ${DB_PASSWORD} + driver-class-name: com.mysql.cj.jdbc.Driver + + jpa: + hibernate: + ddl-auto: update + properties: + hibernate: + show_sql: false + format_sql: true + use_sql_comments: false + dialect: org.hibernate.dialect.MySQLDialect + +jwt: + secret: + key: ${JWT_SECRET_KEY} + +management: + endpoints: + web: + exposure: + include: health,info + endpoint: + health: + show-details: always + security: + enabled: false \ No newline at end of file