티스토리 뷰

개요

기존 서비스에서는 EKS + ArgoCD를 이용한 GitOps를 구축해놨었다. 그런데, 새로운 프로젝트에서는 ECS를 쓰면서 CI/CD를 아예 갈아치워야 하는 상황이 됐다. ECS 환경에서도 ArgoCD를 할 수 있다고는 하는데... 하는 방법이 구체적으로 나와있지 않았다.

 

ArgoCD 메인테이너가 해준 설명 : https://github.com/argoproj/argo-cd/discussions/17843

 

어떻게해야하나 찾아보니까... GitHub Actions에서 ECS용 워크플로우를 만들어놔서 ArgoCD보다 더 쉽게 CI/CD를 구축할 수 있었다. 원리는 Task Definition에 명시해둔 이미지 이름을 변경하고 Task를 재실행시켜서 재배포하는 방식이다. 

 

준비물은 Task Definition을 명시해둔 json 파일만 있으면 되고, GitHub Actions Workflow를 작성하면 된다.

 

전체적인 흐름은 다음과 같다.

 

GitHub Actions Workflow

불필요한건 다 쳐냈다.

jobs:
  deploy-worker:
    runs-on:
      - ubuntu-latest

    steps:
      - name: Checkout source code
        uses: actions/checkout@v4

      - name: Set BUILD_ENV
        run: |
            echo "BUILD_ENV=dev" >> $GITHUB_ENV

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1
        with:
          registries: {{secrets.AWS_REGISTRY}}

      - name: Build and Push Docker Image
        run: |
          chmod +x gradlew
          ./gradlew jib -Djib.to.tags=${BUILD_ENV},${BUILD_ENV}-${{ github.sha }}

      - 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: backend-task-definition.json
          container-name: my-app-backend
          environment-variables: SPRING_PROFILES_ACTIVE=dev
          image: ${{ steps.login-ecr.outputs.registry }}/my-app-backend:${{ env.BUILD_ENV }}-${{ github.sha }}

      - 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: my-app-backend-service
          cluster: my-app-cluster
          wait-for-service-stability: false

AWS ECR 로그인 후, ECR에 이미지를 푸시해줘야하는데 이 방법은 Build and Push는 JIB을 이용했다.

JIB을 이용한 gradle 설정 방법은 다음 글을 확인해보자 : GitHub Actions 으로 스프링부트 CI/CD 구축하기 - 2. JIB

 

자세히 봐야할 부분은 aws-actions/amazon-ecs-render-task-definition@v1aws-actions/amazon-ecs-deploy-task-definition@v1 이 두 가지이다. Workflow의 이름이 모든걸 설명해준다.

 

Fill in the new image ID in the Amazon ECS task definition.

- 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: backend-task-definition.json
    container-name: my-app-backend
    environment-variables: SPRING_PROFILES_ACTIVE=dev
    image: ${{ steps.login-ecr.outputs.registry }}/my-app-backend:${{ env.BUILD_ENV }}-${{ github.sha }}

말 그대로 task definition을 현재 상황에 맞게 재작성하는 과정이다. 워크플로 오리진 : https://github.com/aws-actions/amazon-ecs-render-task-definition

 

task-definition이 json파일의 경로인데, 이번 예시에는 메인 폴더 아래에 뒀다.

 

예시로 든 것 외에도 여러 작성 방법이 있다.

// task-definition 말고도 여러 옵션이 있다.
task-definition-arn: task-definition-arn
task-definition-family: task-definition-family-name 
task-definition-revision: task-definition-revision

// 다중 옵션은 그냥 줄바꿔서 넣어 주면 됨
environment-variables: |
    SPRING_PROFILES_ACTIVE=dev
    APP_ENV=${{ env.BUILD_ENV }}
    LOG_LEVEL=info
    FEATURE_FLAG=true

Deploy Amazon ECS task definition.

- 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: my-app-backend-service
    cluster: my-app-cluster
    wait-for-service-stability: false

변경한 task definition을 ECS에 배포하는 과정이다. 여기서 EBS 등 여러 옵션들을 설정할 수 있으니 확인해 보면 좋다.

워크플로 오리진 : https://github.com/aws-actions/amazon-ecs-deploy-task-definition

 

여기까지 진행했으면 두 가지를 더해줘야한다. 하나는 GitHub Actions VM에게 AWS 리소스 사용 권한을 줘야하고(GitHub Actions 용 IAM 유저를 등록하면 편함), 두번째는 이 유저에게 Task definition 수정 권한을 줘야 한다. 이 내용은 워크플로 오리진 경로 Permission에 자세히 설명 되어있다.

Task-definition.json

{
    "family": "my-app-backend-task",
    "networkMode": "awsvpc",
    "containerDefinitions": [
        {
            "name": "my-app-backend",
            "image": "301591718339.dkr.ecr.ap-northeast-2.amazonaws.com/my-app-backend:latest",
            "cpu": 512,
            "memory": 1024,
            "essential": true,
            "portMappings": [
                {
                    "containerPort": 8080,
                    "hostPort": 8080,
                    "protocol": "tcp"
                }
            ],
            "environment": [
                {
                    "name": "SPRING_PROFILES_ACTIVE",
                    "value": "dev"
                }
            ]
        }
    ],
    "requiresCompatibilities": ["FARGATE"],
    "cpu": "512",
    "memory": "1024"
}

테스크 데피니션에는 별 내용이 없다. 사실상 워크플로에서 데이터를 대부분 다 넣어주기 때문에 디폴트 설정값들만 들고 있다고 보면된다. 경우에 따라서 taskRoleArn, executionRoleArn을 명시해 줄 수도 있으나, json 파일에 작성하는 것보다 GitHub Secret에 보관하고 workflow에서 작성해주는게 좋다.

 

마치며

CI/CD에 대한 기본 개념이 있으면, 생각보다 오래걸리진 않을 작업이다.

 

긔고 ECS를 조금 써보면서 느낀게, 설정하긴 쉬우나 EKS 만큼 새로운 컨테이너를 빠르게 만들고 삭제가 가능하지가 않다. 복잡성과 유연성은 늘 함께 가는 것 같다고 다시한번 느끼게 됐다.

 

그리고 설정 과정이 뭔가를 빼먹은 것 같은데, 기억나는대로 수정해야겠다...

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함