개발 첫 주 차에는 마지막 금요일에 배포를 성공하고 말았었는데, 점점 갈수록 만들어야 하는 API도 많이 생기고 클라이언트에서 급하게 요구하는 수정 사항, 추가 사항들이 생긴다.
그 부분들을 모두 커버하고 배포하는 과정에서 반복적으로 배포를 해야 하는 불필요한 중복이 생기므로 굉장히 귀찮기도 하고 시간도 많이 들뿐더러 배포 과정에서 실수가 생긴다면 다시 인프라에 잡혀서 시간을 써야 한다.
그래서 실수도 줄여주고 반복적인 배포과정을 알아서 해주는 자동 배포를 비교적 프로젝트 초반인 지금 하기로 결정했다.
자동 배포 도구에는 대표적으로 Jenkins, GitHub Actions 가 있다.
그 중 Jenkins 는 플러그인이 굉장히 많지만, 설정과 유지가 비교적 어려워서 자동 배포 구현에 큰 시간을 들일 수 없는 현재 상황에서 부담스러웠고 GitHub Wiki, Project, Issue 등 GitHub 를 적극적으로 사용하면서 많은 일들을 처리하고 있어서 GitHub Actions 를 사용하는 것이 장점이 많아보였다.
따라서 GitHub Actions 를 선택하게 되었다.
name: Server CD
on:
pull_request:
branches: [ "develop", "main" ]
paths:
- "server/**"
types:
- closed
jobs:
deploy:
runs-on: ubuntu-20.04
strategy:
matrix:
node-version: [20.x]
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
cache-dependency-path: '**/package-lock.json'
- name: Install depenencies
run: |
cd server
npm install
- name: Create prod.env file
env:
DB_HOST_IP: ${{ secrets.SERVER_ENV_DB_HOST_IP }}
DB_PORT: ${{ secrets.SERVER_ENV_DB_PORT }}
DB_USER_NAME: ${{ secrets.SERVER_ENV_DB_USER_NAME }}
DB_PASSWORD: ${{ secrets.SERVER_ENV_DB_PASSWORD }}
DB_DATABASE_NAME: ${{ secrets.SERVER_ENV_DB_DATABASE_NAME }}
ACCESS_ID: ${{ secrets.SERVER_ENV_ACCESS_ID }}
SECRET_ACCESS_KEY: ${{ secrets.SERVER_ENV_SECRET_ACCESS_KEY }}
JWT_SECRET_KEY: ${{ secrets.SERVER_ENV_JWT_SECRET_KEY }}
run: |
cd server
touch prod.env
echo "DB_HOST_IP=$DB_HOST_IP" >> prod.env
echo "DB_PORT=$DB_PORT" >> prod.env
echo "DB_USER_NAME=$DB_USER_NAME" >> prod.env
echo "DB_PASSWORD=$DB_PASSWORD" >> prod.env
echo "DB_DATABASE_NAME=$DB_DATABASE_NAME" >> prod.env
echo "ACCESS_ID=$ACCESS_ID" >> prod.env
echo "SECRET_ACCESS_KEY=$SECRET_ACCESS_KEY" >> prod.env
echo "JWT_SECRET_KEY=$JWT_SECRET_KEY" >> prod.env
- name: Build Docker image
run: docker build --platform linux/amd64 ./server -t ${{ secrets.NCP_REGISTRY }}/catchy-tape:latest
- name: Login NCP container registry
run: docker login ${{ secrets.NCP_REGISTRY }} -u ${{ secrets.NCP_DOCKER_ACCESS_KEY_ID }} -p ${{ secrets.NCP_DOCKER_SECRET_KEY }}
- name: Push Docker image to registry
run: docker push ${{ secrets.NCP_REGISTRY }}/catchy-tape:latest
- name: SSH into Server
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_SSH_HOST }}
username: ${{ secrets.SERVER_SSH_USER }}
password: ${{ secrets.SERVER_SSH_PASSWORD }}
port: ${{ secrets.SERVER_SSH_PORT }}
script: |
docker login ${{ secrets.NCP_REGISTRY }} -u ${{ secrets.NCP_DOCKER_ACCESS_KEY_ID }} -p ${{ secrets.NCP_DOCKER_SECRET_KEY }}
docker pull ${{ secrets.NCP_REGISTRY }}/catchy-tape:latest
docker stop catchy-tape-latest
docker rm catchy-tape-latest
docker run -d -p 3000:3000 --name catchy-tape-latest ${{ secrets.NCP_REGISTRY }}/catchy-tape:latest
curl -X POST -H 'Content-type: application/json' --data '{"text":"서버 배포 성공!"}' ${{ secrets.SLACK_WEBHOOK_URL }}
위 yaml 파일을 보면 어떤 순서로 배포가 이루어지는지 대충 알 수 있다.
Checkout repository → Set up Node.js → Install depenencies → Create prod.env file → Build Docker image → Login NCP container registry → Push Docker image to registry → SSH into Server 의 단계로 이루어져 있다.