프로젝트의 dev branch에 CI/CD를 적용하는 내용입니다. (오래 걸렸습니다...)
사용 기술
github actions를 사용하여 CI/CD를 구축합니다.
prod와 dev server 용 CI/CD를 구분하여 구축해야 합니다.
※ workflows에 관한 작업을 할 수 있기 위해서는 해당 권한이 필요합니다. github에 push 명령 시 권한 문제로 에러가 발생할 수 있습니다.
※ public이 아닌 repo는 github actions등의 서비스를 이용할 때마다 비용이 발생할 수 있습니다. 일정 양에 대해서는 무료사용이 가능한 내용도 있으니, 사전에 확인을 해야 합니다.
🫱🏻🫲🏻GitHub Actions 요금 청구 정보 - github docs
참고 사이트 :
제발 깃허브 액션🔥 모르는 개발자 없게해 주세요 🙏 - 드림코딩
Github Actions를 이용한 CI 구축하기(Prettier, ESLint, TSC) - velog
github actinos에서 공식으로 제공하는 Node.js CI workflow를 사용합니다.
# ci.yml
name: Node.js CI
on:
pull_request:
branches: [ "develop" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Use Node.js 18.x
uses: actions/setup-node@v3
with:
node-version: 18.x
cache: 'npm'
- run: npm ci
- run: npm run format
- run: npm run lint
- run: npm run tsc
CI에서 진행할 명령어를 명시합니다. 우리 프로젝트는 prettier, lint, tsc를 확인하도록 했습니다.
테스트 코드는 다음 개발 페이즈에서 작업 예정으로 미포함입니다.
위 코드와 같이 설정하면, feature branch -> develop branch PR 요청시에 CI를 진행하게 됩니다.
github actions에서 공식으로 제공하는 Deploy to Amazon ECS CD workflow를 사용합니다.
# aws.yml
name: Deploy to Amazon ECS
on:
pull_request:
branches:
- develop
types:
- closed
feature branch -> develop branch PR 요청후 merge하면 진행하도록 조건을 넣었습니다. jobs 하위 if구문을 참조합니다. if: github.event.pull_request.merged
env:
AWS_REGION: ap-northeast-2 # set this to your preferred AWS region, e.g. us-west-1
ECR_REPOSITORY: 리포지토리 이름 # set this to your Amazon ECR repository name
ECS_SERVICE: 서비스 이름 # set this to your Amazon ECS service name
ECS_CLUSTER: 클러스터 이름 # set this to your Amazon ECS cluster name
ECS_TASK_FAMILY: 태스크 정의 패밀리 이름
# 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: 컨테이너 이름 # set this to the name of the container in the
# containerDefinitions section of your task definition
AWS ECS에 설정된 값들을 알맞게 명시해 줍니다. ECS_TASK_DEFINITION
은 사용하지 않았습니다. aws ecs
명령어를 사용해 aws에 직접 접근해 가장 최근 task definition을 json 형식으로 가져오도록 설정했습니다. (아래의 jobs 설명에서 참고)
jobs:
deploy:
if: github.event.pull_request.merged
name: Deploy
runs-on: ubuntu-latest
environment: development
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Create .env file
run: echo "${{ secrets.DEV_ENV_FILE }}" > .env
secrets.
로 시작하는 변수는 github secrets 이라는 재사용 가능한 변수를 사용하는 구문입니다. secrets
와 variables
두 종류가 있으며, secrets는 암호화 되기 때문에 민감한 정보에 적합 합니다. - 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 }}
run: |
# Build a docker container and
# push it to ECR so that it can
# be deployed to ECS.
docker build -t ${{ env.ECR_REPOSITORY }} .
timestamp=$(date -d '9 hours' '+%y%m%d-%H%M%S')
echo $timestamp
docker tag ${{ env.ECR_REPOSITORY }}:latest $ECR_REGISTRY/${{ env.ECR_REPOSITORY }}:latest
docker tag ${{ env.ECR_REPOSITORY }}:latest $ECR_REGISTRY/${{ env.ECR_REPOSITORY }}:$timestamp
docker push $ECR_REGISTRY/${{ env.ECR_REPOSITORY }}:$timestamp
echo "::set-output name=image::$ECR_REGISTRY/${{ env.ECR_REPOSITORY }}:$timestamp"
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
steps 중 하나인 login-ecr의 output registry를 ECR_REGISTRY 변수에 담아 사용합니다. - name: Retrieve most recent ECS task definition JSON file
id: retrieve-task-def
run: |
aws ecs describe-task-definition --task-definition ${{ env.ECS_TASK_FAMILY }} --query taskDefinition > task-definition.json
cat task-definition.json
echo "::set-output name=task-def-file::task-definition.json"
- 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: ${{ steps.retrieve-task-def.outputs.task-def-file }}
container-name: ${{ env.CONTAINER_NAME }}
image: ${{ steps.build-image.outputs.image }}
빌드한 이미지와 가장 최신 ECS 태스크 정의 json file을 사용하여 AWS ECS의 새 개정 생성
과 동일한 작업을 진행합니다.
- 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
github actions만 사용하여 프로젝트의 develop branch에 CI/CD를 구축해 보았습니다.
github actions에서 편리한 기능을 잘 제공하고 있다고 느꼈습니다. 아직은 필요성을 못느껴(뭐가 있는지 몰라) terraform, AWS CodePipeline, AWS CodeBuild, AWS Elastic Beanstalk... 등 다른 편의 기능 및 서비스는 적용하지 않았습니다만, 실제 사용 하다보면 예상치 못한 현상이 발생해 보완 기능을 추가해야 할 수 있을 것을 감안해야 겠습니다.