github actions로 CI/CD 구축하기 - 2

ansunny1170·2023년 10월 17일
1

개발

목록 보기
7/11
post-thumbnail

시작하는말

프로젝트의 dev branch에 CI/CD를 적용하는 내용입니다. (오래 걸렸습니다...)

CI/CD 구조

사용 기술
github actions를 사용하여 CI/CD를 구축합니다.

prod와 dev server 용 CI/CD를 구분하여 구축해야 합니다.

※ workflows에 관한 작업을 할 수 있기 위해서는 해당 권한이 필요합니다. github에 push 명령 시 권한 문제로 에러가 발생할 수 있습니다.

※ public이 아닌 repo는 github actions등의 서비스를 이용할 때마다 비용이 발생할 수 있습니다. 일정 양에 대해서는 무료사용이 가능한 내용도 있으니, 사전에 확인을 해야 합니다.
🫱🏻‍🫲🏻GitHub Actions 요금 청구 정보 - github docs

CI

참고 사이트 :
제발 깃허브 액션🔥 모르는 개발자 없게해 주세요 🙏 - 드림코딩
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를 진행하게 됩니다.

CD

참고 사이트:
ECS CI/CD 파이프라인 - github actions - velog

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
  • if 구문을 사용해 PR이 merge 되면 jobs를 실행하도록 했습니다.
  • secrets.로 시작하는 변수는 github secrets 이라는 재사용 가능한 변수를 사용하는 구문입니다. secretsvariables 두 종류가 있으며, secrets는 암호화 되기 때문에 민감한 정보에 적합 합니다.
  • 사진과 같이 .env 파일과 같은 형식으로도 입력이 가능합니다.
    - 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
  • AWS에 자격 증명을 위한 설정을 합니다.
  • AWS ECS에 login 합니다.
    - 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"
  • build & tag & push image 합니다.
  • 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"
  • 가장 최신의 ECS 태스크 정의의 json file을 가져옵니다.
    - 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... 등 다른 편의 기능 및 서비스는 적용하지 않았습니다만, 실제 사용 하다보면 예상치 못한 현상이 발생해 보완 기능을 추가해야 할 수 있을 것을 감안해야 겠습니다.

profile
공정 설비 개발/연구원에서 웹 서비스 개발자로 경력 이전하였습니다. Node.js 백엔드 기반 풀스택 개발자를 목표로 하고 있습니다.

0개의 댓글