devops

Git push시 ECS를 통해 자동으로 서버 배포해보기

하리하링웹 2024. 6. 16. 21:19

Github Repository에 서버 코드를 push했을 때 자동으로 ECS를 통해 서버 코드가 배포되는 실습을 진행할것이다.

 

이 글로 실습하기 전에 아래 글을 참고하면 좋다.

https://jjongsk.tistory.com/entry/Docker이미지를-ECS를-통해-배포해보기

1. Git Repository 생성 및 설정

github repository를 생성해준뒤 이름, public, private 유무는 편한대로 설정한다.

 

repository 생성이 완료되었으면 서버 코드를 push해준다. 서버 코드 설정은 아래 링크를 참고하자

https://jjongsk.tistory.com/entry/Docker이미지를-ECS를-통해-배포해보기

이제 ECS 배포를 위한 AWS env를 설정할 차례이다.

 

repository의 settings > secrets and variables > actions로 이동해준 뒤 아래와 같이 본인의 aws key, secret을 추가해준다.

 

이 때 위 이미지에서 보이는것처럼 Secrets와 Variables가 있는데 이는 엄연히 다른것이니 반드시 Secrets탭의 new repository secret을 사용해 추가해주자.

 

variables를 사용할경우 키가 외부에 노출될 위험이 존재하게된다.

 

위의 이미지처럼 env를 추가해주자

 

이제 github 설정은 완료되었다.

 

2. aws iam 권한 설정하기

이제 ecs 설정을 위해 iam 유저에 ecs 접근 권한을 추가해줘야한다.

 

먼저 관리자 권한이 있는 aws 계정으로 로그인해주자, 관리자 키를 사용하고 있다면 이 과정은 생략해도 된다.

우측 상단의 계정 설정에서 Security credentials로 이동해준다.

 

이후 좌측 사이드바에서 Access management > Users탭으로 이동해준다.

 

 

github env에 추가한 key, secret과 일치하는 유저를 클릭하여 유저 관리 콘솔로 들어간다.

 

이후 permissions policies 탭에서 우측 상단 Add permissions > Add permissions 버튼을 클릭한다.

 

 

Attatch policies directly 탭으로 이동한 뒤 ecs를 검색하여 AmazonECS_FullAccess를 체크한 뒤 next버튼을 눌러 권한을 부여해준다.

 

 

성공적으로 권한이 부여되었다면 아래와 같이 해당 권한이 추가되어 있는 모습을 확인할 수 있다.

 

 

이제 권한 설정은 완료되었다.

 

3. 프로젝트에 Task definition 파일 생성해주기

이제 ecs에서 task를 어떤 방식으로 배포할지를 정의해주는 파일인 task-definition 파일을 프로젝트에 추가해줘야한다.

 

먼저 ecs의 task deifinition 탭으로 이동해준뒤 본인이 생성해놓은 task definition을 클릭하여 콘솔창으로 이동하자

콘솔창으로 이동하면 아래와 같은 탭이 보일것이다.

 

 

위 이미지처럼 JSON 탭으로 이동한 뒤 아래의 json 텍스트를 복사한 뒤 프로젝트의 루트에 task-definition.json 파일을 만들어 복사한 json 텍스트를 추가해준다.

 

이전 실습에서 platform을 arm64로 설정했는데 여기서는 linux/amd64로 설정할 예정이니 값을 바꿔줘야한다.

 

task-definition.json 파일에서 runtimePlatform 값을 아래와 같이 변경해주자.

"runtimePlatform": {
    "cpuArchitecture": "X86_64",
    "operatingSystemFamily": "LINUX"
  },

4. git action 추가하기

이제 git에 push 시 ecs를 사용해 자동으로 배포하게 하는 프로세스를 git action을 사용하여 만들어주자.

 

먼저 github respository로 들어가 actions 탭으로 이동한다.

 

 

deployment의 Deploy to Amazon ECS 를 찾아 configure 버튼을 클릭한다.

 

 

이후 commit changes를 눌러 git aciton 설정 파일을 repository에 푸쉬한 뒤 프로젝트에서 해당 commit을 pull해준다.

 

정상적으로 위의 과정을 완료했다면 아래 이미지와 같은 구조가 되어있을것이다.

 

 

5. git action 설정파일 변경

파일을 받은 뒤 aws.yml 파일을 열어보면 아래와 같이 구성되어 있을것이다. 먼저 각 설정을 확인해보자.

name: Deploy to Amazon ECS

on:
  push:
    branches: [ "main" ]

env:
  AWS_REGION: MY_AWS_REGION                   # set this to your preferred AWS region, e.g. us-west-1
  ECR_REPOSITORY: MY_ECR_REPOSITORY           # set this to your Amazon ECR repository name
  ECS_SERVICE: MY_ECS_SERVICE                 # set this to your Amazon ECS service name
  ECS_CLUSTER: MY_ECS_CLUSTER                 # set this to your Amazon ECS cluster name
  ECS_TASK_DEFINITION: MY_ECS_TASK_DEFINITION # set this to the path to your Amazon ECS task definition
                                               # file, e.g. .aws/task-definition.json
  CONTAINER_NAME: MY_CONTAINER_NAME           # 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@v4

    - 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

name 및 on

  • name: Deploy to Amazon ECS: 현재 워크플로우의 이름을 설정해준다.
  • on: push: branches: [ "main" ]: 메인 브랜치에 푸시할 때마다 실행된다. 여기선 연습이니 main 브랜치에 푸쉬되면 동작하도록 한다.

env

workflow에서 사용할 환경변수이다.

  • AWS_REGION: AWS 리전 (예: us-west-1)
  • ECR_REPOSITORY: Amazon ECR 저장소 이름
  • ECS_SERVICE: Amazon ECS 서비스 이름
  • ECS_CLUSTER: Amazon ECS 클러스터 이름
  • ECS_TASK_DEFINITION: Amazon ECS 태스크 정의 파일 경로 (예: .aws/task-definition.json)
  • CONTAINER_NAME: 태스크 정의의 containerDefinitions 섹션에 있는 컨테이너 이름

permissions

  • contents: read: 해당 workflow의 repository 콘텐츠 권한, 여기서는 읽기만 허용

jobs

  • deploy
    • name: Deploy: 작업의 이름
    • runs-on: ubuntu-latest: 최신 우분투 버전에서 실행
    • environment: production: 작업의 실행 환경, 여기서는 production 환경에서 실행

steps

  1. Checkout
    • name: Checkout
    • uses: actions/checkout@v4: workflow 내에서 repository의 코드에 접근할 수 있도록 한다.
  2. Configure AWS credentials
    • name: Configure AWS credentials
    • uses: aws-actions/configure-aws-credentials@v1
    • with 섹션에서 AWS 자격 증명을 구성한다:
      • **aws-access-key-id**와 **aws-secret-access-key**는 GitHub Secrets에 저장된 AWS 자격 증명을 사용한다.
      • **aws-region**은 환경 변수에서 가져온다.
  3. Login to Amazon ECR
    • name: Login to Amazon ECR
    • id: login-ecr
    • uses: aws-actions/amazon-ecr-login@v1: Amazon ECR에 로그인한다.
  4. Build, tag, and push image to Amazon ECR
    • name: Build, tag, and push image to Amazon ECR
    • id: build-image
    • 환경 변수를 설정하고 Docker 이미지를 빌드하고 ECR에 푸시한다:
      • **IMAGE_TAG**는 현재 GitHub 커밋 SHA이다.
    • run 섹션에서 Docker 명령어를 실행하여 이미지를 빌드하고 푸시한다.
  5. 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
    • 빌드한 이미지를 사용해 최종적으로 ECS task definition을 만들어준다. 이를 통해 다음 스텝에서 사용할 수 있다.
  6. Deploy Amazon ECS task definition
    • name: Deploy Amazon ECS task definition
    • uses: aws-actions/amazon-ecs-deploy-task-definition@v1
    • task-definition, service, 및 cluster 값을 설정한 뒤 ECS에 배포한다.
    • wait-for-service-stability: true: 서비스가 정상적으로 배포될 때까지 작업을 종료하지 않고 기다린다.

이제 aws.yml 파일을 클릭하여 환경변수를 설정해준다. 자신의 AWS 설정에 맞게 설정해야하며 하드코딩하기 보다는 git action에 env 형태로 주입시켜주는게 이상적이지만 여기서는 연습이니 하드코딩하여 진행한다.

 

아래는 설정파일 최종 결과물이다.

name: Deploy to Amazon ECS

on:
  push:
    branches: ["main"]

env:
  AWS_REGION: ap-northeast-2
  ECR_REPOSITORY: fastify-ecr-prac
  ECS_SERVICE: fastify-ecs-prac-service
  ECS_CLUSTER: fastify-ecs-prac-cluster
  ECS_TASK_DEFINITION: task-definition.json
  CONTAINER_NAME: fastify-ecs-prac-container

permissions:
  contents: read

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    environment: production

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

      - 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

6. 확인

이제 설정은 완료되었다. 잘 적용되었나 확인을 위해 코드를 변경하여 푸쉬해보자.

 

 

코드를 푸쉬하면 아래 이미지와 같이 repository의 action 탭에서 현재 진행 상황을 확인할 수 있다. 혹시 에러가 발생했다면 ecs의 콘솔과 actions의 로그로 잘 찾아서 해결해보자.

 

ecs 배포까지 시간이 좀 걸리니 잠시 기다린 뒤 확인하면 아래 이미지처럼 체크 표시가 되어 배포가 성공적으로 이루어진것을 확인할 수 있다.

 

 

배포가 잘 되었는지 확인을 위해 ec2의 로드밸런서 탭에서 해당되는 로드밸런서의 콘솔 창으로 이동하여 dns를 통해 접속해보자.

배포가 정상적으로 되어 아래와 같이 잘 출력되는것을 확인할 수 있다.