이번에는 본격적으로 기존에 만들어둔 VPC에 떠있는 ECS를 자동으로 배포하는 파이프라인을 작성 해 보겠습니다.
당연하게도, 매 푸시마다 배포를 할 수는 없겠죠? 따라서 저는
Fargate가 배포되도록 해 보겠습니다.
필요한 작업 목록
테스트
작업 종류 | 작업명 | Marketplace |
---|---|---|
Repo에서 코드 가져오기 | code checkout | O |
머신에 nodejs 세팅하기 | setup node | O |
반복적인 모듈 인스톨을 위한 캐싱 | cache node modules | O |
의존성 설치 | npm install | X |
린트 | npm run lint | X |
유닛 테스트 | npm run test | X |
테스트 결과 리포트 작성 | Comment with Test Coverage | O |
e2e 테스트 | npm run test:e2e | X |
슬랙으로 알림 보내주기 | Notify Slack | O |
배포
작업 종류 | 작업명 | Marketplace |
---|---|---|
Repo에서 코드 가져오기 | code checkout | O |
AWS 인증정보 가져오기 | configure AWS Credentials | O |
ECR에 로그인하기 | Login to Amazon ECR | O |
이미지 빌드해서 ECR에 푸시하기 | Build and push NestJS | O |
태스크 정의 개정하기 | Fill in the new image ID in the Amazon ECS task definition | O |
서비스 새로 배포하기 | Deploy Amazon ECS task definition | O |
슬랙으로 알림 보내주기 | Notify Slack | O |
deploy.yml
name: Test and Deploy
on:
pull_request:
branches:
- stage
- main
types:
- closed
permissions:
pull-requests: write
env:
ECR_REPOSITORY: 'ford-study'
ECS_CONTAINER_NAME: 'nestjs'
ECS_SERVICE_NAME: 'ford-study-nestjs'
ECS_CLUSTER_NAME: 'ford-study'
jobs:
test:
name: test nestjs
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v4.1.1
- name: Setup node
uses: actions/setup-node@v4.0.0
with:
node-version: '20'
cache: 'npm'
- name: Cache node modules
uses: actions/cache@v3.3.2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: npm install
- name: Run lint
run: npm run lint
- name: Run tests
run: npm run test
- name: Comment with Test Coverage
uses: dkershner6/jest-coverage-commenter-action@v1
with:
github_token: "${{ secrets.GITHUB_TOKEN }}"
test_command: "npm run test:cov"
- name: Run e2e tests
run: npm run test:e2e
- name: Notify Slack on Failure
if: failure()
uses: 8398a7/action-slack@v3.15.1
with:
status: ${{ job.status }}
fields: repo,message,commit,author,action,eventName,ref,workflow,job,took
author_name: ${{ github.actor }}
channel: ${{ vars.SLACK_CHANNEL }}
username: ${{ vars.SLACK_USERNAME }}
text: 'Tests failed! :x:'
env:
SLACK_WEBHOOK_URL: ${{ vars.SLACK_WEBHOOK_URL }}
- name: Notify Slack on Success
if: success()
uses: 8398a7/action-slack@v3.15.1
with:
status: ${{ job.status }}
fields: repo,message,commit,author,action,eventName,ref,workflow,job,took
author_name: ${{ github.actor }}
channel: ${{ vars.SLACK_CHANNEL }}
username: ${{ vars.SLACK_USERNAME }}
text: 'Tests passed! :white_check_mark:'
env:
SLACK_WEBHOOK_URL: ${{ vars.SLACK_WEBHOOK_URL }}
build_and_deploy:
if: github.event.pull_request.merged == true
name: build docker image and ecs deploy
runs-on: ubuntu-22.04
needs: test
steps:
- name: checkout
uses: actions/checkout@v4.0.0
- name: configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: ap-northeast-2
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Build and push NestJS
uses: docker/build-push-action@v5.1.0
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }}
build-args: |
NODE_ENV=production
- 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: task-definition.json
container-name: ${{ env.ECS_CONTAINER_NAME }}
image: ${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ 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: ${{ env.ECS_SERVICE_NAME }}
cluster: ${{ env.ECS_CLUSTER_NAME }}
wait-for-service-stability: false
- name: Notify Slack on Failure
if: failure()
uses: 8398a7/action-slack@v3.15.1
with:
status: ${{ job.status }}
fields: repo,message,commit,author,action,eventName,ref,workflow
author_name: ${{ github.actor }}
channel: ${{ vars.SLACK_CHANNEL }}
username: ${{ vars.SLACK_USERNAME }}
text: 'Deploy failed! :x:'
env:
SLACK_WEBHOOK_URL: ${{ vars.SLACK_WEBHOOK_URL }}
- name: Notify Slack on Success
if: success()
uses: 8398a7/action-slack@v3.15.1
with:
status: ${{ job.status }}
fields: repo,message,commit,author,action,eventName,ref,workflow
author_name: ${{ github.actor }}
channel: ${{ vars.SLACK_CHANNEL }}
username: ${{ vars.SLACK_USERNAME }}
text: 'Deploy success! :white_check_mark:'
env:
SLACK_WEBHOOK_URL: ${{ vars.SLACK_WEBHOOK_URL }}
특별히 신경써야 할 부분은 아래와 같습니다.
...
- 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: task-definition.json // 태스크 정의 파일의 경로
...
AWS에서 권한을 부여하는 방식에는 크게 세 가지가 있습니다.
여기에서는 3번, 권한을 직접 선택하기로 해 줍니다.
정말 사용 목적이라면, 여기에서 최소한의 필요한 권한들을 선택해 주어야 합니다. 왜냐하면, 시크릿의 경우 장기간 사용 가능한 특성상, 한 번 노출되면 큰 피해를 입을 수 있기 때문입니다.
그러나 우선 지금은, 잠깐 체험 후 삭제가 목적이니 간단하게 administrator로 만들어줍시다.
확인이 끝나셨다면, administrator 키는 꼭 잘 관리 해 주시거나 지워주시는게 좋습니다.
그리고 다음 글에서는, Github OIDC를 통해 좀 더 안전하게 AWS 인증정보를 얻어내는 방법을 설명드리겠습니다.