sklass의 s-class 프로그래밍 blog

AWS Code Deploy를 통한 배포 자동화 본문

CI\CD

AWS Code Deploy를 통한 배포 자동화

sklass 2021. 11. 26. 15:32

CD 파이프라인을 구성하기 위해서, 제가 선택한 옵션은 바로 AWS Code Deploy 입니다. 롤백이 가능하며, 서버를 AWS EC2를 쓰고 있던 터라, 다른 CD 툴보다 CodeDeploy를 먼저 시도해보고 싶었습니다. 배포하고 싶은 파일을 S3에 .zip 형태로 업로드한 뒤에 CodeDeply를 통해 배포해도 되지만, 저희 회사에서는 코드를 github으로 관리하고 있어서, github에 merge된 코드를 github action을 통해서 CodeDeploy 트리거 시켜서 진행했습니다.

 

아래는 제가 CodeDeploy를 구현한 절차입니다.

 

우선 AWS IAM Role을 생성합니다. IAM Role 생성 버튼을 누르고 아래 화면에서 EC2를 선택합니다.

그 후, 다음 2가지 role을 찾아서 선택합니다.

  1. AmazonEC2RoleForAWSCodeDeploy
  2. AWSCodeDeployRole

Role 이름을 지어주고, 생성해줍니다. Role이 생성되면 선택해서 다음과 같이 Edit trust relationship를 통해서 trust relationships를 편집해야합니다.

Edit trust relationship을 클릭 후, 아래와 같이 변경해 줍니다.

{ 
    "Version": "2012-10-17", 
    "Statement": [ 
        { 
            "Effect": "Allow", 
            "Principal": { 
                "Service": [ 
                    "codedeploy.us-west-2.amazonaws.com", 
                    "ec2.amazonaws.com" 
                ] 
            }, 
            "Action": "sts:AssumeRole" 
        } 
    ] 
}

 

위에서 만든 role을 존재하는 ec2에 적용하기 위해서, 적용하고자 하는 ec2를 선택후 아래와 같이 Actions창에서 Security → Modify IAM role을 선택 후, 위에서 생성한 role을 연결시켜주고 Save해줍니다.

이제 EC2에 권한 부여가 완료 되었고, 이제 해당 노드에 ssh접속하여 아래의 명령어들을 이용해서 필요한 Dependency만 아래의 명령어들로 설치를 해줍니다.

$ sudo apt-get update -y

# git 설치
$ sudo apt-get install git -y

# python 설치
$ sudo apt-get install python3-pip python3.8 -y

# AWS CodeDeploy Agent 설치. 아래 커맨드는, 프로젝트 루트가 아닌 /home/ubuntu 에서 실행해주시기 바랍니다.
$ sudo apt-get install -y ruby
$ sudo apt-get install wget
$ wget https://aws-codedeploy-us-west-2.s3.us-west-2.amazonaws.com/latest/install
$ chmod +x ./install
$ sudo ./install auto
$ sudo service codedeploy-agent start

 

이제 Load Balancer로 가서, Target group을 위의 노드와 연결해서 생성해줍니다. Target group은 아래와 같이 인스턴스를 선택 후 기본 설정 값들로 (HTTP 80 포트 등) 생성해주면 됩니다.

Aws CodeDeploy 로 들어간 후, Create application을 선택하고, application 이름을 지어준 다음, EC2/On-premises를 선택하고, 생성해줍니다.

 

application이 생성되면, Deployment groups 섹션으로 가서, Create deployment group을 선택해서, 알맞은 이름을 지어준 후, 아래의 Service role 섹션에서 위에서 생성한 role을 선택해 줍니다.

 

Deployment type은 In-place로, Environment configuration은 Amazon EC2 instances를 선택해 준 후에, Key를 Name으로 주고, 연결하고자 하는 노드의 이름을 Value로 설정해 줍니다.

 

아래와 같이 위에서 생성한 Load balancer target group과 연결시켜주고 deployment group을 생성해줍니다.

 

이제 콘솔에서의 준비는 모두 끝났고, 프로젝트 루트로 가서, 루트에 appspec.yaml 파일을 생성해주고, 프로젝트 install이 끝나고 나서 실행될 script 파일을 scripts/start_server.sh 에 작성해주세요

또한,  .github/workflows/cd.yaml 에 풀리케가 머지되면 CodeDeploy가 트리거 되는 github action 코드를 작성해주어야 합니다.

 

여기서 AppSpec 파일은, Application Specification 의 약자로, YAML 혹은 JSON 형식으로 이루어진 사양 파일입니다. AppSpec 파일은 파일에 정의된 일련의 수명 주기 이벤트 후크로, 각 배포를 관리하는데 사용됩니다. 각 후크는 배포별로 한 번 실행되며, 후크를 실행할 수 있는 수명 주기 이벤트의 종류와 순서는 아래 이미지와 같습니다.

CodeDeploy 후크 종류 및 순서

 

이제 프로젝트 루트로 가서 appspec.yaml 파일을 생성해보겠습니다.

appspec.yaml은 아래와 같이 작성해줍니다.

version: 0.0
os: linux
files:
  - source: /
    destination: /home/ubuntu/hits_Platform_backend
hooks:
  AfterInstall:
    - location: scripts/start_server.sh
      timeout: 300
      runas: root

위의 appspec.yaml 에서는 AfterInstall 생명 주기 이벤트에서, start_server.sh 를 실행시키는데, 이는, github에서 막 머지된 코드를 해당 서버에서 빌드한 후에, start_server.sh를 실행한다는 의미입니다.

 

그럼 이제 scripts/start_server.sh의 내용을 살펴보겠습니다.

#!/bin/bash

sudo systemctl restart gunicorn

위의 명령어가 AfterInstall 생명 주기 이벤트 후에 실행되는데, 머지된 코드가 빌드되고, 이를 서버에 반영하기 위해서 gunicorn을 재시작해주는 코드입니다.

 

이제 github action에 추가될 코드를 살펴보겠습니다.

아래는 .github/workflows/cd.yaml 의 코드입니다.

name: HITS CD
on:
  pull_request:
    branches: [ dev ]
    types: [ closed ]
jobs:
  cd:
    runs-on: ubuntu-latest
    steps:
      - 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: us-west-2
      - name: Create CodeDeploy Deployment
        if: github.event.pull_request.merged == true
        run: |
          aws deploy create-deployment --application-name ${{ secrets.AWS_CODE_DEPLOY_APPLICATION }} --deployment-group-name ${{ secrets.AWS_CODE_DEPLOY_GROUP }} --deployment-config-name CodeDeployDefault.AllAtOnce --github-location repository=${{ github.repository }},commitId=${{ github.sha }}

위의 코드에서 on 섹션을 보시면, dev라는 브랜치에 pull_requestclosed 된 경우에만, 해당 yaml파일의 코드를 실행하라는 의미입니다.

 

github action은 단일 azure 서버 위에서 돌아가는데, github action이 돌아갈 때마다 서버를 생성해주는 형식이라, AWS credential을 매번 설정해 주어야합니다. 때문에 steps 섹션의 Configure AWS credentials에서 Access Key와 Secret Access  Key를 설정해주고, Create CdoeDeploy Deployment 에서 merge가 된거라면, aws cli를 이용해서 CodeDeploy를 실행시킵니다.

 

이때, github secret에 위에서 생성한 AWS CodeDeploy application 이름과 deployment group 이름을 아래의 키로 등록해주어야 합니다.

{
	"AWS_CODE_DEPLOY_APPLICATION": <application_name>,
	"AWS_CODE_DEPLOY_GROUP": <deployment_group_name>,
}

 

이제  잘되는지 확인해보기 위해서 풀리케를 날리고 머지를 하고, AWS Console에서 CodeDeploy 로 가서, Deployment(배포) 섹션을 클릭해서 보면 아래와 같은 화면이 뜨는데 View Events를 눌러서 각 수명 주기 이벤트가 잘 작동되는지 확인해 볼 수 있습니다.

View events 창에서 아래와 같이 모든 수명 주기 이벤트가 성공하면, CodeDeploy 가 성공한것 입니다.