git action 을 이용한 CI/CD 구축

2023. 4. 9. 15:50ETC/Git

학교에서 알파프로젝트를 진행하며 항상 새로운 것을 배우는 것을 목표로 하고 있다.

지난 학기 알파프로젝트에서는 Docker 컨테이너에 대해 학습하고 적용해 보았고 이번 프로젝트에서는 개발뿐 아니라 테스트 코드 작성 및 CI/CD 파이프라인을 간단하게 라도 시도해보고자 하였다.

 

CI / CD 파이프라인

CI/CD 란 Continuous Integration / Continuous Delivery를 의미한다. 지속적 통합, 지속적 배포라고도 불린다.

 

소프트웨어의 개발, 테스트, 배포를 통합하고 이를 자동화하는 것을 목표로 한다. 이를 이용하면 사용자가 개발한 코드에 대해서 직접 테스트를 하지 않더라도 CI/CD가 자동으로 테스트를 해주며 문제가 없을 시 배포까지 자동으로 연결되도록 진행할 수 있다.

 

저번 프로젝트를 진행할 때 AWS EC2에 ssh로 접속하여 서버에서 직접 코드를 pull 받아서 배포를 해본 경험이 있다. 하지만 테스트도 일일이 해야 하고 배포도 일일이 해야 되는 부분은 사용자가 실수할 수도 있고 시간도 많이 뺏기게 된다. 이런 단점을 CI/CD를 이용하여 극복할 수 있다.

 

Git Action

Git Action 이란 Github에서 제공하는 CI/CD 파이프라인 구축을 위한 플랫폼이다. CI/CD를 포함하고 PR을 올렸을 때도 정해놓은 workflow로 테스트를 해준다. 또한 이런 기능을 제공하기 위한 가상머신(Linux, Windows, MacOS)도 git에서 제공해 준다.

 

Git Action의 구성요소

1. Workflow

GitHub는 레포지토리의 .github/workflows 디렉터리에서 이벤트의 연결된 커밋 SHA 또는 Git 참조에 있는 워크플로 파일을 검색합니다.

 

Github는 repository 내부. github/workflows 디렉토리에서 워크플로 파일을 검색한다. workflow는. yml 혹은. yaml 파일의 YAML syntax를 이용한다. repository의 event에 의해 trigger 될 때 자동으로 실행되거나 수동으로 실행할 수 있습니다.

 

또한 repo에는 여러 개의 workflow가 들어갈 수 있습니다. 예를 들어서 pr이 생겼을 때 실행되는 workflow, main에 push 되어 자동으로 배포할 때 실행되는 workflow 등 여러 workflow를 동시에 사용할 수 있습니다.

자세한 workflow 사용법

 

2. Event

말 그대로 repository에서 어떤 event가 일어났는지를 보는 것이다. event가 일어나면 workflow를 실행시킨다.

pr을 만들거나, issue를 만들거나, commit을 푸쉬할 때 혹은 일정시간마다 배포를 진행하도록 스케쥴링할 수도 있다.

workflow를 실행시키는 events

 

3. Job

같은 runner에서 실행되는 일련의 과정이다. shell script가 실행될 수도 있고, 특정 일을 실행시킬 수도 있다. 테스트 코드의 실행, docker build 등을 할 수 있다.

자세한 job 사용법

 

4. Action

workflow에서 사용가능한 reusable한 코드이다. 모든 언어로 쓰일 수 있지만 흔히 Docker container JavaScript로 쓰인다. git에서 미리 만들어둔 Action들 혹은 shell 파일로 custom 하여 만들 수도 있다.

자세한 Action 만들기

 

5. Runners

workflow를 실행하는 서버라고 생각하면 된다. git은 Linux, Windows, MacOS를 기본적으로 제공하지만 사용자가 정의한 자체 러너를 사용할 수도 있다.

자세한 Runner에 관한 설명

 

main.yml

name: CICD # workflow 이름 지정

on:
  push:
    branches: [ main ] # main branch에 push될 때 workflow 실행

jobs:
  # 빌드
  build:
    runs-on: self-hosted # runner 지정 : custom runner 지정
    steps: #step 순서대로 실행됨
    
      # repository 파일을 runner에 받음
      - name: Checkout                # step의 이름 지정
        uses: actions/checkout@v3     # 사용할 action 설정(git이 제공하는 action으로 설정하였음)

      # .env파일 생성.
      - name: Generate Environment Variables File for Docker-compose
        run: |
          echo "POSTGRES_USER=$POSTGRES_USER" >> ./.env
          echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> ./.env
          echo "POSTGRES_PORT=$POSTGRES_PORT" >> ./.env
        env:
          POSTGRES_USER: ${{ secrets.POSTGRES_USER }}
          POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
          POSTGRES_PORT: ${{ secrets.POSTGRES_PORT }}

      - name: Generate Environment Variables File for settings.py
        run: |
          echo "DJANGO_SECRET_KEY=$DJANGO_SECRET_KEY" >> ./webapp/.env
          echo "DATABASE_LOCAL_NAME=$DATABASE_LOCAL_NAME" >> ./webapp/.env
          echo "DATABASE_LOCAL_USER=$DATABASE_LOCAL_USER" >> ./webapp/.env
          echo "DATABASE_LOCAL_PASSWORD=$DATABASE_LOCAL_PASSWORD" >> ./webapp/.env
          echo "DATABASE_LOCAL_HOST=$DATABASE_LOCAL_HOST" >> ./webapp/.env
          echo "DATABASE_LOCAL_PORT=$DATABASE_LOCAL_PORT" >> ./webapp/.env
          echo "KAKAO_REST_API_KEY=$KAKAO_REST_API_KEY" >> ./webapp/.env
          echo "KAKAO_REDIRECT_URI=$KAKAO_REDIRECT_URI" >> ./webapp/.env
        env:
          DJANGO_SECRET_KEY: ${{ secrets.DJANGO_SECRET_KEY }}
          DATABASE_LOCAL_NAME: ${{ secrets.DATABASE_LOCAL_NAME }}
          DATABASE_LOCAL_USER: ${{ secrets.DATABASE_LOCAL_USER }}
          DATABASE_LOCAL_PASSWORD: ${{ secrets.DATABASE_LOCAL_PASSWORD }}
          DATABASE_LOCAL_HOST: ${{ secrets.DATABASE_LOCAL_HOST }}
          DATABASE_LOCAL_PORT: ${{ secrets.DATABASE_LOCAL_PORT }}
          KAKAO_REST_API_KEY: ${{ secrets.KAKAO_REST_API_KEY }}
          KAKAO_REDIRECT_URI: ${{ secrets.KAKAO_REDIRECT_URI }}


  # 배포
  deploy:
    needs: build # 의존성 : build가 실행되고 나서 deploy 실행
    name: Deploy with Docker Compose
    runs-on: [ self-hosted, label-go ]
    steps:
      - name: Docker run
        run: |
          sudo docker-compose -f docker-compose.production.yml up -d --build

아직 테스트 코드를 작성하지 않아서 배포 자동화만 설정해 놓은 상태이다. 테스트 코드 작성 후 배포 이전 빌드에서 테스트를 하는 과정을 추가할 예정이다.

 

환경변수 등록

환경변수 같은 경우는 우리가 github에 올리지 않기 때문에 git action 실행을 위해 따로 등록을 해주어야 한다.

 

Repository - settings - Secrets and Variables - Actions 에 들어가 보자.

환경변수 등록
New repository secret 을 이용하여 환경변수를 추가하자!

New repository secret을 눌러서 

이런 식으로 등록을 해주면 workflow yml 파일에서 

${{ secrets.POSTGRES_USER }}

이런식으로 접근할 수 있다.

 

Runner 설정

runner를 그냥 ubuntu-latest 이런 식으로 설정해도 괜찮지만 나는 내 AWS EC2 서버의 컴퓨터 환경을 runner로 작동시키기 쉬웠기에 custom runner를 사용하기로 했다.

 

Repository - settings - Actions - Runners에 들어가 보자.

self-hosted runner 이용

New self-hosted runner를 클릭하면 이런 화면이 뜰 것이다.

EC2 환경을 Linux로 설정을 해주었기에 Linux를 골라주었고 적혀있는 command를 EC2에 접속해서 적어주면 된다.

./run.sh를 실행한 상태에선 git action이 자동으로 ec2와 연결되어 적용이 된다.

 

진짜 실행!

많은 시행착오가 있었다.. 나 같은 경우 오류의 내용은 build 할 때의 runner를 ubuntu로 적고 와 deploy 할 때의 runner를 self-hosted로 다르게 적어준 것이 이유였다. 구글링해도 나오지 않아서 힘들었지만,, 해결해 냈다.

 

main에 push 혹은 merge를 하니 자동으로 git action이 실행되고 나의 ec2 서버에서 docker compose build가 실행되어 자동으로 배포가 되는 것을 확인할 수 있었다.

 

진정한 CI/CD를 위해 조만간 test 코드까지 준비를 하여 pr를 올렸을 때도 적용할 수 있도록 해볼 것이다.