Github Workflow로 블로그 배포 자동화하기
Written in 2022/11/20 09:42:36 UTC, categoried as web
배포가 귀찮아졌다
내 블로그는 이전에 언급했다시피, Elder.js
라는 SSG
프레임워크로 빌드된다. 이 때 해야할 일이 꽤 많은 관계로, 나는 내 블로그를 아래와 같이 저장소 두 개로 분리해 구성했다.
devlog-posts
: 블로그 포스트를 관리한다. 포스트를 생성하고 빌드하는 모든 과정이 여기에서 일어난다.devlog-ssg
: 블로그의 전반적인 레이아웃 및SSG
빌드를 담당한다.devlog-posts
의 빌드된 컨텐츠를 참조하기 위해submodule
로 가지고 있다.
그런데 이 구성에서는 포스트 하나를 쓸 때마다 devlog-posts
는 물론이고 devlog-ssg
도 수동으로 머지하고, 빌드하고, 배포해야 한다. 이러기엔 너무 귀찮으니까, 이참에 github workflow
를 써서 자동으로 머지하고, 빌드하고, 배포하도록 구성해봤다.
Submodule 업데이트 하기
먼저 devlog-posts
(앞으로 자식
이라 한다) 저장소에 변경 사항이 발생하면, devlog-ssg
(편의상 앞으로 부모
라 한다) 저장소의 모든 submodule
을 업데이트 하고 해당 업데이트 커밋을 기록해야 한다. 이를 위해서 양쪽 모두에 github workflow
를 적용했다.
# .github/workflows/trigger.yaml of the child side
on:
workflow_dispatch:
push:
branches:
- main
jobs:
notify:
name: Notify Parent
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
- name: Github REST API Call
run: |
curl -fL --retry 3 -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token ${{!env!}}" https://api.github.com/repos/${{!env!}}/actions/workflows/${{!env!}}/dispatches -d '{"ref":"${{!env!}}"}'
env:
CI_TOKEN: ${{!span!}}
PARENT_REPO: ${{!span!}}
PARENT_BRANCH: main
WORKFLOW_ID: ${{!span!}}
# .github/workflows/deploy.yaml of the parent side
on:
workflow_dispatch:
push:
branches:
- 'main'
jobs:
submodule-update:
name: Submodule Update
runs-on: ubuntu-latest
defaults:
run:
shell: bash
steps:
- name: Checkout
uses: actions/checkout@v3
with:
token: ${{!span!}}
submodules: true
- name: Git Sumbodule Update
run: |
git pull --recurse-submodules
git submodule update --remote --recursive
- name: Commit Update
run: |
git config --global user.name 'Git bot'
git config --global user.email 'bot@noreply.github.com'
git remote set-url origin https://x-access-token:${{!secrets!}}@github.com/${{!github!}}
git commit -am "[no ci]: automatic update of submodule references" && git push || echo "No changes to commit"
전체적인 흐름은 보시다시피 아주 간단하다. 자식이 Github
의 REST API
를 호출하면, 부모의 workflow
를 Github
가 실행해 준다. 부모는 가지고 있던 모든 submodule
을 업데이트하고 커밋한다. 끝.
눈 여겨볼 점 하나: workflow id
자식이 부모의 workflow
를 참조할 때 workflow id
라는 식별자를 사용한다. 얘는 Github
가 할당해주는 모양인데 언제 변하는지는 잘 모르겠다. 일단 구성해본 결과, 왠만한 상황에서는 변하지 않는 것 같다. 이 workflow id
를 얻어오는 방법은 위 SO
링크를 참고하기 바란다.
눈 여겨볼 점 둘: no ci
- 부모의 yaml 파일을 잘 읽어보면, 마지막 커밋 단계에서 아래처럼 하고 있다.
git commit -am "[no ci]: automatic update of submodule references"
여기서 no ci
는 github workflow
에게 이 커밋은 무시하라고 알리는 지시어다. 이 문서에서 더 자세한 내용을 알 수 있다. 이 처리를 하지 않으면 이 workflow
가 두 번 도는 경우가 생긴다. 왜 두 번 도냐고? 그것은 본인이 생각해보기 바란다.
자동으로 배포하기
submodule
을 업데이트 했으니, 이제 배포를 알아서 해보도록 하자. 이 블로그는 AWS S3 + AWS CF
로 서빙되고 있다. 따라서 AWS CLI
를 사용하면 편리하다. github workflow
의 ubuntu-latest
는 현재 ubuntu 20.04
버전을 사용한다. 운이 좋게도, 여기에는 AWS CLI v2
가 미리 준비되어 있으므로 따로 설치하지 않아도 사용할 수 있다.
# .github/workflows/deploy.yaml of the parent side
on:
# ...
jobs:
# ...
deployment:
name: Deployment
runs-on: ubuntu-latest
needs: submodule-update
defaults:
run:
shell: bash
steps:
- name: Checkout
uses: actions/checkout@v3
with:
token: ${{!span!}}
ref: main
submodules: true
- name: Install Dependuncies
run: |
npm install
- name: Build Artifacts
run: |
npm run build
cp ./dist/favicon.ico ./dist-opt
cp ./dist/robots.txt ./dist-opt
cp ./dist/sitemap*.xml ./dist-opt
- name: Deploy to AWS
run: |
aws s3 rm --recursive s3://${{!secrets!}}
aws s3 cp --recursive dist-opt/ s3://${{!secrets!}}/
aws cloudfront create-invalidation --distribution-id ${{!secrets!}} --paths "/*"
env:
AWS_ACCESS_KEY_ID: ${{!span!}}
AWS_SECRET_ACCESS_KEY: ${{!span!}}
AWS_DEFAULT_REGION: ap-northeast-2
간단하다. 테스트해보면, 아주 잘 돌아간다.
눈 여겨볼 점 하나: needs
needs
구문을 활용해 이전 submodule-update
job
이 끝나기를 기다린다. 업데이트된 submodule
을 사용해야 올바르게 배포할 수 있기 때문이다.
눈 여겨볼 점 둘: ref: main
거의 항상 사용하는 checkout
action
에서 ref
를 주지 않으면 기본값으로 해당 workflow
를 트리거한 commit
이 잡힌다. 그러나 이전 workflow
에서 HEAD
를 업데이트 했을 가능성이 있으므로(submodule
을 업데이트 했음을 잊지 말자), 강제로 마지막 변경사항을 가져오도록 한다. 이렇게 해야 올바르게 배포할 수 있다.
Secret 점검, 배포
CI/CD
구성을 마친 뒤에는 항상 secret이 올바르게 설정되어 있는지 점검이 필요하다. 위 변경사항을 푸시하기 전에 꼭! 두 번 확인해 보자.
성공이다! 이제 배포의 고통으로부터 해방될 수 있다...
결론
이번에는 따로 시간을 내서 블로그 자동 배포를 구성해보았다. CI/CD
는 간만에 하느라 약간 헤메긴 했지만, 그래도 짬을 제법 먹었는지 큰 시간 소모 없이 완료했다. 다만 아직 아쉬운 부분도 있는데, 블로그 포스트 작성 후 빌드는 여전히 내가 직접 해야하는 점이 그렇다. 이건 약간 더 작업하면 되겠지만 오늘은 귀찮아서 더 못하겠다. 다음에 또 해야지~