[AWS] AWS ECS Fargate를 이용하여 Container 배포하기, Github Actions를 이용하여 자동화하기

꼬마요리사레미·2024년 4월 6일

AWS

목록 보기
7/10

✨ ECS : AWS의 컨테이너 오케스트레이션 서비스


ECS (Amazon Elastic Container Service)의 구성요소는 다음과 같다.

  • Task Definition (작업 정의) : 컨테이너를 실행하기 위해 필요한 구성을 정의한다.
    AWS Fargate 또는 Amazon EC2 인스턴스 중 어디에 컨테이너를 배포할지를 결정할 수도 있다.
  1. EC2 인스턴스: 사용자가 직접 관리하는 가상 서버를 사용하여 컨테이너를 실행할 수 있다.
  2. AWS Fargate: 사용자가 서버를 관리하지 않고도 컨테이너를 실행할 수 있는 서버리스 방식을 제공한다.
  • Task (작업) : Task Definition에 정의된 설정에 따라 실행되는 컨테이너 세트이다. Task는 하나 이상의 컨테이너로 구성될 수 있다. ECS 클러스터에서 실행된다.
  • Service (서비스) : Cluster 내에서 Task를 관리한다. ALB와 연결되어 네트워크 트래픽을 관리하고 필요한 경우 Auto Scaling을 통해 Task 수를 동적으로 관리할 수 있다.
  • Cluster (클러스터): Task가 실행되는 공간을 제공한다.

✨ Cluster

  • Cluster 내의 ECS Container들은 AWS Fargate 위에서 동작하도록 설정하였다.

✨ Tesk Definition

  • 해당 작업에 사용할 컨테이너 이미지의 URI를 Amazon ECR Repositories에서 복사하여 붙여넣으면 된다.
  • 또한 Spring Boot 애플리케이션은 기본적으로 8080 포트에서 동작하므로, 컨테이너를 호스트에 매핑할 때 포트 매핑을 8080으로 설정한다.
  • 애플리케이션 구동을 위해 필요한 환경 변수를 설정한다. 환경 변수는 AWS Secerts Manager가 관리하도록 설정하였고, 해당 보안 정보의 ARN을 복사해서 붙여넣으면 된다.

✨ Service

  • ECS Container를 위와 같이 Private Subnet에 위치시키면 외부와의 통신이 차단되기 때문에 ECR에서 Image를 Pull하는 과정에서 문제가 발생할 수 있다.
  • 이전에 Private Subnet의 라우팅 테이블을 NAT Gateway로 구성한 이유가 여기에서 나온다.
  • NAT Gateway 사용하여 트래픽을 Private Subnet 외부로 전달할 수 있도록 하면 해결된다.
  • 보안 그룹은 ALB로부터만 들어오는 모든 트래픽을 허용하도록 인바운드 규칙을 설정하였다.

  • Task Definition을 통해 정의한 ECS Container를 ALB로부터의 트래픽을 수신할 Target Group으로 설정한다. 해당 설정을 통해 ALB가 어떤 ECS Container에 트래픽을 라우팅할지 결정된다.
  • 결국 ALB는 리스너 규칙에 따라 외부로 들어오는 트래픽을 Target Group으로 적절히 분산시켜 라우팅할 수 있다.
  • 상태 확인 경로를 루트 경로로 설정했는데, 따로 API를 설계하지 않아 404 코드로 응답된다. 대상 그룹 상태 확인 편집 에서 성공 코드를 404로 설정해서 상태 확인이 제대로 이루도록 만든다.

이제 Github Actions를 이용하여 해당 작업이 자동화 될 수 있는 발판이 마련되었다.

- name: Download Task Definition Template
  id: download-task
  run: |
    aws ecs describe-task-definition \
      --task-definition ${{ env.ECS_TASK_DEFINITION }} \
      --query taskDefinition > task-definition.json

- 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: task-definition.json
    container-name: ${{ env.CONTAINER_NAME }}
    image: ${{ steps.build-image.outputs.image }}
  • 메인에 푸쉬가 될 때마다 해당 워크플로가 동작하면서 현재 버전의 작업 정의를 다운로드하고 새로운 이미지를 채워넣으면서 작업 정의가 업데이트 되고, 새 버전의 작업 정의가 계속 AWS에 올라가는 것을 발견했다.
  • 이렇게 작업 정의를 업데이트할 때 이전 버전 작업 정의는 비활성화 시키고자 아래와 같이 워크플로를 재정의 해주었다.
- name: Download Task Definition Template
  run: |
    # AWS ECS에서 작업 정의를 가져와서 task-definition.json에 저장한다.
    aws ecs describe-task-definition \
      --task-definition ${{ env.ECS_TASK_DEFINITION }} \
      --query taskDefinition \
      > task-definition.json
  id: download-task

- name: Set New Revision
  if: steps.download-task.outputs.revision > 1
  run: |
    # 현재 작업 정의의 버전을 가져와서 그 이전의 작업 버전을 새로운 리비전으로 설정한다.
    revision=$(jq '.revision' < task-definition.json)
    new_revision=$((revision - 1))

    # 새로운 리비전을 출력으로 설정한다.
    echo "::set-output name=revision::$new_revision"
  id: set-new-revision

- name: Deregister Previous Revision
  if: steps.set-new-revision.outputs.revision > 0 
  run: |
    # 해당 리비전의 작업 정의를 등록 해제한다.
    aws ecs deregister-task-definition \
      --task-definition ${{ env.ECS_TASK_DEFINITION }}:${{ steps.set-new-revision.outputs.revision }}

ECR에 이미지를 업데이트 하는 워크플로에 이어서 이번엔 ECS에 작업을 배포하는 워크플로도 작성을 완료하였다.

0개의 댓글