
마이크로서비스 아키텍처(Microservices Architecture, MSA)를 구성하는 것은 ECS를 사용하여 컨테이너화된 애플리케이션을 배포하고 관리하는 것과 관련이 있습니다. 아래는 ECS를 통해 MSA를 구성하는 일반적인 단계입니다.
먼저 프로젝트의 HealthCheck를 하기위해 아주 간단한 API를 하나 만들어줍니다.
@RestController
public class HealthCheckController {
@GetMapping("/")
public String checkHealth() {
return "OK";
}
}
Dockerfile은 아래와 같이 작성해 주었습니다.
# Dockerfile
# jdk17 Image Start
FROM openjdk:17
# 인자 설정 - JAR_File
ARG JAR_FILE=build/libs/*.jar
# jar 파일 복제
COPY ${JAR_FILE} app.jar
# 인자 설정 부분과 jar 파일 복제 부분 합쳐서 진행해도 무방
#COPY build/libs/*.jar app.jar
# 실행 명령어
ENTRYPOINT ["java", "-jar", "/app.jar"]
bootJar를 실행하여 jar파일을 build 합니다.
로컬에서 서버가 잘 뜨는지는 먼저 확인해 봅시다!
가장 먼저 프로젝트를 docker image로 빌드해야 한다.
먼저 리포지토리 생성을 해야합니다.

리포지토리가 잘 생성이 되었다면 이미지를 푸시합니다.
생성된 리포지토리를 들어가여 푸시 명령 보기를 클릭해 image를 push 합니다.

aws cli 설치는 생략하겠습니다.
명령 프롬프트에서 아래의 명령어를 순서대로 실행합니다. 원하는 태그를 달아 push 할 수 있습니다.

이미지 푸시가 성공적으로 이루어진 모습입니다.

다음으로 Task 정의를 생성해야 합니다.

먼저 태스크 정의 패밀리의 이름을 지정해줍니다.

AWS Fargate로 인프라 설정을 해줍니다. 그 밖의 다른 설정은 default로 진행합니다.

컨테이너 이름과 이미지 URI를 넣어주어야 하는데 이미지 URI는 ECR에 Push한 이미지 URI를 넣어주면 됩니다.
ECR 리포지토리에서 URI 복사한 후 붙여 넣어주면 됩니다.
ECR Repository

이후 포트설정을 해주고 환경 변수가 필요하다면 넣어줘야 합니다.
이 프로젝트의 경우엔 application.yml에 DB정보나 JWT-secret-key같은 정보들을 환경변수로 설정해 놓았기 때문에 환경 변수를 추가해 주었습니다.
여기까지 설정을 마쳤다면 태스크 정의 생성을 해주면 됩니다.
다음으로 클러스터를 생성해보겠습니다.

클러스터의 이름을 설정하고 Fargate로 생성해줍니다.

생성된 클러스터에 들어와 서비스를 생성해줘야 합니다.
서비스 란의 생성 버튼을 눌러 생성합니다.

환경란은 모두 default로 설정하고 넘어갑니다.

위에서 생성한 테스크 정보를 넣어줍니다.
서비스 이름도 원하는 이름을 지정해주면 됩니다.

추가적으로 네트워킹과 로드밸런싱을 설정해주었습니다.

먼저 네트워킹 설정을 살펴보겠습니다.
VPC, 서브넷, 보안그룹을 설정해주겠습니다.

저는 여러개의 서비스를 만들고 로드밸런서를 통해 요청을 나누어 보내기 위해 한개의 로드밸런서를 계속 사용합니다.

다음으로 리스너와 대상 그룹을 설정해줍니다.
리스터 포트에 8081로 열어주면 로드밸런서에 8081번 포트로 요청이 오면 이 요청을 대상 그룹으로 전달합니다.

설정을 마쳤으면 서비스를 생성합니다.
서비스를 생성하면 잠시 뒤에 클러스터안에 서비스가 생성되기 시작합니다. 서비스에 들어가 정의된 태스크에 들어갑니다.

프라이빗 IP를 복사합니다.

이후 대상 그룹에서 대상 등록하기 버튼을 누릅니다.

태스크에서 복사한 프라이빗 IP주소를 Ipv4에 넣어줍니다. 포트는 8081로 설정하고 아래에 보류 중인 것으로 포함을 누른뒤 대상을 등록합니다.

여기까지 성공적으로 마치면 서비스가 성공적으로 생성됩니다.
생성된 서비스에 들어와 로드 밸런서 보기 버튼을 클릭합니다.

DNS이름을 복사하여 새로운 페이지에서 접속해보겠습니다.


성공적으로 배포가 되었습니다!
github actions
name: Deploy to Amazon ECS
on:
push:
branches: [ "main" ]
env:
AWS_REGION: ap-northeast-2 # set this to your preferred AWS region, e.g. us-west-1
ECR_REPOSITORY: 10-trillion-dollars # set this to your Amazon ECR repository name
ECS_SERVICE: testest-front-service # set this to your Amazon ECS service name
ECS_CLUSTER: test-cluster # set this to your Amazon ECS cluster name
ECS_TASK_DEFINITION: testest-family-revision4.json # set this to the path to your Amazon ECS task definition
# file, e.g. .aws/task-definition.json
CONTAINER_NAME: testest-container # set this to the name of the container in the
# containerDefinitions section of your task definition
permissions:
contents: read
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Java JDK
uses: actions/setup-java@v4.2.1
with:
java-version: 17
distribution: 'adopt'
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
- name: gradlew bootJar
run: ./gradlew bootJar
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
IMAGE_TAG: ${{ github.sha }}
run: |
# Build a docker container and
# push it to ECR so that it can
# be deployed to ECS.
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT
- name: Fill in the new image ID in the Amazon ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: ${{ env.ECS_TASK_DEFINITION }}
container-name: ${{ env.CONTAINER_NAME }}
image: ${{ steps.build-image.outputs.image }}
- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: ${{ env.ECS_SERVICE }}
cluster: ${{ env.ECS_CLUSTER }}
wait-for-service-stability: true
우리 팀의 프로젝트는 Monolithic Architecture에서 MicroSerivces Architecture로 나아가고자 한다. 각 도메인 별로 서버를 나누어 놨고 서버간 통신은 feign통신, 공통적으로 들어가는 내용에 대해서는 공통 라이브러리를 만들어 놓았다. 처음에는 5개의 서버를 각각 docker image로 build하여 docker hub에 push하고 1개의 EC2 인스턴스에서 image를 pull 받아 docker compose로 묶어서 서버를 띄웠다.
하지만 여기서 생기는 문제점은 위와 같은 방식으로 서버를 띄우게 되면 MSA환경으로 서버를 나눈 이유가 사라진다. 인스턴스가 다운되면 모든 서비스가 중지될 것이다. 그래서 우리는 ECS로 서버를 각각 띄우기로 결정했다. 이렇게 되면 1개의 서버에 문제가 생겨도 다른 서버에 미치는 영향을 최소화 할 수 있다고 기대하기 때문이다.