[CI/CD] GitHub Actions ECS 구성하기
안녕하세요!
키크니 개발자 입니다. 🦒
회사에서 AWS ECS로 배포를 진행하고 있는데 하나하나 커맨드를 입력하면서 배포하기에는 너무 번거로워서
간편하게 배포하기 위해 Github Actions를 적용하였습니다.
GitHub Action 이란?
- github에서 제공하는 CI(Continuous Integration, 지속적 통합)/CD(Continuous Deployment, 지속적 배포) 서비스 입니다.
Github Action Core 개념
- 깃허브 액션을 이해하기 위해서 알아야 하는 개념은 workflow, event, job, step, action, runner 등이 있습니다.
- Workflow
- 여러 Job으로 구성되고, Event에 의해 트리거 될 수 있는 자동화 된 프로세스를 의미합니다.
- 깃허브 액션에서 최상위 개념으로 자동화 해놓은 작업 과정이라고 볼 수 있습니다.
- Workflow 파일은 YAML으로 작성되고, Github Repository의 .github/workflows 폴더 아래에 저장됩니다.
- name : workflow의 이름. 나중에 해당 값을 사용할 수 있기 때문에 저는 유니크하게 사용합니다.
- Event
- workflow를 trigger(실행)하는 특정 활동이나 규칙을 의미합니다.
- 예를 들어 다음과 같은 상황을 사용할 수 있음
- 특정 브랜치로 Push하거나
- 특정 브랜치로 Pull Request하거나
- 특정 시간대에 반복(Cron)
- Webhook을 사용해 외부 이벤트를 통해 실행
- 자세한 내용은 Events that trigger workflows 참고
- on : workflow를 동작하게 하는 trigger입니다.
- push(Branch or Tag), pull_request, schedule을 사용할 수 있음
- 단일 Event를 사용할 수도 있고, array로 작성할 수도 있음
on: push
# 또는
on: [pull_request, issues]
# 또는
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
- Job
- 깃허브액션에서 Job(작업)은 독립된 가상머신 또는 컨테이너에서 돌아가는 하나의 처리 단위를 의미합니다.
- 하나의 워크플로우는 여러 개의 작업(job)으로 구성되며 적어도 하나의 작업은 있어야 합니다.
- Job은 여러 Step으로 구성되고, 가상 환경의 인스턴스에서 실행됩니다.
- 다른 Job에 의존 관계를 가질 수 있고, 독립적으로 병렬 실행도 가능합니다.
- 모든 작업은 기본적으로 동시에 실행되며 필요시 작업간에 의존관계를 설정하여 작업이 실행되는 순서를 제어할 수 있습니다.
- 작업의 세부 내용으로는 여러 가지 내용을 명시할 수 있으며 필수로 들어가야 하는 runs-on속성을 통해 해당 리눅스나 윈도우즈와 같은 실행환경을 지정해줘야 합니다.
- 예를 들어, 가장 널리 사용되는 우분투의 최신 실행 환경에서 해당 작업을 실행하고 싶다면 다음과 같이 설정합니다.
- 아래 예시는 build라는 job을 생성하고, 그 아래에 2개의 step이 존재하는 구조
jobs:
job1:
# job1에 대한 세부 내용
job2:
# job2에 대한 세부 내용
job3:
# job3에 대한 세부 내용
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run a one-line script
run: echo Hello, world!
- name: Run a multi-line script
run: |
echo Add other actions to build,
echo test, and deploy your project.
- Step
- Task들의 집합으로, 커맨드를 날리거나 action을 실행할 수 있습니다.
- 깃허브 액션에서는 각 작업(Job)이 하나 이상의 단계(Step)로 모델링이 됩니다.
- 커맨드나 스크립트를 실행할 때는 run 속성을 사용하며, 액션을 사용할 때는 uses 속성을 사용합니다.
- 예를 들어 자바스크립트 프로젝트에서 테스트를 돌리려면 코드 저장소에 코드를 작업 실행 환경으로 내려 받고, 패키지를 설치한 후, 테스트 스크립트를 실행해야할텐데요. 이 3단계의 작업은 아래와 같이 steps 속성을 통해서 명시될 수 있을 것입니다.
- 워크플로우 파일 내에서 작업 단계를 명시해줄 때는 주의할 부분이 있는데요. YAML 문법에서 시퀀스(sequence) 타입을 사용하기 때문에 각 단계 앞에 반드시 - 를 붙여줘야 합니다.
- steps의 uses는 어떤 액션을 사용할지 지정함. 이미 만들어진 액션을 사용할 때 지정한다.
- runs-on은 어떤 OS에서 실행될지 지정한다.
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm install
- run: npm test
- Action
- Workflow의 가장 작은 블럭(smallest portable building block)
- Job을 만들기 위해 Step들을 연결할 수 있음
- 재사용이 가능한 컴포넌트
- 개인적으로 만든 Action을 사용할 수도 있고, Marketplace에 있는 공용 Action을 사용할 수도 있습니다.
- Runner
- Gitbub Action Runner 어플리케이션이 설치된 머신으로, Workflow가 실행될 인스턴스
- Github에서 호스팅해주는 Github-hosted runner와 직접 호스팅하는 Self-hosted runner로 나뉨
- Github-hosted runner는 Azure의 Standard_DS2_v2로 vCPU 2, 메모리 7GB, 임시 스토리지 14GB
Secret Key 저장하기
- 클라우드의 저장소에 데이터를 저장하거나, Dockerhub에 접근하는 등을 할 때 고유한 Key가 필요할 수 있습니다.
- 이런 경우 Secrets에 등록해서 사용할 수 있습니다.
- Github Access Token 생성하기
- Github Issue를 남기기 위해 Github Access Token이 필요함
- Settings - Developer settings - Personal access tokens - Generate new token 클릭
- 체크박스에 필요한 권한 체크. repo, workflow 설정 후 저장
- Value 복사하기
- Repository의 Settings > 왼쪽에 Secrets 클릭
- New secret 클릭하고 Name과 Value 입력하기
- Repository access 쪽으로 가면, access policy를 정할 수 있음
- workflow에서 사용할 땐 $ 으로 사용하고, python에선 os.getenv(변수 이름)으로 사용
- 더 자세한 내용은 Creating and storing encrypted secrets 참고Secret Key 등록하기
Workflow 정의하기
- Github Repo에서 Actions 클릭
- 깃허브액션을 적용할 레파지토리를 들어간 후 github action에서 ecs를 선택합니다.
- aws.yml 파일에서 ecr repository name, region, ecs container name을 수정해주고 repository setting tab에 secret에 secret 변수들을 설정해줍니다.
- 어디 브랜치에 커밋이 되었거나 Pr이 되었을 때 CI/CD가 작동할 수 있도록 브랜치 설정도 해줍니다.
GItHub Actions Yaml 예시
# This is a basic workflow to help you get started with Actions
name: Build Docker Image with bootBuildImage(Gradle) & Deploy to Amazon ECS
# Controls when the workflow will run
# release 브랜치로 pull_request가 올라오고, closed 되었을 때 실행
on:
pull_request:
branches:
- release
types: [closed]
env:
AWS_REGION: ECS_REGION # set this to your preferred AWS region
ECR_REPOSITORY: ECR_NAME # set this to your Amazon ECR repository name
ECS_SERVICE: SERVICE_NAME # set this to your Amazon ECS service name
ECS_CLUSTER: CLUSTER_NAME # set this to your Amazon ECS cluster name
ECS_TASK_DEFINITION: .aws/ecs/task-definition.json (TASK_DEFINITION_PATH) # set this to the path to your Amazon ECS task definition
# file, e.g. .aws/task-definition.json
CONTAINER_NAME: CONTAINER_NAME # set this to the name of the container in the
# containerDefinitions section of your task definition
# 컨텍스트 : 워크플로 및 작업에서 컨텍스트 정보에 액세스할 수 있습니다.
# 컨텍스트 정보 : 워크플로 실행, 실행자 환경, 작업 및 단계에 대한 정보에 엑세스 하는 방법입니다.
# 각 컨텍스트는 속성을 포함하는 개체이며 문자열 또는 기타 개체일 수 있습니다.
# 표현식 : ${{ <context> }}
# ${{ github.sha }} : 워크플로우를 트리거한 commit SHA입니다. 워크플로우를 트리거한 이벤트에 따라 다릅니다. (일종의 중복이 없는 임의의 문자열 이라고 생각하시면 됩니다.)
# 버전을 따로 관리하기위해 latest가 아닌 임의의 string을 설정합니다.
IMAGE_TAG: ${{ github.sha }}
IMAGE_NAME: DOCKER_IMAGE_NAME
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
deploy:
name: Deploy
# 만약 pull_request 가 merged 되었을 경우 아래의 steps들을 실행한다.
if: ${{ github.event.pull_request.merged }}
runs-on: ubuntu-latest
environment: prod
steps:
# Checkout : GitHub Actions는 해당 프로젝트를 리눅스 환경에 Checkout 하고 나서 실행합니다. (브랜치 만들때 checkout 하는 것이라고 생각하면 됩니다, 저장소(리포지토리)에서 파일을 받아오는 것)
- name: Checkout
# uses : 누군가 만들어놓은 action을 사용할 때 표기합니다.
uses: actions/checkout@v2
- name: Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'adopt'
- name: Grant execute permission for gradlew
# chmod +x : 접근 권한 변경 / +x : 모든 사용자(소유자, 그룹, 기타사용자)에게 실행 권한 추가 (chmod +x gradlew : gradlew에 실행 권한 부여)
run: chmod +x gradlew
- name: build docker
id: build-image
run: ./gradlew clean build bootBuildImage --imageName=${{env.IMAGE_NAME}}:${{ env.IMAGE_TAG }} -P profile=prod
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
# secrets.XXXX : Github repository에서 setting -> Secrets에서 설정한 key를 사용합니다.
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: tag, and push image to Amazon ECR
id: tag-and-push-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
run: |
docker tag $ECR_REPOSITORY:${{ env.IMAGE_TAG }} $ECR_REGISTRY/$ECR_REPOSITORY:${{ env.IMAGE_TAG }}
docker push $ECR_REGISTRY/$ECR_REPOSITORY:${{ env.IMAGE_TAG }}
# echo 명령어 : 유닉스 혹은 리눅스 운영체제에서 지정한 문자열 또는 텍스트를 터미널에 출력하는 명령어입니다.
# 출력 변수의 값을 쓰려면 ::set-output name={name}::{value} 문법을 사용해야 합니다.
# 출력 변수의 값을 읽으려면 GitHub Actions의 문맥인 steps.<step_id>.outputs.<output_name> 문법을 사용해야 합니다.
echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:${{ env.IMAGE_TAG }}"
- 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.tag-and-push-image.outputs.image }}
# ECS task definition을 새로 배포합니다. 배포 후 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: ${{ env.ECS_SERVICE }}
cluster: ${{ env.ECS_CLUSTER }}
wait-for-service-stability: true
위의 yml파일을 프로젝트의 루트 경로 기준으로 /.github/workflows 안에 위 스크립트 yml을 위치시켜줍니다.
References
https://fe-developers.kakaoent.com/2022/220106-github-actions/
https://roseline.oopy.io/dev/github-action-cahce
https://zzsza.github.io/development/2020/06/06/github-action/
https://www.daleseo.com/github-actions-basics/
https://insight-bgh.tistory.com/473
https://velog.io/@rudwnd33/zero-downtime-deployment
https://www.daleseo.com/github-actions-steps/
https://docs.aws.amazon.com/ko_kr/AmazonECS/latest/developerguide/task_definition_parameters.html
https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request
https://medium.com/prnd/앱-배포후-jira에서-버전-release처리-자동으로-하는-방법-feat-github-action-ab4c4ecf437d
https://jojoldu.tistory.com/668
https://www.daleseo.com/github-actions-steps/