Post

[CI_CD] (Github Actions) 확장성을 고려한 프로젝트에서 많이 쓰는 CI/CD 구축 방법

🪵 AWS CodeDeploy

🪵 서버 (EC2 인스턴스) 가 여러대여도 쉽게 배포를 할 수 있게 도와준다

※ 무중단 배포기능도 내재되어 있어 쉽게 무중단 배포를 구현할 수 있다.

AWS CodeDeployEC2에 명령을 해야하는데, EC2가 해당 명령을 알아들을 수 있는 프로그램을 설치해야 한다 (codedeploy-agent)

🧙‍♂️ EC2 內 codedeploy-agent 설치

1
2
3
4
5
6
7
8
sudo apt update && \
sudo apt install -y ruby-full wget && \
cd /home/ubuntu && \
wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install && \
chmod +x ./install && \
sudo ./install auto

systemctl status codedeploy-agent

active (running) 확인 🔅

1
2
3
4
ls
(install, codedeploy-agent 설치파일)
rm -rf install
(없어도 상관x)

👹 확장성을 고려한 CI/CD 구축

👹 전체적인 흐름

Alt text

Github Actions에서 빌드 및 테스트를 수행하고, S3에 빌드파일을 전달한다.
Github ActionsCodeDeploy에 배포를 진행하라고 명령하면,
CodeDeployEC2에게 S3로부터 빌드 파일을 다운받고, 배포를 진행하도록 명령한다.
(정확히는 EC2에 설치된 codedeploy-agent에게 명령)

🔌 실습 STEP1: 확장성을 고려한 CI/CD 구축, AWS 설정

🔌 각 리소스 접근할 수 있는 권한 설정 (사용자, 정책, 역할)

📔 외부 리소스가 AWS 리소스를 사용할 때 허용할 정책을 가진 사용자를 생성한다.
📔 정책은 특정 리소스에 대한 권한을 지정한다.
※ 하나의 역할은 여러개의 정책을 가질 수 있다. (역할 생성하면서 정책 연결)
📔 특정 AWS 리소스가 다른 AWS 리소스에 접근할 권한을 얻을 때 역할을 생성한다.

⛓️ Github Actions(외부리소스)에서 S3에 접근할 권한 필요 (빌드파일 업로드)
⛓️ Github Actions(외부리소스)에서 CodeDeploy에 접근할 권한 필요 (배포 진행 명령)

🍜 Github Actions에게 IAM 발급 및 Github Repository secrets에 저장
※ IAM

[IAM > 사용자]
🕹️ '사용자 생성'
  사용자 이름: [TEST-SERVER-GITHUB-ACTIONS]
  🕹️ '다음'

  권한 옵션
  ✅ 직접 정책 연결
   ✅ AWSCodeDeployFullAccess
   ✅ AmazonS3FullAccess
   🕹️ '다음'
  🕹️ '사용자 생성'

생성된 사용자 🖱️
[보안 자격 증명 Tab]
'액세스 키 만들기'
  ✅ AWS 외부에서 실행되는 애플리케이션
  🕹️ '다음'
  🕹️ '액세스 키 만들기'
  액세스 키 복사 📑
  비밀 액세스 키 복사 📑
  ※ 따로 메모장에 저장
  🕹️ '완료'
  🕹️ '계속'

[in Github Repository]
[Settings > Secrets and variables > Actions]
🕹️ 'New repository secret'
  AWS_ACCESS_KEY_ID
  값 붙여넣기
  🕹️ 'Add secret'

🕹️ 'New repository secret'
  AWS_SECRET_ACCESS_KEY
  값 붙여넣기
  🕹️ 'Add secret'

⛓️ CodeDeploy에서 EC2에 접근할 권한 필요 (배포 진행 명령)

🍜 CodeDeploy의 S3에 대한 역할 생성
[IAM > 역할]
🕹️ '역할 생성'
  ✅ AWS 서비스
  서비스 또는 사용 사례: [CodeDeploy 선택]
  '다음'

  AWSCodeDeployRole
  (필요한 권한들이 이미 다 세팅되어 있다.)
  '다음'

  역할 이름: [CODE-DEPLOY-ROLE]
  🕹️ '역할 생성'

⛓️ EC2에서 S3에 접근할 권한 필요 (빌드파일 다운로드)

🍜 역할에 연결할 정책 생성
[IAM > 정책]
🕹️ '정책 생성'
  JSON 🖱️
  아래 json 파일 복붙 📑
  🕹️ '다음'

  정책 이름: [CODE-DEPLOY-EC2-POLICY]
  🕹️ '정책 생성'
1
2
3
4
5
6
7
8
9
10
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": ["s3:Get*", "s3:List*"],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

🪄 s3에 접근하고, 조회하는 기능을 허용

🍜 역할 생성 및 EC2에 연결
[IAM > 역할]
🕹️ '역할 생성'
  ✅ AWS 서비스
  서비스 또는 사용 사례: EC2
  🕹️ '다음'

  위에서 생성한 정책 검색 🔍 [CODE-DEPLOY-EC2-POLICY] 및 체크
  🕹️ '다음'
  역할 이름: [CODE-DEPLOY-EC2-ROLE]
  🕹️ '역할 생성'

[EC2 > 인스턴스]
✅ [생성했던 인스턴스]
  [작업 > 보안 > IAM 역할 수정]
  [새로 생성한 역할 선택]
  🕹️ 'IAM 역할 업데이트'
🔌 빌드파일을 업로드할 S3 생성
🍜 S3 생성
[Amazon S3]
🕹️ '버킷 만들기'
  버킷 이름: [TEST-SERVER-S3]
  🕹️ '버킷 만들기'
🔌 CodeDeploy > 애플리케이션 생성
🍜 애플리케이션 및 배포그룹 생성
[CodeDeploy > 애플리케이션]
🕹️ '애플리케이션 생성'
  애플리케이션 이름: [TEST-APPLICATION]
  컴퓨팅 플랫폼: ✅ EC2/온프레미스
  🕹️ '애플리케이션 생성'

배포그룹: 프로덕션, 스테이징, 디벨롭 환경을 구별하기 위한 단위
🕹️ '배포그룹 생성'
  배포 그룹 이름 입력: Production
  서비스 역할 입력: [IAM에서 생성한 역할 선택]

  [애플리케이션 배포 방법 선택]: ✅ 현재 위치

  [환경구성]
  ✅ Amazon EC2 인스턴스
  키: Name
  값: [EC2 인스턴스 선택]

  [로드밸런서]
  로드 밸런싱 활성화 해제

  🕹️ '배포 그룹 생성'

🔌 실습 STEP2: CodeDeploy 설정파일 및 쉘스크립트 파일 작성

🔌 appspec.yml, CodeDeploy 필수 설정 파일

해당 yml에는 S3로부터 빌드파일을 다운받고 쉘 스크립트 파일을 실행하라는 내용이 담겨있다.
※ EC2 내부에 설치된 codedeploy-agent가 해당 파일을 읽고 실행한다.
※ 파일명이 꼭 appspec.yml 여야만 AWS CodeDeploy가 해당 파일을 인식한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
version: 0.0
os: linux

# AWS EC2가 S3로부터 어떤 파일을 어느 위치에 다운받을 것인지
files:
  - source: / # S3의 저장한 전체 파일
    destination: /home/ubuntu/test-server

# codedeploy-agent가 작업을 수행할 때 어떤 권한을 가지고 수행할 것인지
permissions:
  - object: /
	owner: ubuntu
	group: ubuntu

# 애플리케이션을 시작할 단계에서 어떤 작업을 수행할 것인지
hooks:
  ApplicationStart:
    - location: scripts/start-server.sh # 쉘스크립트 파일 실행
      timeout: 60
      runas: ubuntu
🪄 소스 제공 위치
deploy.yml 파일에서 aws deploy create-deployment 명령에서
--s3-location bucket=test-server-build-s3,bundleType=tgz,key=$GITHUB_SHA.tar.gz 옵션을 설정했기 때문에
files > sourceAWS S3의 지정한 버킷을 가리킨다.

프로젝트 루트 > 📂scripts > start-server.sh

1
2
3
4
5
6
7
#!/bin/bash

echo "------------------서버 시작------------------"
cd /home/ubuntu/test-server
sudo fuser -k -n tcp 8080 || true
nohup java -jar project.jar > ./output.log 2>&1 &
echo "------------------서버 배포 끝------------------"

🔌 실습 STEP3: deploy.yml 워크플로우 파일 작성

🔌 deploy.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
name: Deploy TO EC2 With CodeDeploy

on:
  push:
    branches:
      - main

jobs:
  Deploy:
    runs-on: ubuntu-latest
	steps:
      - name: Github Repository에 업로드한 파일 불러오기
        uses: actions/checkout@v4

      - name: test
        run: |
          ls
          pwd
      - name: JDK 11 ver. 설치
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: 11

      - name: Java ver. 확인
        run: java -version

      - name: application.yml 파일 생성
        run: echo "$" > src/main/resources/application.yml

      - name: 테스트 및 빌드
        run: |
          chmod +x gradlew
          ./gradlew clean build

      - name: 빌드된 파일 이름 변경
        run: mv ./build/libs/*SNAPSHOT.jar ./project.jar

      - name: 압축하기
        run: tar -czvf $GITHUB_SHA.tar.gz project.jar appspec.yml scripts

      - name: AWS Resource에 접근할 수 있게 AWS Credentials 설정
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ap-northeast-2
          aws-access-key-id: $
          aws-secret-access-key: $

      - name: S3에 프로젝트 폴더 업로드
        run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.tar.gz s3://test-server-build-s3/$GITHUB_SHA.tar.gz

      - name: CodeDeploy를 활용해 EC2에 프로젝트 코드를 배포하라고 명령
        run: aws deploy create-deployment
            --application-name test-server-application
            --deployment-config-name CodeDeployDefault.AllAtOnce
            --deployment-group-name Production
            --s3-location bucket=test-server-build-s3,bundleType=tgz,key=$GITHUB_SHA.tar.gz
🪄 압축
tar -czvf [압축후 파일명] [압축할 대상1] [압축할 대상2] [압축할 대상1] …
 
🪄 Github Actions에서 AWS 리소스에 접근할 수 있도록 로그인과 유사한 인증이 필요하다.
AWS Credentials
🧩 관련 라이브러리: aws-actions/configure-aws-credentials@v4
 
🪄 aws 명령어
  • aws s3 cp --region ap-northeast-2 p1 s3://~/~.tar.gz: S3에 있는 파일을 업로드
  • aws deploy create-deployment
    배포생성 (개발자 도구 > CodeDeploy > 애플리케이션 > 배포그룹 > ‘배포 생성’ 하는 것과 같다.)
    create-deployment 명령어가 실행되면, 지정한 S3 버킷에서 .tar.gz 파일을 다운로드 받는다.
    해당 압축파일을 임시 디렉토리에 풀고, appspec.yml을 찾는다.
    해당 파일을 파싱하고, 그 내용에 따라 EC2 인스턴스내에서 작업을 수행한다.
     
    CodeDeployDefault.AllAtOnce: 모든 인스턴스를 한번에 배포하는 옵션 (인스턴스가 여러개 있을 때 중요)

🥊 git push 후 배포 확인
[개발자 도구 > CodeDeploy > 배포]
배포 내용이 생겼는 지 확인 🔅

[Amazon S3]
S3에 압축된 파일이 업로드 되었는지 확인 🔅
($GIHUB_SHA.tar.gz)

[EC2 인스턴스 內]
ls
cd test-server
ls
appspec.ymloutput.logproject.jarscripts 확인 🔅

lsof -i:8080

🍝 실행된 쉘스크립트 로그 확인

🍝 codedeploy-agent가 실행시킨 스크립트 파일에 대한 로그를 보고 싶을 때
1
2
3
4
5
6
7
8
cd /opt
cd codedeploy-agent
cd deployment-root
cd [START WITH ALPHABET...]
ls
cd [DISTRIBUTION ID]
cd logs
cat scripts.log
🪄 배포 ID
[개발자 도구 > CodeDeploy > 배포]
해당 배포 id에 해당하는 폴더가 생성되어 있다.
This post is licensed under CC BY 4.0 by the author.