CI CD

무중단 배포 (Github Actions, Code Deploy) - 1

붓 필 2025. 1. 23. 00:30

NCP(네이버 클라우드), jenkins, ArgoCD를 사용해서 무중단 배포를 경험했지만, AWS와 Github Action을 사용해서 CI/CD구현해 보고 삽질을 경험하며 기록을 남기려 한다.

 

전체 흐름

 

먼저 하늘색으로 칠해진 부분을 설정해 보자

 

1.  Main  브랜치에 Push  했을 때, WorkFlow 작성

name: Github Actions

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2.4.2

      - name: Setup Node.js environment
        uses: actions/setup-node@v4.1.0
        with:
          node-version: v20.18.1

      - name: Install Dependencies
        run: npm install

      - name: Build a Nest Application
        run: npm run build
        shell: bash

      # 불필요한 node_module, coverage, src, test, readme, .git* 등의 파일은 제외
      - name: Make a zip file
        run: zip -r ./$GITHUB_SHA.zip . -x "node_modules/*" "coverage/*" "src/*" "test/*" "README.md" "*.git*"
        shell: bash

우선 이렇게 워크플로우를 작성한다. 깃헙 워크플로우는 하나의 컴퓨터라 볼 수 있다. 위 컴퓨터에서 os는 무엇을 사용하고 어떤 환경을 구성해서 어떻게 빌드할지 정한다고 생각하면 된다.

 

2. AWS 설정

Workflow는 보안상 AWS 서비스에 접근이 불가능하다. 위에서 설명했듯이 하나의 컴퓨터 이기 때문에 보안상 접근 불가하다.

그럼 AWS에 접근을 해줄 수 있게 하기 위해 IAM이라는 서비스를 사용해야 한다.

 

사용자와 역할이 이미 있기 때문에 만약 사용자와 역할이 없다면 생성을 하자.

사용자 생성 하면 액세스 키, 시크릿 키를. csv파일로 다운로드할 수 있는데 잘 보관하고 이 두 개의 키를 사용할 것이다.

 

Code Deploy 역할 생성

위 페이지에서 역할 생성을 클릭 후

다음 버튼을 눌러 역할을 생성해 준다.

 

EC2 역할 생성

code deploy와 같이 역할 생성을 눌러

역할을 만들고 권한 정책 페이지에서 AmazonS3ReadOnlyAccess, AmazonSSManagedinstanceCore를 추가해 준 후 역할 생성해 준다.

3. EC2 생성

 

간단한 게 설명할 사항들이 있다. 이름은 마음대로 생성하고 os는 우분투를 사용했다. 인스턴스는 프리티어적용이 되는 유형을 선택했고, 네트워크는 따로 생성하지 않고 기본값으로 설정했다. 물론 따로 NACL, SG(보안그룹)을 생성해야 하지만 간단하게 넘어가자.

여기서 키 페어 없이 진행하려 한다. 이유는 ssh 접속 말고 ssm 접속을 할 것이기 때문에 필요 없다. ssh 접근보다 ssm접근이 더 권장된다. 이유는 액세스 키값들을 관리할 필요 없이 ec2에 접근할 수 있어서 이다. 더 많은 이유들이 있지만 여기서 설명하지 않겠다.

마지막으로 인스턴스 시작 버튼을 눌러 인스턴스를 만들자.

 

보안그룹을 기본값으로 설정하고 만들었다 여기서 보안그룹과 NACL의 설명은 하지 않겠다.

여기서 80, 443번만 인바운드 규칙에 추가해 준다. 물론 https사용까지 하지 않겠지만 일단 80, 443을 인바운드 규칙에 추가해 준다.

😀 추가정보 -> 우리는 ssm 접속을 하기 때문에 22번 SSH포트를 열어줄 필요 없다. (보안상 더 유리) 

 

 

EC2 역할을 적용해 준다.

 

4. S3 생성

간단한 CI/CD구축을 위해 모든 퍼블릭 액세스 차단의 체크박스를 제거하고 S3 버킷을 생성해 준다.

 

5. CodeDeploy 생성

아래와 같이 CodeDeploy 애플리케이션을 생성해 준다.

 

애플리케이션 생성하고, 배포 그룹을 생성해 준다.

배포 그룹 이름은 자유롭게 만들고 서비스 역할은 생성해 둔 code-deploy역할을 선택해 준다. 환경구성은 EC2인스턴스에 생성해 둔 인스턴스를 선택하고 배포 설정은 CodeDeployDefault.AllAtOnce와 로드밸런서는 사용하지 않을 것 이기 때문에 체크박스 해제 후 배포 그룹을 생성해 준다.

 

6. Github Actions 작업

중간점검을 해보면 EC2, s3, CodeDeploy를 생성했으니 Github Action을 통해서 main 브랜치에 push 되었을 때, 서버에 배포할 main브랜치의 코드들을 압축에서 S3에 보낸 후, CodeDeploy서비스가 이 압축된 파일을 내 EC2인스턴스에 배포하는 프로세스를 거치면 된다.

 

Github Actions에 액세스 키, 시크릿 키를 등록해 주자. 해당 레파지토리에 Settings - Secrets and variables - Actions에 들어가 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY를 등록해 준다. 

name: Github Actions

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v2.4.2

      - name: Setup Node.js environment
        uses: actions/setup-node@v4.1.0
        with:
          node-version: v20.18.1

      - name: Install Dependencies
        run: npm install

      - name: Build a Nest Application
        run: npm run build
        shell: bash

      # 불필요한 node_module, coverage, src, test, readme, .git* 등의 파일은 제외
      - name: Make a zip file
        run: zip -r ./$GITHUB_SHA.zip . -x "node_modules/*" "coverage/*" "src/*" "test/*" "README.md" "*.git*"
        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: ap-northeast-2 # AWS 서울 리전

      # 위에서 만든 zip 파일을 S3에 업로드
      - name: Upload to S3
        run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$PROJECT_NAME/$GITHUB_SHA.zip

      # CodeDeploy에게 deployment를 생성하도록 요청
      - name: Request Deployment
        run: aws deploy create-deployment --application-name $AWS_CODEDEPLOY_APPLICATION_NAME --deployment-config-name CodeDeployDefault.AllAtOnce --deployment-group-name $AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME --s3-location bucket=$S3_BUCKET_NAME,bundleType=zip,key=$PROJECT_NAME/$GITHUB_SHA.zip

    env:
      AWS_CODEDEPLOY_DEPLOYMENT_GROUP_NAME: my-nest-app-deploy-group # CodeDeploy 배포 그룹 이름
      AWS_CODEDEPLOY_APPLICATION_NAME: my-nest-app-codeDeploy # CodeDeploy 애플리케이션 이름
      S3_BUCKET_NAME: my-nest-app-deploy-s3 # S3 버킷 이름
      PROJECT_NAME: my-nest-app # S3 버킷 내 폴더 이름

이렇게 Github Actions를 구성하면 된다.

 

7. 도커, 도커컴포스 EC2에 설치

# 도커 설치
sudo apt-get update
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
sudo apt-get update
sudo apt-get install docker-ce
sudo systemctl status docker
sudo usermod -aG docker ${USER}

#도커 컴포스 설치
sudo curl -L "https://github.com/docker/compose/releases/download/v2.8.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose -v

 

8. appspec.yml 작성

CodeDeploy에서 배포관리를 위해 사용하는 파일이며, 프로젝트의 루트 경로에 만들어 줘야 한다.

version: 0.0
os: linux
files:
  - source: /
    destination: /home/ubuntu/my-nest-app 
    overwrite: yes 
    
# 아래 부분은 권한 문제로 좀더 자세하게 경로를 적어주었음
permissions:
  - object: /home/ubuntu/my-nest-app
    pattern: '**'
    owner: ubuntu
    group: ubuntu
    mode: 755
    type:
      - file
      - directory

hooks:
  AfterInstall:
    - location: scripts/exec.sh 
      timeout: 600 
      runas: root 
      ^^^^^^^^^^
      # 스크립트 실행 시 가장하는 사용자
      ec2-user, root, ssm-user 중 하나를 선택할 수 있음

오랜 시간 삽질한 내용을 잠깐 짚고 넘어가려 한다. 위 appspec.yml을 main브랜치에 push 했을 때, 권한 문제 때문에 스크립트 파일을 실행시키지 못하고 있었고 사용자가 ssm-user로 접근하려 해서 hooks의 runas를 root로 해주었다. 권한문제가 있을 경우 해당문제를 잘 파악하기 바란다. 그리고 권한을 my-nest-app 폴더 하위의 모든 파일들에 권한을 줬다. 

sudo chmod 755 /home/ubuntu
sudo chown -R ubuntu:ubuntu /home/ubuntu

sudo mkdir -p /home/ubuntu/my-nest-app
sudo chown -R ubuntu:ubuntu /home/ubuntu/my-nest-app
sudo chmod -R 755 /home/ubuntu/my-nest-app

hooks의 -location: scripts/exec.sh를 보면 scripts 폴더밑에 exec.sh파일을 실행시킬 것이다.

프로젝트의 루트경로에 scripts폴더가 있다.