[AWS] ECS로 배포하기(Feat. GitLab CI/CD)

sinryuji·2025년 2월 28일
post-thumbnail

지금까지 EC2에 Docker를 설치하여 직접 Docker Hub에 업로드한 이미지를 pull 받아 컨테이너를 구동하는 식으로만 배포를 해왔습니다. 하지만 AWS에서는 Elastic Container Service(ECS)라는 서비스를 제공해주고 이를 활용하면 컨테이너 환경에 더욱 최적화된 배포가 가능합니다.

이는 Kubernetes와 같은 Container OrchestrationKubernetes보다 쉽고 비용적으로 저렴하기에 소규모 프로젝트에 적합합니다.

ECS 구조

출처: https://aws.amazon.com/ko/blogs/korea/new-amazon-ecs-service-connect-enabling-easy-communication-between-microservices/

ECS는 크게 ECR, ECS Cluster, ECS Service, ECS Task로 이루어집니다.

  • ECR: Docker image 저장소
  • ECS Cluster: 컨테이너를 실행하기 위한 Cluster로 여러 인스턴스로 이루어집니다. 이 인스턴스에 Docker container가 분산 실행됩니다. Serverless로 할 경우에는 인스턴스도 필요가 없습니다.
  • ECS Service: Docker 애플리케이션의 실행 그룹입니다.
  • ECS Task: ECS Server에 실제로 실행되는 docker container들을 Task 라고 합니다.
  • 로드밸런서와, 모니터링, Auto Scaling 등의 요소도 있습니다. ECS를 이용하면 이런 요소들까지 자동으로 관리 됩니다.

ECS의 최소 실행 단위는 Task이고 Service는 Task가 2개 이상 모인 것입니다. 어느 포트에서 몇개의 Docker Container들을 어떤 이미지로 실행 시킬지 등의 실행 정보가 필요하고, 이러한 정보를 기술해 놓은 것이 Task definition 입니다.

ECS 설정하기

보안 그룹 설정

보안 그룹을 새로 만들어서 인바운드 규칙을 편집해줍니다. 저는 다음과 같이 80포트오 8080포트를 열어주었습니다.

ECR 설정

ECR은 Elastic Container Registry의 약자로 ECS에서 사용할 Docker Image를 저장하는 곳입니다.

이름만 자유롭게 적어주면 생성이 됩니다.

레포지토리 생성 후 우측 상단에 주황색의 푸쉬 명령 보기를 클릭합니다.

그럼 위와 같이 커맨드들이 나오는데 후에 CI/CD를 작성할 때 활용이 됩니다.

ECS Cluster 설정

ECS 대시보드에서 클러스터 생성을 클릭합니다.

클러스터 이름을 자유롭게 설정하고 AWS Fargate(서버리스)를 선택해서 생성하면 됩니다.

좌측의 태스크 정의를 클릭하고 우측 상단의 주황색 새 태스크 정의 생성을 클릭합니다.

나머지는 다 기본 설정으로 냅두고 태스크 정의 패밀리와 컨테이너 정보에 이름와 이미지 URI를 채워줍니다. 이미지 URI은 위에서 생성한 ECR의 URI입니다. 그 후 Spring 컨테이너를 띄울것이기에 포트를 8080으로 설정해줍니다.

ECS Service 설정

앞서 생성상 ECS Cluster는 클릭하면 하단에서 서비스를 생성할 수 있습니다.

나머지는 다 기본 설정으로 냅두고 배포 구성에서 패밀리를 앞서 생성한 Task로 선택해줍니다.

그후 스크롤을 내려 로드밸런서를 설정해줍니다. 컨테이너는 앞서 생성한 컨테이너, 리스너에서 80포트 리스닝 설정을 확인합니다.

AWS IAM 설정

ECS 접근하기 위한 IAM을 생성하겠습니다. IAM 대시보드에서 좌측에 사용자를 클릭하고 우측 상단에 사용자 생성을 클릭합니다.

그 후 자유롭게 사용자 이름을 입력하고 다음을 누르면 권한을 설정할 수 있습니다. 직접 정책 연결을 선택하고 AdministratorAccess를 선택합니다. 모든 권한이 있는 정책입니다.

그 후 생성한 사용자를 누르고 액세스 키 만들기를 누르고 기타를 선택합니다. 만들어진 액세스 키를 .csv 파일로 다운로드 받아 저장합니다.

GitLab CI/CD

이제 CI/CD를 구축해봅시다. ECS를 콘솔에서 수동으로 사용할수도 있지만 이는 매우 복잡하고 귀찮은 작업으로 ECS를 제대로 사용하기 위해서 CI/CD는 선택 사항이 아니라 필수입니다.

우선 GitLab CI/CD를 이용한 배포 과정을 알아봅시다.

여담이지만 이번에 GitLab을 처음 이용해보았는데, GitHub Actions는 CI/CD 외에도 다양한 워크플로우를 위해 자유롭고 다채로운 사용이 가능하지만 그만큼 문법도 다양하고 action의 종류나 사용법 등 알아보아야 할 정보가 많은 느낌인데 반해, GitLab CI/CD는 CI/CD에 특화된 GitLab 내장 기능으로 CI/CD를 구축하는데는 더 직관적이고 간단한 느낌이들었습니다. 추가로 private repository에도 CI/CD가 가능하다는 것도 큰 장점입니다.

GitLab Repository나 Spring 프로젝트 생성 과정은 생략하겠습니다.

Dockerfile

FROM openjdk:17-jdk-slim

VOLUME /tmp

ARG JAR_FILE=build/libs/*.jar

COPY ${JAR_FILE} app.jar

ENTRYPOINT ["java","-jar","/app.jar"]

프로젝트를 Docker Image로 만들어 줄 Dockerfile을 작성해줍니다. 프로젝트의 루트에 생성하면 됩니다. java 버전은 본인의 프로젝트에 맞게 설정해주면 되겠습니다.

.gitlab-ci.yml

GitLab CI/CD를 어떻게 동작시킬지 정의하는 파일입니다. 프로젝트 루트 폴더에 위치하면 됩니다. 이를 작성하기 이전에 앞서 .csv로 다운로드 받은 액세스 키를 설정해봅시다.

만드신 GitLab 레포지토리에 Settings - CI/CD - Variables에서 위와 같이 AWS_ACCESS_KEY_IDAWS_SECRET_ACCESSKEY를 하나씩 생성해줍니다. 값은 아까 다운로드 받은 .csv 파일에 있습니다.

services:
  - docker:stable-dind
stages:
  - build jar
  - build and push docker image
  - deploy
variables:
  APPLICATION_NAME: "01"
  TAG_NAME: "latest"
  DOCKER_IMAGE: "group-19180109/ci-cd-test"
build:
  image: openjdk:17-jdk-slim
  stage: build jar
  script:
    - chmod +x gradlew
    - ./gradlew clean build
  artifacts:
    paths:
      - build/libs/*.jar
docker build:
  image: docker:latest
  stage: build and push docker image
  rules:
    - if: $CI_COMMIT_BRANCH == "main" || $CI_COMMIT_REF_NAME == "main"
      variables:
        TAG_NAME: "latest"
    - if: $CI_COMMIT_BRANCH == "develop" || $CI_COMMIT_REF_NAME == "develop"
      variables:
        TAG_NAME: "develop"

  script:
    - apk add --update --no-cache curl py3-pip py3-virtualenv
    - python3 -m venv /tmp/venv
    - source /tmp/venv/bin/activate
    - pip install awscli
    - aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID
    - aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY
    - aws configure set region ap-northeast-2
    - docker build -t $DOCKER_IMAGE .
    - docker tag $DOCKER_IMAGE:latest 257394482388.dkr.ecr.ap-northeast-2.amazonaws.com/$DOCKER_IMAGE:$TAG_NAME
    - aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 257394482388.dkr.ecr.ap-northeast-2.amazonaws.com
    - docker push 257394482388.dkr.ecr.ap-northeast-2.amazonaws.com/$DOCKER_IMAGE:$TAG_NAME

deploy:
  image: python:3.9-slim
  stage: deploy
  script:
    - python3 -m venv /tmp/venv
    - source /tmp/venv/bin/activate
    - pip install awscli
    - aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID
    - aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY
    - aws configure set region ap-northeast-2
    - aws ecs update-service --cluster ci-cd-test-cluster --service ci-cd-test-service --task-definition ci-cd-test-task:1 --force-new-deployment

앞서 푸쉬 명령 보기에 있는 커매드를 기반으로 .gitlab-ci.yml를 작성했습니다. variables에 설정한 값들을 스크립트 내에서 재활용 할 수 있는데 DOCKER_IMAGE만 각자 설정한 ECR 레포지토리 이름으로 설정하면 됩니다.

  • docker tag $DOCKER_IMAGE:latest 257394482388.dkr.ecr.ap-northeast-2.amazonaws.com/$DOCKER_IMAGE:$TAG_NAME
  • aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin 257394482388.dkr.ecr.ap-northeast-2.amazonaws.com

위 두 줄 역시 본인의 푸쉬 명령과 비교하여 알맞게 설정해주면 됩니다.

커밋 & 푸시하기

코드를 커밋 푸시하면 GitLab CI/CD가 동작합니다.

GitLab 레포지토리의 Build - Pipelines에서 위와 같이 확인이 가능합니다.

profile
응애 개발자입니다.

0개의 댓글