From b9b2020b28c6759730001a28b72d9073a05cc653 Mon Sep 17 00:00:00 2001 From: MooSong Lee <46563149+fromitive@users.noreply.github.com> Date: Thu, 19 Dec 2024 20:47:34 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20prod=20CI/CD=20=EB=B3=80=EA=B2=BD=20(#6?= =?UTF-8?q?72)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 로컬 스토리지 서비스로 변경 * refactor: docker 이미지 cpu 아키텍처 변경 * chore: ci/cd 스크립트 변경 * chore: 인프라 환경 변경 (ssl, 로컬 이미지서버 업로드) * style: eol 제거 * fix: 설정 오류 해결 * chore: local health-check를 위해 80포트 활성화 * chore: local 헬스 체크를 위해 도커에 로컬 80포트 활성화 * fix: 호스트명 다시 변경 * fix: nginx 설정 변경 * chore: nginx 이미지서버 설정 변경 * refactor: 저장 로직 분리 * chore: ssl을 로드벨런서가 처리하도록 변경 * chore: 이미지 경로 환경별로 다르게 변경 * chore: dev.default.conf 추가 * chore: ci/cd dev.default.conf 설정 분리 * fix: 테스트 프로파일을 추가하여 테스트 깨짐 수정 * style: 개행추가 * chore: image dev 경로 변경 * refactor: default 이미지 Url 변경 * chore: 브랜치 변경으로 인한 ci/cd 트리거 브랜치 수정 * chore: 브랜치 변경으로 인한 ci/cd 트리거 브랜치 수정 --- .github/workflows/backend-dev-ci-cd.yml | 14 ++++---- .github/workflows/backend-prod-ci-cd.yml | 33 ++++++++----------- Dockerfile | 2 +- backend/deploy/default.conf | 16 +++++++-- backend/deploy/dev.default.conf | 26 +++++++++++++++ backend/deploy/launch_next_container.sh | 1 + backend/deploy/setup.sh | 9 +++-- backend/deploy/switch_blue_green_container.sh | 10 +++++- .../service/dto/OfferingMetaResponse.java | 3 +- .../storage/config/StorageConfig.java | 4 +-- .../storage/service/LocalStorageService.java | 17 +++++++--- .../src/main/resources/application-dev.yml | 4 +++ .../src/main/resources/application-prod.yml | 4 +++ backend/src/main/resources/application.yml | 4 --- .../member/service/NicknameGeneratorTest.java | 2 ++ .../src/test/resources/application-test.yml | 5 +++ 16 files changed, 110 insertions(+), 44 deletions(-) create mode 100644 backend/deploy/dev.default.conf diff --git a/.github/workflows/backend-dev-ci-cd.yml b/.github/workflows/backend-dev-ci-cd.yml index e6de46050..f0e17ae60 100644 --- a/.github/workflows/backend-dev-ci-cd.yml +++ b/.github/workflows/backend-dev-ci-cd.yml @@ -7,12 +7,12 @@ on: - "backend/**" - ".github/workflows/backend-dev-ci-cd.yml" - "Dockerfile" - # pull_request: - # branches: [ "chongdae" ] - # paths: - # - "backend/**" - # - ".github/workflows/backend-dev-ci-cd.yml" - # - "Dockerfile" +# pull_request: +# branches: [ "develop" ] +# paths: +# - "backend/**" +# - ".github/workflows/backend-dev-ci-cd.yml" +# - "Dockerfile" jobs: @@ -80,5 +80,5 @@ jobs: steps: - name: Switch from old to new container run: | - bash switch_blue_green_container.sh + bash switch_blue_green_container.sh dev.default.conf working-directory: backend/deploy diff --git a/.github/workflows/backend-prod-ci-cd.yml b/.github/workflows/backend-prod-ci-cd.yml index 83b353135..1abcf213a 100644 --- a/.github/workflows/backend-prod-ci-cd.yml +++ b/.github/workflows/backend-prod-ci-cd.yml @@ -7,12 +7,12 @@ on: - "backend/**" - ".github/workflows/backend-prod-ci-cd.yml" - "Dockerfile" - # pull_request: - # branches: [ "develop" ] - # paths: - # - "backend/**" - # - ".github/workflows/backend-prod-ci-cd.yml" - # - "Dockerfile" +# pull_request: +# branches: [ "develop" ] +# paths: +# - "backend/**" +# - ".github/workflows/backend-prod-ci-cd.yml" +# - "Dockerfile" jobs: @@ -62,28 +62,23 @@ jobs: docker push ${{ secrets.BE_DOCKERHUB_USERNAME }}/${{ secrets.BE_DOCKER_IMAGE_NAME_PROD }}:${GITHUB_SHA::7} deploy-new-container: - needs: build-and-test - strategy: - matrix: - runner: [prod-a, prod-b] - runs-on: [ self-hosted, ${{ matrix.runner }} ] + needs: build-and-test + runs-on: [ self-hosted, prod ] steps: - name: Checkout repository uses: actions/checkout@v4 - - name: Deploy new container on ${{ matrix.runner }} + - name: Deploy new container run: | bash launch_next_container.sh ${GITHUB_SHA::7} prod ${{ secrets.BE_DOCKERHUB_USERNAME }} ${{ secrets.BE_DOCKER_IMAGE_NAME_PROD }} working-directory: backend/deploy switch-new-container: needs: deploy-new-container - strategy: - matrix: - runner: [prod-a, prod-b] - runs-on: [ self-hosted, ${{ matrix.runner }} ] + runs-on: [ self-hosted, prod ] + steps: - - name: Switch from old to new container on ${{ matrix.runner }} + - name: Switch from old to new container run: | - bash switch_blue_green_container.sh - working-directory: backend/deploy \ No newline at end of file + bash switch_blue_green_container.sh default.conf + working-directory: backend/deploy diff --git a/Dockerfile b/Dockerfile index c676ab6ec..9306571fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=linux/arm64 amazoncorretto:17 +FROM --platform=linux/amd64 amazoncorretto:17 ENV TZ=Asia/Seoul diff --git a/backend/deploy/default.conf b/backend/deploy/default.conf index 6dfeddc86..c73e25c4d 100644 --- a/backend/deploy/default.conf +++ b/backend/deploy/default.conf @@ -1,14 +1,26 @@ upstream active_server { - server chongdae_backend:8080; + server chongdae_backend:8080; } server { listen 80; + server_name chongdae.site; + location / { - proxy_pass http://active_server; + proxy_pass http://active_server; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } +server { + listen 80; + server_name image.chongdae.site; + + root /uploads; + + location / { + try_files $uri $uri/ =404; + } +} diff --git a/backend/deploy/dev.default.conf b/backend/deploy/dev.default.conf new file mode 100644 index 000000000..00d3bb12d --- /dev/null +++ b/backend/deploy/dev.default.conf @@ -0,0 +1,26 @@ +upstream active_server { + server chongdae_backend:8080; +} + +server { + listen 80; + server_name dev.chongdae.site; + + location / { + proxy_pass http://active_server; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} + +server { + listen 80; + server_name image.dev.chongdae.site; + + root /uploads; + + location / { + try_files $uri $uri/ =404; + } +} diff --git a/backend/deploy/launch_next_container.sh b/backend/deploy/launch_next_container.sh index 287d02326..d36eb1d7a 100755 --- a/backend/deploy/launch_next_container.sh +++ b/backend/deploy/launch_next_container.sh @@ -73,6 +73,7 @@ docker run -d \ --network ${INITIAL_BLUE_GREEN_NETWORK_NAME} \ --name ${NEXT_CONTAINER} \ -v /logs:/logs \ + -v /uploads:/uploads \ -e SPRING_PROFILES_ACTIVE=${PROFILE_ACTIVE} \ ${DOCKERHUB_USER_NAME}/${DOCKER_IMAGE_NAME}:${GITHUB_SHA:0:7} diff --git a/backend/deploy/setup.sh b/backend/deploy/setup.sh index e9812c79c..34ccbad11 100755 --- a/backend/deploy/setup.sh +++ b/backend/deploy/setup.sh @@ -3,9 +3,11 @@ GITHUB_SHA=$1 PROFILE_ACTIVE=$2 DOCKERHUB_USER_NAME=$3 DOCKER_IMAGE_NAME=$4 +NGINX_DEFAULT_CONF_NAME=$5 + # parameter check -if [ -z "$GITHUB_SHA" ] || [ -z "$PROFILE_ACTIVE" ] || [ -z "$DOCKERHUB_USER_NAME" ] || [ -z "$DOCKER_IMAGE_NAME" ]; then +if [ -z "$GITHUB_SHA" ] || [ -z "$PROFILE_ACTIVE" ] || [ -z "$DOCKERHUB_USER_NAME" ] || [ -z "$DOCKER_IMAGE_NAME" ] || [ -z "$NGINX_DEFAULT_CONF_NAME" ]; then echo "사용법: $0 " exit 1 fi @@ -13,7 +15,6 @@ fi # intialize blue & gren INITIAL_INSTANCE_NAME="chongdae_backend_green" INITIAL_BLUE_GREEN_NETWORK_NAME="blue_green_network" -NGINX_DEFAULT_CONF_PATH="default.conf" NGINX_NEW_CONF_PATH="new-default.conf" # 1. ADD DOCKER NETWORK @@ -31,6 +32,7 @@ docker run -d \ --network ${INITIAL_BLUE_GREEN_NETWORK_NAME} \ --name ${INITIAL_INSTANCE_NAME} \ -v /logs:/logs \ + -v /uploads:/uploads \ -e SPRING_PROFILES_ACTIVE=${PROFILE_ACTIVE} \ ${DOCKERHUB_USER_NAME}/${DOCKER_IMAGE_NAME}:${GITHUB_SHA:0:7} @@ -39,7 +41,7 @@ if [ $? -ne 0 ]; then fi # 3. CHANGE INITIAL UP STREAM SERVER -cp ${NGINX_DEFAULT_CONF_PATH} ${NGINX_NEW_CONF_PATH} +cp ${NGINX_DEFAULT_CONF_NAME} ${NGINX_NEW_CONF_PATH} if grep -q "server chongdae_backend:" "${NGINX_NEW_CONF_PATH}"; then sed -i "s/server chongdae_backend:/server ${INITIAL_INSTANCE_NAME}:/" "${NGINX_NEW_CONF_PATH}" @@ -51,6 +53,7 @@ docker run -d \ --network ${INITIAL_BLUE_GREEN_NETWORK_NAME} \ --name nginx \ -p 80:80 \ + -v /uploads:/uploads \ nginx:latest # 5. setup proxy in nginx container diff --git a/backend/deploy/switch_blue_green_container.sh b/backend/deploy/switch_blue_green_container.sh index 25402f9b0..1859661a9 100755 --- a/backend/deploy/switch_blue_green_container.sh +++ b/backend/deploy/switch_blue_green_container.sh @@ -1,8 +1,16 @@ #!/bin/bash +NGINX_DEFAULT_CONF=$1 + +# parameter check +if [ -z "$NGINX_DEFAULT_CONF" ]; then + echo "사용법: $0 " + exit 1 +fi + + NGINX_CONTAINER_NAME="nginx" BLUE_CONTAINER="chongdae_backend_blue" GREEN_CONTAINER="chongdae_backend_green" -NGINX_DEFAULT_CONF="default.conf" NGINX_CHANGED_DEFAULT_CONF="new-default.conf" get_active_container() { diff --git a/backend/src/main/java/com/zzang/chongdae/offering/service/dto/OfferingMetaResponse.java b/backend/src/main/java/com/zzang/chongdae/offering/service/dto/OfferingMetaResponse.java index 460c3cef9..5832acec1 100644 --- a/backend/src/main/java/com/zzang/chongdae/offering/service/dto/OfferingMetaResponse.java +++ b/backend/src/main/java/com/zzang/chongdae/offering/service/dto/OfferingMetaResponse.java @@ -3,7 +3,8 @@ import com.zzang.chongdae.offering.repository.entity.OfferingEntity; public record OfferingMetaResponse(String title, String thumbnailUrl) { - private static final String DEFAULT_THUMBNAIL_URL = "https://d3a5rfnjdz82qu.cloudfront.net/chongdae-market/images/common/no-image.png"; + + private static final String DEFAULT_THUMBNAIL_URL = "https://image.chongdae.site/common/no-image.png"; public OfferingMetaResponse(OfferingEntity offering) { this(offering.getTitle(), getOrDefault(offering.getThumbnailUrl())); diff --git a/backend/src/main/java/com/zzang/chongdae/storage/config/StorageConfig.java b/backend/src/main/java/com/zzang/chongdae/storage/config/StorageConfig.java index b5727959b..4c852e895 100644 --- a/backend/src/main/java/com/zzang/chongdae/storage/config/StorageConfig.java +++ b/backend/src/main/java/com/zzang/chongdae/storage/config/StorageConfig.java @@ -4,7 +4,7 @@ import com.amazonaws.regions.Regions; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; -import com.zzang.chongdae.storage.service.AmazonS3StorageService; +import com.zzang.chongdae.storage.service.LocalStorageService; import com.zzang.chongdae.storage.service.StorageService; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -14,7 +14,7 @@ public class StorageConfig { @Bean public StorageService storageService() { - return new AmazonS3StorageService(amazonS3()); + return new LocalStorageService(); } private AmazonS3 amazonS3() { diff --git a/backend/src/main/java/com/zzang/chongdae/storage/service/LocalStorageService.java b/backend/src/main/java/com/zzang/chongdae/storage/service/LocalStorageService.java index e4da968f7..3f32605c5 100644 --- a/backend/src/main/java/com/zzang/chongdae/storage/service/LocalStorageService.java +++ b/backend/src/main/java/com/zzang/chongdae/storage/service/LocalStorageService.java @@ -25,16 +25,25 @@ public class LocalStorageService implements StorageService { @Value("${storage.path}") private String storagePath; + LocalStorageService(String redirectUrl, String storagePath) { + this.redirectUrl = redirectUrl; + this.storagePath = storagePath; + } + @Override public String uploadFile(MultipartFile file) { + String extension = getFileExtension(file); + validateFileExtension(extension); + String newFilename = UUID.randomUUID().toString(); + storeFile(file, newFilename); + return createUri(newFilename); + } + + private void storeFile(MultipartFile file, String newFilename) { try { - String extension = getFileExtension(file); - validateFileExtension(extension); - String newFilename = UUID.randomUUID() + "." + extension; Path uploadPath = Paths.get(storagePath); Path filePath = uploadPath.resolve(newFilename); Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING); - return createUri(filePath.toString()); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/backend/src/main/resources/application-dev.yml b/backend/src/main/resources/application-dev.yml index 7bee33ae5..db8e5b7cd 100644 --- a/backend/src/main/resources/application-dev.yml +++ b/backend/src/main/resources/application-dev.yml @@ -14,3 +14,7 @@ security: token: access-secret-key: ${JWT_ACCESS_SECRET_KEY} refresh-secret-key: ${JWT_REFRESH_SECRET_KEY} + +storage: + path: /uploads + redirectUrl: image.dev.chongdae.site \ No newline at end of file diff --git a/backend/src/main/resources/application-prod.yml b/backend/src/main/resources/application-prod.yml index ce19cf6ee..ae2396cca 100644 --- a/backend/src/main/resources/application-prod.yml +++ b/backend/src/main/resources/application-prod.yml @@ -19,3 +19,7 @@ security: token: access-secret-key: ${JWT_ACCESS_SECRET_KEY} refresh-secret-key: ${JWT_REFRESH_SECRET_KEY} + +storage: + path: /uploads + redirectUrl: image.chongdae.site \ No newline at end of file diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml index ffeab0a95..164854d5d 100644 --- a/backend/src/main/resources/application.yml +++ b/backend/src/main/resources/application.yml @@ -46,10 +46,6 @@ amazon: redirectUrl: d3a5rfnjdz82qu.cloudfront.net storagePath: chongdae-market/images/offerings/product/ -storage: - path: /uploads - redirectUrl: image.chongdae.site - security: jwt: token: diff --git a/backend/src/test/java/com/zzang/chongdae/member/service/NicknameGeneratorTest.java b/backend/src/test/java/com/zzang/chongdae/member/service/NicknameGeneratorTest.java index 42e9f7a23..156c582de 100644 --- a/backend/src/test/java/com/zzang/chongdae/member/service/NicknameGeneratorTest.java +++ b/backend/src/test/java/com/zzang/chongdae/member/service/NicknameGeneratorTest.java @@ -7,7 +7,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.test.context.ActiveProfiles; +@ActiveProfiles("test") @SpringBootTest(webEnvironment = WebEnvironment.NONE, classes = {TestNicknameWordPickerConfig.class}) public class NicknameGeneratorTest { diff --git a/backend/src/test/resources/application-test.yml b/backend/src/test/resources/application-test.yml index 47e4f02e4..abe554500 100644 --- a/backend/src/test/resources/application-test.yml +++ b/backend/src/test/resources/application-test.yml @@ -11,6 +11,7 @@ spring: properties: hibernate: format_sql: true + security: jwt: token: @@ -22,3 +23,7 @@ security: fcm: secret-key: path: /fcm/chongdaemarket-fcm-key.json + +storage: + path: /uploads + redirectUrl: fake.image.chongdae.site \ No newline at end of file