개발일지

AWS Lightsail로 CI/CD 구축하기_2. Github Actions으로 배포 자동화 파이프라인 구축하기 본문

Infra, AWS, Linux

AWS Lightsail로 CI/CD 구축하기_2. Github Actions으로 배포 자동화 파이프라인 구축하기

lyjin 2024. 6. 16.

개요

이제 Github Actions를 사용해 수정된 코드가 Github에 올라올 때마다 실서버에도 자동 반영할 수 있는 파이프라인을 구축해보자.

 


 

먼저 프로젝트의 .github/workflows 경로에 yml 파일을 생성한다. 다음과 같이 CI, CD flow를 독립적으로 관리할 것이다.

project
└── .github
    └── workflows
        ├── ci.yml
        └── cd.yml

 

 


Continuous Integration (CI)

CI는 “지속적 통합”, 즉 개발자들이 코드 변경 사항을 주기적으로 중앙 저장소(Github)로 통합하는 프로세스를 의미한다. 자동화 된 빌드 및 테스트로 코드의 품질을 보장하고 혹시 모를 에러를 조기 발견할 수 있도록 도와준다.

name: test        # 워크플로우 이름

on: pull_request  # pull request가 발생할 때 실행 됨

jobs:
  test:
    runs-on: ubuntu-22.04  # 가상머신에 사용할 운영체제 버전
    steps:
      - name: Checkout repository    # 해당 repo로 체크아웃
        uses: actions/checkout@v3    # 해당 action 사용

      - name: Node.js setup          # Node.js 설치
        uses: actions/setup-node@v3  # 해당 action 사용
        with:
          node-version: '18'

      - name: Install npm packages   # 패키지 설치
        run: npm ci

      # 기타 필요한 프로세스 정의
      - name: Install and run redis-server
        run: |
          T

      - name: Run test
        run: npm run test:ci  # 테스트 수행

      - name: Run build
        run: npm run build    # 빌드 수행

 

 

파일 생성 완료 후, 이제 PR을 날려보면 해당 워크플로우가 실행되는 것을 확인할 수 있다.

 

진행 상황도 확인할 수 있다.

 


CD (Continuous Delivery/Deployment)

CD는 “지속적 제공(Delivery)” 또는 “지속적 배포(Deployment)”로 빌드 및 배포 과정을 자동화하여 최종 상용화 서버로 릴리즈 하는 것을 의미한다.

 

스크립트 전반적인 내용을 먼저 살펴본 뒤 세부적인 내용을 설명하겠다.

name: deploy

on:  # main 브랜치로 push가 발생할 때 실행 됨
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-22.04
    steps:
      # 상용화 서버로 SSH 접속하기 위한 키 설정
      - name: Set up SSH
        run: |
          mkdir -p ~/.ssh/
          echo "${{secrets.SSH_SECRET_KEY}}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa

      - name: Set up known hosts
        run: |
          echo "${{secrets.SSH_KNOWN_HOSTS}}" >> ~/.ssh/known_hosts
          chmod 644 ~/.ssh/known_hosts

      # 상용화 서버 접속 및 프로젝트 실행 (배포)
      - name: SSH and deploy
        run: |
          ssh ${{secrets.SSH_USERNAME}}@${{secrets.SSH_PUBLIC_IP}} "
          cd "project"

          git pull origin main || exit 1
          npm install || exit 1
          npm run build || exit 1
          sudo npm run start || exit 1  # pm2 reload all
          exit
          "

 

 

SSH 접속을 위한 키 설정하기

우리가 로컬에서 상용화 서버로 접속할 때 SSH 키가 필요했던 것처럼 Github action VM에서 상용화 서버로 접속하기 위해서도 SSH 키가 필요하다. 로컬에서는 터미널로 직접 SSH 키 파일을 생성해줄 수 있었지만 VM에서는 그럴 수가 없다. 따라서 워크플로우가 실행될 때 등록할 키 내용을 복제하고 생성할 수 있도록 작성했다.

 

여기서 유의할 점은 SSH 개인 키 같이 민감한 정보들은 외부에 노출 되어서는 안된다는 것이다. 다행히도 우리가 로컬에서 개발할 때 .env 파일로 환경변수를 관리했던 것처럼 Github에도 동일한 기능을 제공해주고 있다.

 

 

Github Secrets

Repo > Settings > Security > Secrets > Actions 탭 > New repository secret을 클릭해서 환경변수를 등록해주자.

  • SSH_SECRET_KEY: 상용화 서버 접속하기 위한 SSH 개인 키 (서버 측에서 클라이언트를 인증하기 위함)
  • SSH_KNOWN_HOSTS: 상용화 서버의 호스트 키 정보 (클라이언트 측에서 서버를 신뢰하기 위함)
  • SSH_USERNAME: 상용화 서버의 username
  • SSH_PUBLIC_IP: 상용화 서버의 Public IP 주소

이제 워크플로우에서 ${{secrets.SSH_SECRET_KEY}}의 형태로 접근이 가능하다.

 

 

known_hosts

known_hosts는 SSH 클라이언트에서 사용되는 파일로 클라이언트가 이전에 접속했던 호스트 키를 저장한다. 이후 동일한 호스트에 접속할 때 호스트에 대한 신뢰성을 검증하는 데 사용된다.

 

우리가 처음 로컬에서 상용화 서버로 접속했을 때를 생각해보면 “… Are you sure you want to continue connecting (yes/no)?” 이런 문구가 뜨고 당연히 yes를 입력했을 것이다. 이때 동의 하면 해당 호스트 키가 known_hosts 파일에 추가되기 때문에 이후론 경고 없이 접속 가능했던 것이다. 하지만 워크플로우는 실행될 때마다 새로운 VM에서 진행된다. 우리가 직접 동의해줄 수 없기 때문에 known_hosts에 상용화 서버의 호스트키를 등록해줘야한다.

 

호스트 키는 아래의 명령어로 확인할 수 있다. 출력되는 내용을 SSH_KNOWN_HOSTS 값으로 넣어주면 된다.

$ ssh-keyscan "public-ip"

 

 

이제 main 브랜치로 push될 때마다 해당 워크플로우가 실행 된다.

 

ㅎ.. 에러 내역도 확인할 수 있다.

 


마무리

이렇게 배포 자동화까지 구축해봤는데 CD에서 계속 에러가 난다. 추측해봤을 때 npm run build 할 때 노드 버전이 안맞아서 그런 거 같은데 이유를 모르겠다. 분명 CI에서는 성공했고 혹시 몰라 node 버전 설정까지 다 해줬는데 왜 지맘대로 12버전 사용하냐고ㅜ 이래서 도커를 사용하는게 아닐까..?