Cloud Service/AWS 공부

[CICD] Github Action으로 CICD 구축하기 4)

Queen Julia 2023. 10. 28. 20:29

1. 들어가며..


이번 시간에는 가장 널리 사용되는 CICD 플랫폼 중 하나인 Github Action을 사용하여 간단한 CICD Pipeline을 구축해봄으로써 CICD의 실제 작동 방법을 학습하겠습니다.

Github Action을 사용하여 빌드, 테스트를 해보고 더 나아가 docker image까지 빌드 및 push까지 구현해 봅니다. 그 다음 과정인 실제 배포는 CICD나 Github Action에 관한 내용을 넘어서서 실제 인프라 (예시: AWS)에 대한 이해도와 설정 방법까지 알아야 하므로 이번 세션에서는 다루지 않습니다. AWS 배포 부분까지 구현에 관심이 있으신 분들은 공식 문서를 참조하실 수 있습니다.

이번 세션의 목적은 간단한 CICD를 구축하여 CICD의 작동 방법과 구조를 조금 더 자세히 이해하기 위함 입니다. Github Action에 대해 자세히 다루는 목적은 아니므로 Github Action의 기본적인 문법만 설명합니다. Github Action의 자세한 내용은 공식 문서를 참조하세요.

2. Github Action의 장점


Github Action은 깃허브에서 제공하는 CICD 플랫폼입니다. 즉, Github Action을 사용하여 CICD를 구축할 수 있습니다. CICD를 구축할 수 있게해주는 CICD 플랫폼은 다양하게 있지만 Github Action의 장점은 CICD를 손쉽게 구축할 수 있다는 점입니다. Github Action만 사용하면 서버나 기타 다른것들을 구축할 필요 없이 간단한 설정 파일만으로도 Github안에서 CICD를 구현할 수 있기에 편리합니다.

Github Action은 Github 내에서 쉽게 사용할 수 있다는 장점 때문에 널리 사용되고 있는 CICD 플랫폼 중 하나입니다. 또한 가격도 부담스럽지 않습니다. 개인적인 용도로는 무료로 사용 가능하고, 팀으로 사용해도 가격이 크게 비싸지 않은 점 또한 널리 사용되는 이유 중 하나입니다.

3. CICD Workflow


우리가 구현할 CICD workflow 순서는 다음과 같습니다:

  1. 새로운 코드를 추가 후 커밋과 push를 한다.
  2. Github에서 새로운 push 받으면 자동으로 Github Action을 실행시킨다.
  3. 만일 develop 브랜치에 push 되었다면 CICD pipeline을 실행시킨다. Develop 브랜치가 아니라면 종료한다.
  4. 먼저 새로운 코드를 checkout 한다.
  5. 그 후 빌드 후 Unit Test를 실행 시킨다.
  6. Unit Test가 전부 통과하면 docker image를 빌드한다.
  7. Docker image가 성공적으로 빌드 되면 dockerhub에 푸쉬한다.

그림 [3-1] Github Action 작업 흐름도

4. Project Setup


먼저 배포할 수 있는 코드가 있어야겠지요? Github Action을 이용한 CICD 구축 방법을 학습하는 것이 주 목적이므로 application 자체는 아주 간단하게 ExpressJS의 Hello World 예제를 사용하도록 하겠습니다.

먼저 expressjs 와 jest 를 설치하겠습니다.

$ npm install express
$ npm install --save-dev jest

그 다음 server.js 파일을 구현합니다.

// server.js
const express = require('express')
const app     = express()
const port    = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

개발자가 커밋을 푸쉬를 했을때 Github Action을 통해서 자동으로 Unit Test가 실행되는지 확인하기 위해 dummy unit test도 작성해 보겠습니다.

// test.js
test('Dummy Unit Test For Github Action Testing', () => {
  expect(1).toBe(1);
});

다음은 docker image 빌드를 위한 Dockerfile이 필요합니다.

# Dockerfile

FROM node:latest

WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 3000
CMD [ "node", "server.js" ]

마지막으로 Github Action을 설정합니다. Github Action 설정은 Github의 리포지토리 페이지에서 Action 탭을 통해 할 수 있습니다.

그림 [4-1] Github Action 탭 버튼 위치

미리 설정된 여러 workflow중에 하나를 선택하면 됩니다. 저희는 node.js 애플리케이션 이므로 node용 workflow를 선택하면 됩니다. 검색창에 “Node.js”를 입력하고 검색을 한후 Node.js 용 workflow를 선택합니다.

그림 [4-2] node.js 용 workflow 선택란 예시

이제 화면에서 github action 설정 파일 수정을 할 수 있는 화면이 나옵니다. 오른쪽 사이드바에는 자세한 안내 문서도 나와 있습니다. 다음과 같이 파일을 수정합니다:

name: Node.js CI

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

jobs:
  build:
    name: build and test
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [12.x, 14.x, 16.x]
        # See supported Node.js release schedule at <https://nodejs.org/en/about/releases/>

    steps:
    - uses: actions/checkout@v3
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v3
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
    - run: npm ci
    - run: npm run build --if-present
    - run: npm test
    
  docker-push:
    name: docker build and push
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v1
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v1
      - name: Login to DockerHub
        uses: docker/login-action@v1 
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      - name: Build and push
        uses: docker/build-push-action@v2
        with:
          push: true
          tags: mydockerhub/github-action-test:latest

Github action 설정은 YAML로 구현되어 있으며, 특별히 문법을 알지 못해도 이해가 가능합니다. 하지만 그래도 몇가지 중요한 부분을 설명해보도록 하겠습니다.

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  • Github action workflow가 언제 실행되어야 하는지를 명시합니다. 우리의 경우에는 main 브랜치에 push 나 PR이 있을 경우 github action workflow를 실행하라고 명시되어 있습니다.
jobs:
  build:
    name: build and test
    runs-on: ubuntu-latest

....

  docker-push:
    name: docker build and push
    needs: build
    runs-on: ubuntu-latest
  • Workflow가 시작 됬을 경우 실행되어야 하는 실제 작업들을 명시합니다. 우리의 경우 크게 2개의 작업(job)이 명시되어 있습니다. builddocker-push 라는 작업이 명시되어 있습니다.
  • needs 구문은 해당 job 이 실행되기 전에 먼저 실행되어야 하는 job 을 명시합니다. 우리의 경우 docker-push 가 실행되기 전에 build 가 먼저 실행되어야 한다고 명시해 놓았습니다.
  • runs-on 구문은 어떤 환경에서 해당 job 들이 실행되어야 하는지 명시합니다. 우리의 경우 최신 우분투에서 실행되도록 명시되어 있습니다.
    strategy:
      matrix:
        node-version: [12.x, 14.x, 16.x]
        # See supported Node.js release schedule at <https://nodejs.org/en/about/rele이제>
  • job 이 실행될때의 다양한 전략이나 구성을 명시할 수 있습니다. 우리의 경우 node의 버젼을 한 버젼 뿐만이 아니라 12, 14, 16 이렇게 3개의 버전 모두 실행 시킬 수 있습니다. 특정 버전 뿐만이 아니라 하위 버전들 에서도 문제가 없이 실행되는지를 한번에 확인할 수 있습니다.
      - name: Login to DockerHub
        uses: docker/login-action@v1 
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
  • Dockerhub에 push하기 위해서는 먼저 dockerhub에 로그인이 필요합니다. 그리고 로그인을 하기 위해서는 dockerhub의 아이디와 비밀번호가 필요 하겠죠? 위 부분의 secrets.DOCKERHUB_USERNAMEsecrets.DOCKERHUB_TOKEN 는 Github의 Secrets 설정 페이지에 미리 추가해놓아야 사용할 수 있습니다.

그림 [4-3] Github Action상 Dockerhub 개인정보 설정버튼 위치그림

[4-4] Github Action상 Dockerhub 개인정보 입력란그림

[4-5] Github Action상 Dockerhub 개인정보 입력 상태 확인

5. Github Action Trigger


Github Action 설정이 끝났으면 이제 드디어 실제 실행을 시켜볼 차례 입니다. main 브랜치에 push나 PR을 하면 Github Action workflow가 자동으로 실행되는 것을 Action 탭에서 볼 수 있습니다.

그림 [5-1] Github Action 자동 동작 모습

오른쪽의 각 job 을 나타내는 박스를 클릭하면 자세한 진행 사항 로그도 볼 수 있습니다.

그림 [5-2] Github Action 진행사항 로그 확인