단 1시간만 투자해서 간단한 CI / CD를 진행해 보자!
Github actions만으로도 CI / CD를 할 수 있지 않을까?
아래의 화면으로 이동하고 초록색 버튼인 New self-hosted runner를 선택한다.
EC2의 운영체제가 Ubuntu이기에 Runner image의 2번째에 있는 Linux를 선택한다.
Architecture는 그대로 사용하고 Download, Configure의 내용을 하나씩 복사해 EC2에서 실행한다.
Configure의 마지막에 있는 ./run.sh 명령어는 nohup ./run.sh & 로 실행한다.
./run.sh로 실행하면 해당 터미널에서 다른 작업을 할 수 없을뿐더러 터미널을 종료하면 run.sh도 종료된다. nohup ./run.sh &는 run.sh를 백그라운드에서 실행시키겠다는 의미이다.
.env를 github에 올릴 수는 없으니 환경변수를 따로 추가해 준다.
아래의 화면으로 이동해 초록색 버튼인 New repository secret을 눌러 환경변수를 추가할 수 있다.
한번 환경변수를 추가하면 그 내용을 다시 볼 수는 없고 수정과 삭제만 가능하다.
우선 CI를 위한 push.yml을 작성한다.
해당 repository의 바로 아래에 .github/workflows/push.yml 경로로 파일을 생성한다.
Yaml파일 작성 간에 띄어쓰기를 잘못하면 오류가 발생하니 주의해야 한다.
이제 yml 파일을 작성해 보자.
name: push
on:
push:
branches-ignore: [main, develop]
jobs:
test:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@main
- name: Setup Node
uses: actions/setup-node@main
with:
node-version: '18'
- name: Install npm packages
run: npm ci
- name: Test
run: npm run test
name은 작업의 이름을 정의한다.
on은 어떤 순간에 해당 workflow가 실행되는지 설정할 수 있으며 내 경우에는 main branch와 develop branch 이외의 branch에 push 되는 순간 해당 workflow가 실행되도록 설정했다.
jobs에는 workflow의 작업 내용을 작성할 수 있다. 나는 push 간 test만을 진행할 것이기에 test라 이름 지었다.
runs-on은 해당 코드가 실행되는 환경으로 EC2의 운영체제를 적는다.
steps에는 실행하고자 하는 작업을 순서대로 적으면 된다.
uses는 github actions에서 만들어둔 steps를 가져다 쓰는 것으로 checkout은 내 repository의 최신 branch를 가져오고, setup-node는 node를 설치한다.
추가로 with를 사용해 node의 버전을 지정했다.
아후 npm ci로 package-lock.json의 파일을 설치하고 npm run test로 테스트를 진행했다.
다음은 CD를 위한 yml 파일을 작성한다.
마찬가지로 해당 repository의 바로 아래에 .github/workflows/deploy.yml 경로로 파일을 생성한다.
name: deploy
on:
push:
branches: [main]
env:
SERVER_PORT: ${{ secrets.SERVER_PORT }}
DB_AWS_HOSTNAME: ${{ secrets.DB_AWS_HOSTNAME }}
DB_PORT: ${{ secrets.DB_PORT }}
DB_USERNAME: ${{ secrets.DB_USERNAME }}
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
DB_DATABASE: ${{ secrets.DB_DATABASE }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
JWT_EXPIRE: ${{ secrets.JWT_EXPIRE }}
HASH_SALT: ${{ secrets.HASH_SALT }}
AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.AWS_REGION }}
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
jobs:
deploy:
runs-on: ['self-hosted', 'Linux', 'X64']
steps:
- name: Checkout
uses: actions/checkout@main
- name: Install npm packages
run: npm ci
- name: Build
run: npm run build
- name: Kill process
run: fuser -k ${{ secrets.SERVER_PORT }}/tcp || true
- name: Run background
run: RUNNER_TRACKING_ID="" && nohup npm run start:prod &
중복되는 설명은 생략한다.
해당 workflow는 main branch에 push되는 순간에만 동작한다.
다른 branch에서 main에 merge하는 순간도 포함된다.
env에는 github에서 설정한 환경변수를 ${{ secret.ENVIRONMENT }} 형식으로 가져올 수 있다.
jobs를 deploy로 이름짓고 runs-on에 runner의 정보를 작성한다.
npm run build까지는 이전 설명과 동일하다.
fuser -k ${{ secrets.SERVER_PORT }}/tcp || true
이 명령어는 해당 포트를 사용 중인 프로세스가 있다면 해당 프로세스를 종료한다는 의미이다. 종료할 프로세스가 없어도 오류를 발생시키지 않고 다음 단계로 넘어간다.
RUNNER_TRACKING_ID="" && nohup npm run start:prod &
이 명령어는 runner가 종료되어도 해당 runner에 의해 실행된 프로세스를 살려두기 위해 작성되었다.
RUNNER_TRACKING_ID를 빈 문자열로 초기화하지 않으면 해당 서버를 백그라운드에서 실행하는 nohup npm run start:prod & 명령을 실행해도 runner가 종료됨과 함께 해당 프로세스도 종료된다.
이 방법이 올바른 방법인지는 모르겠지만 CI / CD를 할 수 있는 가장 간단한 방법임은 틀림없을 것이다.
앞으로 DevOps를 공부하다 보면 이 글의 방법이 부적절하다 생각하게 될 수도 있겠지만, 다른 복잡한 것은 사용하지 않고 github actions만으로 CI / CD를 하고 싶은 사람이 있다면 이 글이 도움이 되길 바란다.