티스토리 뷰

CodeDeploy

소개

전 시간에 이어 다음으로는 Github Actions 에서 CodeDeploy 에게 S3에 있는 jar 파일을 가져가서 담당한 배포 그룹의 EC2에 배포해 줘! 라는 명령을 내릴 수 있도록 구성해 보겠습니다.

먼저 CodeDeploy에 대해 간단하게 소개하자면, 애플리케이션 배포를 자동화하는 AWS 의 배포 서비스입니다.
EC2, AWS Lambda 와 같은 서비스에 배포를 할 수 있고, 현재위치 배포나 블루/그린 배포와 같은 무중단 배포를 지원합니다.
한 번 구축해 놓으면 이후로는 배포가 매우 간편하고 AWS 콘솔을 통해 제어하면서 배포 과정을 확인할 수 있기 때문에 많은 분들이 이 서비스를 이용하여 배포 플로우를 구축합니다.

조금 더 자세한 설명은 CodeDeploy 레퍼런스를 참고해보시면 좋습니다.

CodeDeploy 의 배포 과정은 다음과 같습니다.

  • 개발한 애플리케이션 최상단 경로에 AppSpec.yml 이라는 파일을 추가합니다.
    • AppSpec.yml 은 배포에 필요한 모든 절차를 적어둔 명세서라고 생각하시면 됩니다.
  • CodeDeploy에 프로젝트의 특정 버전을 배포해 달라고 요청하면, CodeDeploy는 배포를 진행할 EC2 인스턴스에 설치돼 있는 CodeDeploy Agent들과 통신하며 Agent들에게 요청받은 버전을 배포해 달라고 요청합니다.
  • 요청 받은 Agent들은 코드 저장소에서 프로젝트 전체를 서버에 내려받고, AppSpec.yml 파일을 읽어 해당 파일에 적힌 절차대로 배포를 진행합니다.
  • Agent는 배포를 진행한 후 CodeDeploy에게 성공/실패 등의 결과를 알려줍니다.

CodeDeploy Agent 는 EC2 인스턴스에 설치되어 CodeDeploy의 명령을 기다리고 있는 프로그램입니다.
실제로 배포를 수행하는 것은 Agent이기 때문에 반드시 EC2 인스턴스에 설치되어 있어야 합니다.

배포할 EC2 세팅하기

먼저 우리가 애플리케이션을 배포할 EC2 를 하나 생성하겠습니다.
EC2 인스턴스를 띄우는 방법은 이미 많은 자료가 있기 때문에 생략하겠습니다.

저는 Amazon Linux 2 AMI를 사용하였습니다.
Ubuntu 를 사용하시는 분들은 아래 소개되는 과정들에서 진행하는 커맨드가 조금 다를 수 있습니다. (패키지 매니저 등)

다만 다음과 같이 인바운드 규칙을 생성해주세요!
ssh 접속은 현재 내 IP, 그리고 기본적으로 웹 서비스를 할 서버이기 때문에 HTTP, HTTPS 포트인 80, 443 포트에 대해서는 열어주시면 됩니다.

ssh 로 새롭게 생성한 인스턴스에 접속해주세요!

먼저 Java 가 있는지 확인하고 없다면 설치해줍니다.

sudo yum install -y java-1.8.0-openjdk-devel.x86_64
java -version # 1.8 버전이 설치되었는지 확인

다음으로는 CodeDeploy Agent 를 설치하겠습니다.

CodeDeploy Agent 설치 레퍼런스를 참고하셔서 다음 커맨드를 차례로 수행합니다.

# 패키지 매니저 업데이트, ruby 설치
sudo yum update
sudo yum install ruby
sudo yum install wget

# 서울 리전에 있는 CodeDeploy 리소스 키트 파일 다운로드
cd /home/ec2-user
wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install

# 설치 파일에 실행 권한 부여
chmod +x ./install

# 설치 진행 및 Agent 상태 확인
sudo ./install auto
sudo service codedeploy-agent status

CodeDeploy Agent 가 실행되었음을 확인할 수 있습니다!

만약 status 확인 시 Agent 가 실행중이지 않다면 다음 커맨드를 수행합니다.

sudo service codedeploy-agent start

EC2 에 IAM 역할 부여하기

이전 글에서 IAM 권한 사용자를 생성하여 Github Actions 가 해당 사용자의 권한을 사용할 수 있도록 설정한 것을 기억하실텐데요.
이번에는 EC2 에 S3, CodeDeploy 권한 정책을 부여해 보겠습니다.
IAM 사용자는 아이디/비밀번호 기반으로 외부 프로그램이 사용자처럼 접근하는 것이라면, IAM 역할은 다른 계정의 IAM 사용자, 혹은 다른 AWS 서비스가 수행하는 역할 권한을 부여하는 것이라고 생각하시면 됩니다.

다음과 같이 IAM 의 역할로 이동하여 역할을 만들어 보겠습니다.

사용 사례에서 EC2 를 선택합니다.

S3 와 CodeDeploy 에 대한 권한 정책을 검색하여 추가합니다.

적당한 태그와 역할 이름을 설정하고 역할 만들기를 선택합니다.

역할을 생성했다면 EC2 대시보드로 돌아와 해당 EC2 우클릭 - 인스턴스 설정 - IAM 역할 연결/바꾸기 를 선택합니다.

방금 생성했던 IAM 역할을 부여합니다.

CodeDeploy IAM 역할 생성하기

이제 CodeDeploy를 설정해 보겠습니다.

CodeDeploy 애플리케이션을 생성하기 전에, 앞에서와 마찬가지로 CodeDeploy를 위한 IAM Role이 필요합니다.
다시 IAM - 역할 - 역할 만들기 로 이동하여, 아래쪽의 CodeDeploy 선택, 사용 사례도 CodeDeploy를 선택하고 다음으로 넘어갑니다.

나머지는 방금전까지 했던 과정과 동일합니다.
역할의 이름을 정하고 역할을 생성합니다.

CodeDeploy 애플리케이션 생성하기

다음으로 CodeDeploy 애플리케이션을 생성하겠습니다.
CodeDeploy - 애플리케이션 - 애플리케이션 생성 에서 이름과 EC2를 선택하고 생성을 진행합니다.

다음으로는 만들어진 애플리케이션에서 배포 그룹 생성을 클릭합니다.

배포 그룹 생성 화면에서 이름과, 방금 만들었던 IAM 역할을 연결합니다.
우리는 최소 단위의 무중단 배포를 CodeDeploy가 아닌 Nginx를 통해 구현할 것이기 때문에, 지금은 일단 현재 위치 배포를 선택하고 넘어갑니다.

현재 위치 배포와 블루/그린 배포 모두 무중단 배포의 형태들입니다.
다만 지금 우리는 서버를 여러 대 띄우는 방식이 아니라, 하나의 EC2 내부에서 두 개의 포트에 WAS를 띄우고 스위칭하는 방식을 쓸 것이기 때문에 CodeDeploy가 무중단 배포의 역할을 가지고 있지는 않습니다.

환경 구성은 EC2를 선택하고 태그에는 EC2 인스턴스에 설정했던 태그를 걸어줍니다.
해당 태그를 기준으로 CodeDeploy가 배포를 진행합니다.

배포 설정은 여러 대의 서버를 어떤 단계에 따라 순차적으로 배포할 것인지를 선택하는 설정인데요.
어차피 EC2가 하나기 때문에 한번에 배포를 끝내는 CodeDeployDefault.AllAtOnce 를 선택합니다.

로드밸런서는 없기 때문에 활성화를 해제하고 배포 그룹을 생성합니다.

스크립트 추가하기

이제 CodeDeploy의 설정은 끝이 났습니다!
마지막으로 프로젝트에서 스크립트를 몇 가지 추가해 보겠습니다.

먼저 프로젝트의 최상단에 appspec.yml을 생성합니다.
appspec.yml은 CodeDeploy Agent가 참조하면서 배포를 진행하는 명세서입니다.

기본적인 appspec.yml을 다음과 같이 작성합니다.
다음 단계인 Nginx 적용 단계에서 스크립트를 추가적으로 작성하겠습니다.

# appspec.yml

version: 0.0
os: linux
files:
  - source: /
    destination: /home/ec2-user/playground-logging/ # 프로젝트 이름
    overwrite: yes

permissions:
  - object: /
    pattern: "**"
    owner: ec2-user
    group: ec2-user
  • files.destination
    • S3에서 받아온 프로젝트의 위치를 지정해주시면 됩니다.

그리고 Github Actions의 스크립트에도 마지막 단계를 업데이트합니다.
Github Actions 는 이번 CodeDeploy Step 작업을 끝으로 더이상 추가할 것이 없으니 전체 스크립트를 다시 보여드리겠습니다.

# logging-deploy.yml

name: logging-system

on:
  workflow_dispatch:

env:
  S3_BUCKET_NAME: logging-system-deploy
  PROJECT_NAME: playground-logging

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Set up JDK 1.8
        uses: actions/setup-java@v1
        with:
          java-version: 1.8

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew
        shell: bash

      - name: Build with Gradle
        run: ./gradlew build
        shell: bash

      - name: Make zip file
        run: zip -r ./$GITHUB_SHA.zip .
        shell: bash

      - 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: ${{ secrets.AWS_REGION }}

      - name: Upload to S3
        run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$PROJECT_NAME/$GITHUB_SHA.zip

      ### 새로 추가한 부분 ###
      - name: Code Deploy
        run: aws deploy create-deployment --application-name logging-system-deploy --deployment-config-name CodeDeployDefault.AllAtOnce --deployment-group-name develop --s3-location bucket=$S3_BUCKET_NAME,bundleType=zip,key=$PROJECT_NAME/$GITHUB_SHA.zip
  • application-name
    • CodeDeploy 애플리케이션의 이름을 지정합니다.
  • deployment-config-name
    • 배포 그룹 설정에서 선택했던 배포 방식을 지정합니다.
  • deployment-group-name
    • 배포 그룹의 이름입니다.
  • s3-location
    • jar를 S3에서 가지고 오기 위해 차례로 bucket 이름, 파일 타입, 파일 경로를 입력합니다.

여기까지가 이번 단계의 끝입니다!

Github Actions에서 배포를 실행하기 전에 한 가지 진행해야 하는 부분이 있는데요.
지금까지의 과정 순서를 똑같이 따라하셨다면, CodeDeploy Agent를 시작한 후에 IAM Role을 EC2에 부여했기 때문에 아마 Agent가 IAM Role을 가지고 있지 않아 배포가 실패할 것입니다.

EC2에 접속해서 다음 커맨드로 Agent를 재시작해주세요!

sudo service codedeploy-agent restart

그리고 나서 Github Actions의 workflow를 시작하고 잠시 기다리면!

CodeDeploy의 배포가 성공한 것을 볼 수 있습니다!

EC2에 접속해서 한번 확인해 보겠습니다.

ec2-user home 디렉토리에 S3에서 받아온 프로젝트가 있는 것을 확인할 수 있습니다!
물론 아직 진짜 배포를 하도록 스크립트를 짜지는 않았지만, 적어도 각 서비스 간 통신은 잘 이루어졌다고 생각할 수 있습니다.

만약 배포가 실패했다면 아래쪽에 배포 실행 목록에서 View events를 확인하면 에러 로그를 볼 수 있습니다.
View events를 확인했는데 에러 로그도 보이지 않는다면, 이 글을 참고해 주세요!

여기까지 완료했다면 이제 마지막 단계인 Nginx 무중단 배포를 진행하러 가보겠습니다.


참고