Profile picture

[Github Actions] ECR 이미지 배포 자동화

JaehyoJJAng2023년 04월 22일

ECR


ECR은 아마존에서 관리하는 이미지 등록 및 관리 서비스이다.
Private 레포지터리 및 IAM 권한 기반으로 이미지를 관리할 수 있다.
https://docs.aws.amazon.com/ko_kr/AmazonECR/latest/userguide/what-is-ecr.html


이미지 배포 자동화

Github Actions를 사용하여 AWS의 ECR 리소스에 도커 이미지를 자동으로 배포하는 작업을 진행해보자.


1. IAM 계정 생성

먼저 IAM 계정에 ECR 권한을 추가해줘야 한다.
IAM 계정 만드는 과정은 [AWS] IAM를 참고하도록 하자.


1. 정책 추가에서 AmazonEC2ContainerRegistryFullAccess 권한을 추가한다.
image


권한 생성 후 이미지를 올릴 ECR에서 레포지토리를 생성해줘야 한다. ECR에서 레포지토리를 생성하는 방법에는 2가지 있는데

  • AWS ECR 플랫폼 페이지에서 직접 생성한다.
  • AWS CLI를 설치하여 명령어로 생성한다.

오늘 두 가지 방법 모두 다뤄볼 것이다.


1-1 ECR 페이지에서 생성하기

1. https://aws.amazon.com/ko/ecr/ ECR 페이지에 접속하자.
image
화면 우측의 레포지토리 생성을 클릭해주자.


2. 프라이빗 레포와 퍼블릭 레포 설정이 있는데 비공개로 사용할 것이기에 프라이빗을 선택해주도록 한다.
image
레포지토리 이름은 배포할 도커 이미지에 맞는 적당한 이름을 지어주도록 하자.


3. 레포지토리 생성 완료
image
image
레포지토리를 생성하고나서 우측 상단에 푸시 명령 보기를 클릭하면 이미지를 바로 업로드할 수 있는 명령어들이 나온다.
여기서 이걸 따라하여 바로 도커 이미지를 업로드할 수도 있지만 나는 Github Actions를 사용하여 ECR 업로드 기능을 자동화할 것이다.


1-2 AWS CLI로 생성하기

  • 설치 환경: CentOS 7

AWS CLI를 사용하기 위해서는 AWS CLI를 설치해줘야 한다.
설치를 하는 자세한 방법은 리눅스에 AWS CLI 설치하기를 참고하도록 하자.


0. 도커 설치하기
[Docker] 도커 설치하기 - Install Docker [CentOS7] 포스트 참고하기


1. AWS Configure 설정하기
위에서 생성한 IAM 계정의 Access Key IDSecret Access Key를 aws configure에 설정해줘야 한다.

$ aws configure
AWS Access Key ID [None]: AKIxxxxxxxxxxxx
AWS Secret Access Key [None]: VyQ+xxxxxxxxxxxxxxxxxxx
Default region name [None]: ap-northeast-2
Default output format [None]: json

2. 기본 레지스트리 인증하기

AWS CLI를 설치 및 구성했으면, 기본 레지스트리에 대해 Docker CLI를 인증합니다. 이렇게 하면 docker 명령이 Amazon ECR을 사용하여 이미지를 푸시하고 가져올 수 있습니다. AWS CLI는 인증 절차를 간소화하는 get-login-password 명령을 제공합니다.

이 get-login-password는 AWS CLI을(를) 사용 시 Amazon ECR 프라이빗 레지스트리에 인증하는 데 선호되는 방법입니다. AWS와 상호 작용하기 위해 AWS CLI을(를) 구성했는지 확인합니다. 자세한 내용은 AWS Command Line Interface사용 설명서의 AWS CLI구성 기초 섹션을 참조하세요.

Amazon ECR 인증 토큰을 docker login 명령에 전달할 때 사용자 이름으로 AWS 값을 사용하고, 인증하려는 Amazon ECR 레지스트리 URI를 지정합니다. 여러 레지스트리에 대해 인증하는 경우 각 레지스트리에 대해 명령을 반복해야 합니다.

🔺 중요

오류가 발생하거나 get-login-password 명령을 사용할 수 없는 경우 최신 버전의 AWS CLI를 사용 중인지 확인하세요. AWS CLI를 설치하거나 최신 버전으로 업그레이드하는 방법에 대한 자세한 내용은 AWS Command Line Interface 사용 설명서의 AWS Command Line Interface 설치를 참조하세요.


get-login-password (AWS CLI)

$ aws ecr get-login-password --region <region-name> \
| docker login --username AWS --password-stdin <aws_account_id>.dkr.ecr.<region-name>.amazonaws.com
$ aws ecr get-login-password --region ap-northeast-2 \
| docker login --username AWS --password-stdin 795748368257.dkr.ecr.ap-northeast-2.amazonaws.com

WARNING! Your password will be stored unencrypted in /home/jaehyo/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

3. 레포지토리 생성하기

Amazon ECR에 푸시할 이미지가 준비되었으면 이를 보유할 리포지토리를 생성해야 합니다. 이 예에서는 hello-repository라는 리포지토리를 생성합니다. 나중에 이 리포지토리에 hello-world:latest 이미지를 푸시하게 됩니다. 리포지토리를 생성하려면 다음 명령을 실행합니다.

$ aws ecr create-repository \
    --repository-name <생성할 레포지토리 이름> \
    --image-scanning-configuration scanOnPush=true \
    --region <Region Name>

나의 경우 아래처럼 작성하였다.

$ aws ecr create-repository \
    --repository-name ecr-test \
    --image-scanning-configuration scanOnPush=true \
    --region ap-northeast-2
{
    "repository": {
        "repositoryArn": "arn:aws:ecr:ap-northeast-2:795748368257:repository/ecr-test",
        "registryId": "795748368257",
        "repositoryName": "ecr-test",
        "repositoryUri": "795748368257.dkr.ecr.ap-northeast-2.amazonaws.com/ecr-test",
        "createdAt": "2023-10-18T14:36:50+09:00",
        "imageTagMutability": "MUTABLE",
        "imageScanningConfiguration": {
            "scanOnPush": true
        },
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        }
    }
}

4. 정상적으로 생성되었는지 확인해보자.
(aws 계정 내의 ECR 레포지토리 나열)

# 모든 ECR 레포지토리 나열
$ aws ecr describe-repositories
{
    "repositories": [
        {
            "repositoryArn": "arn:aws:ecr:ap-northeast-2:795748368257:repository/ecr-test",
            "registryId": "795748368257",
            "repositoryName": "ecr-test",
            "repositoryUri": "795748368257.dkr.ecr.ap-northeast-2.amazonaws.com/ecr-test",
            "createdAt": "2023-10-18T14:36:50+09:00",
            "imageTagMutability": "MUTABLE",
            "imageScanningConfiguration": {
                "scanOnPush": true
            },
            "encryptionConfiguration": {
                "encryptionType": "AES256"
            }
        }
    ]
}

2. Github 환경변수 설정

image
본인 깃허브 프로젝트 - Settings - Secrets and variables - Actions 에서 Repository Secret 생성


3. 배포 프로젝트 설정

파이썬 웹 프레임워크인 FastAPI 기반으로 작성된 간단한 프로젝트를 배포할 것이다.


1. 프로젝트 구조

$ tree -L 2 .
.
├── Dockerfile
├── requirements
│   └── requirements.txt
└── server.py

2. server.py

from fastapi import FastAPI
import socket


app : FastAPI = FastAPI()

@app.get('/hostname')
def get_hostname() -> dict[str,str]:
    hostname = socket.gethostname()
    return {'hostname': hostname}

서버의 호스트네임을 리턴해주는 간단한 코드이다.


4. workflow 작성

배포를 위한 Github Actions workflow를 작성해보도록 하자.

.github/workflows/deploy.yaml

name: build fastapi project

on:
  workflow_dispatch:
  # push:
  #   branches:
  #     - main
  #   pull_request:
  #     - main
jobs:
  fastapi:
    name: Build fastapi project image to ECR
    runs-on: ubuntu-latest
    steps:
      - name: "1. github runner's repository checkout"
        uses: actions/checkout@v3

      # 이미지 태그에 시간 설정을 하기 위해 현재 시간 가져오기
      - name: "2. Get Seoul current time"
        uses: 1466587594/get-current-time@v2 
        id: current-time
        with:
          format: YYYY-MM-DDTHH-mm-ss
          utcOffset: "+09:00"

      - name: "3. Show current time"
        run: echo "CurrentTime=${{ steps.current-time.outputs.formattedTime }}"
      
      - name: "4. 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: ap-northeast-2

      - name: "5. Login to Amazon ECR"
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1

      - name: "6. Build, tag, and push image to Amazon ECR"
        env:
          ECR_REPO: "ecr-test"
          IAM_ID: "795748368257" # 해당 값은 비공개 처리되어야 함. 깃허브 환경변수에 등록하는 것을 추천.
        run: |
          docker build --tag app:${{ steps.current-time.outputs.formattedTime}} ./apps
          docker tag app:${{ steps.current-time.outputs.formattedTime}} ${{ env.IAM_ID}}.dkr.ecr.ap-northeast-2.amazonaws.com/${{ env.ECR_REPO }}:${{ steps.current-time.outputs.formattedTime }}
          docker push ${{ env.IAM_ID }}.dkr.ecr.ap-northeast-2.amazonaws.com/${{ env.ECR_REPO }}:${{ steps.current-time.outputs.formattedTime }}

5. 배포 결과 확인

정상적으로 배포가 되었는지 ECR 레포지토리 이미지 목록을 조회해보자. AWS CLI로 조회해볼 것이다.

# 특정 ECR 레포지토리의 이미지 목록 조회
$ aws ecr list-images --repository-name ecr-test
{
    "imageIds": [
        {
            "imageDigest": "sha256:22117f178da3a29bfbda1591d2045bb80326a97fb348a39681412a477008a150",
            "imageTag": "2023-10-18T15-46-59"
        }
    ]
}

이미지 태그가 current time으로 태깅된 것 보이는가? 아주 정상적으로 배포가 완료되었다!.


Clean Up

이제 배포했던 이미지와 레포지토리를 AWS CLI 상에서 삭제해볼 것이다.


1. 이미지 삭제

리포지토리 중 하나에 있는 이미지가 더 이상 필요하지 않거나 저장해 두기 싫은 경우 batch-delete-image 명령을 사용하여 이를 삭제할 수 있습니다. 이미지를 삭제하려면 이미지가 들어 있는 리포지토리 및 이미지의 imageTag 또는 imageDigest 값을 지정해야 합니다. 다음은 이미지 태그 hello-repository를 사용하여 latest 리포지토리에 있는 이미지를 삭제하는 예제입니다.

$ aws ecr batch-delete-image \
--repository-name ecr-test \
--image-ids imageTag=2023-10-18T15-46-59 \
--region ap-northeast-2
{
    "imageIds": [
        {
            "imageDigest": "sha256:22117f178da3a29bfbda1591d2045bb80326a97fb348a39681412a477008a150",
            "imageTag": "2023-10-18T15-46-59"
        }
    ],
    "failures": []
}

2. 레포지토리 삭제

이미지의 전체 리포지토리가 더 이상 필요하지 않거나 저장해 두고 싶지 않으면 리포지토리를 삭제하면 됩니다. 기본적으로, 이미지가 들어 있는 리포지토리는 삭제할 수 없지만, --force 플래그를 사용하면 가능합니다. 이미지가 들어 있는 리포지토리(및 리포지토리 안에 있는 모든 이미지)를 삭제하려면 다음 명령을 실행합니다.

$ aws ecr delete-repository \
      --repository-name ecr-test \
      --force \
      --region ap-northeast-2
{
    "repository": {
        "repositoryArn": "arn:aws:ecr:ap-northeast-2:795748368257:repository/ecr-test",
        "registryId": "795748368257",
        "repositoryName": "ecr-test",
        "repositoryUri": "795748368257.dkr.ecr.ap-northeast-2.amazonaws.com/ecr-test",
        "createdAt": "2023-10-18T14:36:50+09:00",
        "imageTagMutability": "MUTABLE"
    }
}

Loading script...