2024. 6. 24. 23:20ㆍ스프링
오늘, 졸업 논문을 위한 창의설계프로젝트를 마무리했다.
이번 프로젝트에서는 밸런스 게임이라는 도메인에 집중하기보다 여러 기술들을 사용(체험)해보고, 서버를 배포부터 구성하는 것에 초점을 맞췄다.
이벤트 브로커 서버가 담긴 컨테이너는 직접 SSH에서 배포했다.
API 서버와 추천 시스템 서버는 따라 깃허브 액션을 통해 도커 이미지로 만들어지고, 도커 허브에 push 된다. 이후, EC2 SSH에 접근, 도커 허브에서 갱신된 이미지를 pull 한다. 이는 도커 컴포즈를 활용해서 실행했다.
아래는 깃허브 액션을 위한 파일이다.
생각보다 깃허브 액션을 위한 환경변수 설정이 번거로웠다. 나중에는 요령이 생기긴 했지만.
name: CI/CD using GitHub Actions & Docker
on:
push:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Create directory and file if not exist
run: |
mkdir -p ./src/main/resources
echo "${{ secrets.APPLICATION }}" > ./src/main/resources/application.yml
- name: Create docker-compose.yml
run: echo "${{ secrets.DOCKER_COMPOSE_YML }}" > compose.yml
- name: Set executable permission
run: chmod +x ./gradlew
- name: Build with Gradle
run: ./gradlew build -x test
- name: Build Docker image using Docker Compose
run: docker-compose build
- name: Tag Docker image
run: docker tag ${{ secrets.DOCKER_USERNAME }}/valanse-api-server:latest makingjjj/valanse-api-server:${{ github.sha }}
- name: Login to Docker Hub
run: docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_ACCESS_TOKEN }}
- name: Push Docker image to Docker Hub
run: docker push ${{ secrets.DOCKER_USERNAME }}/valanse-api-server:${{ github.sha }}
- name: Deploy to prod
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.HOST_PROD }}
username: ec2-user
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd valanse-project/apiServer
CURRENT_DIR=$(pwd)
echo "IMAGE_TAG=${{ github.sha }}" > .env
docker pull ${{ secrets.DOCKER_USERNAME }}/valanse-api-server:${{ github.sha }}
docker-compose -f $CURRENT_DIR/docker-compose.yml stop apiserver
docker-compose -f $CURRENT_DIR/docker-compose.yml rm -f apiserver
docker-compose -f $CURRENT_DIR/docker-compose.yml up -d apiserver
EC2 인스턴스 하나에 3개의 도커 컨테이너를 Docker Compose를 활용해서 실행했다. 프리티어(t2.micro)로는 메모리가 부족하여 t2.small을 사용했다.
클라이언트의 요청에 응답하는 API 서버는 가비아에서 도메인을 구매하고 Route53을 통해 DNS 처리를 했다. 이 과정에서 HTTPS 프로토콜을 사용하는 프론트엔드에 맞추기 위해 AWS Certificate Manager에서 SSL 인증서를 발급받아 사용했다. 또한, API 서버로 들어오는 80, 8080 포트의 요청을 ALB를 활용하여 443 포트(HTTPS)로 우회시켰다.
컨테이너 내에 Redis는 JWT의 리프레시 토큰과 상태 토큰을 관리한다.
추천 시스템 서버는 원본 DB의 로깅을 통해 복제된 읽기 전용 DB를 사용하여 부하를 분산시켰다. RDS는 프리티어를 사용했지만, DB를 복제하니 요금이 발생했다. 굳이 복제를 할 필요가 없었을 것 같다.
이벤트 브로커 서버의 Kafka는 추천 시스템과 관련된 이벤트를 중개하는 역할을 한다. API 서버에 특정 요청이 오거나, 읽기 전용 DB를 사용하는 추천 시스템 서버가 DB 수정 요청이 필요하다면 이벤트를 등록했다.
이외에도 보안 취약점이 될 수 있는 S3 버킷 URL을 노출하지 않기 위해서 CloudFront를 사용했다. CDN 기능도 있으니 겸사겸사 좋을 거라고 생각했다.
학습보다 구현에 초점을 맞추고 진행했기에, 다음 프로젝트에서 이를 되짚어볼 계획이다.
'스프링' 카테고리의 다른 글
Spring Batch ItemReader 성능 개선, 근데 이제 Querydsl을 곁들인... (2) | 2024.10.15 |
---|---|
서버에서 클라이언트의 쿠키를 설정할 수 없었기에. (0) | 2024.05.12 |