버튼 클릭으로 GitHub Action을 실행하고 싶었습니다.
GitHub Action을 실행하는 방법에는 push로 자동 실행하거나, 버튼을 클릭하여 수동으로 실행하는 방식이 있습니다.
push 방식의 단점은 단 한 번만 실행된다는 점입니다.
물론 실패한 Action이라면 다시 재실행할 수 있지만, 그럼에도 불구하고 버튼 클릭 방식이 본래의 목적에 더 부합한다고 생각했습니다.
그래서 버튼 클릭으로 GitHub Action을 실행하는 방법을 개발하고, 이를 기록해두려 합니다.
테스트는 제가 개인 프로젝트로 진행 중인 Qosmo-API를 대상으로 생성할 예정입니다.
https://github.com/cwadven/Qosmo-API/actions
[참고사항]
GitHub Action을 설치하기 위해 self-hosted runner를 사용했습니다.
sudo
명령어를 실행할 수 있도록 하기 위해, runner 설정 시 아래와 같이 명령어를 실행했습니다:
# sudo 권한으로 전부 실행
sudo su -
# 다운로드 받은 파일 위치로 가기
sudo RUNNER_ALLOW_RUNASROOT="1" ./config.sh --url https://github.com/cwadven/Qosmo-API --token xxxxxxxxxxxxxxxxxxxx
sudo RUNNER_ALLOW_RUNASROOT="1" ./run.sh
sudo RUNNER_ALLOW_RUNASROOT="1" ./svc.sh install
sudo RUNNER_ALLOW_RUNASROOT="1" ./svc.sh start
# 잘되는지 확인
sudo RUNNER_ALLOW_RUNASROOT="1" ./svc.sh status
# 만약 status 부분에서 에러가 난다면 권한 수정이 필
sudo chown -R $(whoami):$(whoami) /path/to/actions-runner
chmod -R 755 /path/to/actions-runner
지금은 Actions 탭에 들어가도, 위에서 설명한 workflow_dispatch
기능이 보이지 않습니다.
workflow_dispatch
기능을 적용하면, 버튼 클릭으로 GitHub Action을 수동 실행할 수 있습니다.
프로젝트 루트 디렉터리에 .github/workflows/deploy.yml
파일을 생성합니다.
workflow_dispatch
를 적용합니다저는 deployment-type
이라는 이름으로 input 값을 받을 예정이며, 이 값을 기반으로 어떤 서버에 배포할지 결정하려고 합니다.
(지금은 라이브 밖에 없어서 productino 만 넣습니다.)
name: Deploy
on:
workflow_dispatch:
inputs:
deployment-type:
type: choice
description: 'Which server to deployment type'
required: true
default: 'production'
options:
- production
짜잔 생겼습니다~
이렇게도 나왔네요.
이제 배포 스크립트를 작성하기 전에, 여러 사람이 동일한 action 방지를 위해서 concurrency 를 보장하기 위해 아래와 같이 넣습니다.
name: Deploy
on:
workflow_dispatch:
inputs:
deployment-type:
type: choice
description: 'Which server to deployment type'
required: true
default: 'production'
options:
- production
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
github action 에서 쓸 Secret 을 Actions Secret 에 정의하고 시작 합시다.
github 에 접근 권한이 있어야하기 때문에 github token 도 생성합니다.
Settings 에서 Developer settings 접속
Tokens 접속
Generate new token 클래식
권한 다 체크 한 후, 생성합니다.
생성된 토큰을 github action 에서 쓸 Secret 에 추가로 등록합니다.
자 이제 그럼 배포를 하기 위해서 배포 flow 에 필요한 명령어를 작성해 봅시다.
name: Deploy
on:
workflow_dispatch:
inputs:
deployment-type:
type: choice
description: 'Which server to deployment type'
required: true
default: 'production'
options:
- production
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
DJANGO_SETTINGS_MODULE: "config.settings.production"
jobs:
setup-git:
runs-on: self-hosted
steps:
- name: Set Safe Directory
run: |
git config --global --add safe.directory "${{ secrets.PRODUCTION_PROJECT_FILE_PATH }}"
pull-code:
needs: setup-git
runs-on: self-hosted
env:
GITHUB_TOKEN: ${{ secrets.TOKEN }}
steps:
- name: Pull Branch
run: |
cd ${{ secrets.PRODUCTION_PROJECT_FILE_PATH }} && sudo git checkout ${{ github.ref }} && sudo git pull origin ${{ github.ref }}
update-dependencies:
needs: pull-code
runs-on: self-hosted
steps:
- name: pip Update
run: |
cd ${{ secrets.PRODUCTION_PROJECT_FILE_PATH }} && . ${{ secrets.PRODUCTION_PROJECT_FILE_PATH }}/venv/bin/activate && pip install -r ${{ secrets.PRODUCTION_PROJECT_FILE_PATH }}/requirements.txt
collect-static:
needs: update-dependencies
runs-on: self-hosted
steps:
- name: Collectstatic
run: |
cd ${{ secrets.PRODUCTION_PROJECT_FILE_PATH }} && . ${{ secrets.PRODUCTION_PROJECT_FILE_PATH }}/venv/bin/activate && python ${{ secrets.PRODUCTION_PROJECT_FILE_PATH }}/manage.py collectstatic --noinput
database-migrate:
needs: collect-static
runs-on: self-hosted
steps:
- name: Database Update
run: |
cd ${{ secrets.PRODUCTION_PROJECT_FILE_PATH }} && . ${{ secrets.PRODUCTION_PROJECT_FILE_PATH }}/venv/bin/activate && python ${{ secrets.PRODUCTION_PROJECT_FILE_PATH }}/manage.py migrate --noinput
update-cron:
needs: database-migrate
runs-on: self-hosted
steps:
- name: cronjob command update
run: |
cd ${{ secrets.PRODUCTION_PROJECT_FILE_PATH }} && . ${{ secrets.PRODUCTION_PROJECT_FILE_PATH }}/venv/bin/activate && fab2 update-crontab
continue-on-error: true
restart-cron:
needs: update-cron
runs-on: self-hosted
steps:
- name: cronjob restart
run: |
cat ${{ secrets.PRODUCTION_PROJECT_FILE_PATH }}/command.cron | sudo crontab -
sudo /etc/init.d/cron reload
continue-on-error: true
restart-celery:
needs: restart-cron
runs-on: self-hosted
steps:
- name: celery restart
run: |
sudo /etc/init.d/celeryd restart
continue-on-error: true
restart-web-server:
needs: restart-celery
runs-on: self-hosted
steps:
- name: Restart web server
run: |
sudo systemctl restart nginx
sudo systemctl restart gunicorn
위와 같이 정의했습니다.
작동을 시키니 아주 잘 돌아갑니다.
이제 버튼 클릭으로 스테이징 배포 혹은 라이브 배포가 가능합니다.
지금은 self hosted 를 라이브 서버에 설치해서 라이브든 스테이징이든 라이브가 배포되겠지만 이걸 한번더 나누려면 self hosted 를 나눠서 설정하면 될것 같습니다.