๐ Workflow ๊ตฌ์ฑ๋
โพ๏ธ ๋ฐฐํฌ ์ค๋น
1. ๋ธ๋์น ์์ฑ
์ด์ ์ [Deploy] ๊ฐ์์๋ฒ(Virtual Machine)์ node API ๋ฐฐํฌํ๊ธฐ - AWS Lightsail ํ๋ก์ ํธ์์ ์งํํ์๋ express ์ฑ์ ๊ทธ๋๋ก ์ฌ์ฉํ ๊ฒ์ด๋ค.
์ฐ์ ํ๋ก์ ํธ ๊ฒฝ๋ก๋ก ์ด๋ํ ํ "dev" ๋ธ๋์น๋ฅผ ์์ฑํ์.
$ git checkout -b dev # dev ๋ธ๋์น ์์ฑ ํ dev ๋ธ๋์น๋ก checkout
$ git branch # branch ๋ชฉ๋ก ๋ฐ ํ์ฌ checkout ๋์ด์๋ ๋ธ๋์น ํ์ธ
* dev
main
๊ทธ๋ฆฌ๊ณ main ๋ธ๋์น์์ ๋ชจ๋ ์์ค์ฝ๋๋ฅผ ๊ด๋ฆฌํ์๋๋ฐ, ์ด์ ๋ dev ๋ธ๋์น์์ ์ฝ๋ ์์ /์ถ๊ฐ ๋ฑ์ ํ ๊ฒ์ด๋ค.
app/index.ts ํ์ผ์ ์๋์ console ๋ฌธ์ ์ถ๊ฐํ๊ณ main ๋ธ๋์น๋ก PR์ ์์ฒญํ์.
# app/index.ts
...
const startServer = async () => {
console.log("trying to start server"); # ์ถ๊ฐ๋ ๋ถ๋ถ
const client = redis.createClient({ url: REDIS_URL });
await client.connect();
...
};
startServer();
์ฝ๋๋ฅผ ์์ ํ์ผ๋ฉด ๋ณ๊ฒฝ ์ฌํญ์ ์ปค๋ฐํ๊ณ github์ dev ๋ธ๋์น๋ก pushํ์.
$ git add .
$ git commit -m "[UPD] added starting messages"
$ git push -u origin dev
ํ๋ก์ ํธ์ ๊นํ๋ธ ๋ ํฌ์งํ ๋ฆฌ๋ก ์ด๋ ํ, dev ๋ธ๋์น๊ฐ ์๋ก ์๊ฒผ๋์ง ํ์ธํ์.
dev ๋ธ๋์น๊ฐ ์๋ก ์๊ธด ๊ฒ์ ํ์ธํ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ ๋์ dev ๋ธ๋์น์ ์์ /์ถ๊ฐ๋ ์ฝ๋๋ค์ main ๋ธ๋์น๋ก Pull Request(PR)์ ์์ฒญํด์ผํ๋ค.
'Pull Request' ํญ์ ๋ค์ด๊ฐ ํ 'New Pull Request'๋ฅผ ํด๋ฆญํ์.
์๋์ฒ๋ผ PR ๊ธฐ๋ก์ด ๋จ๊ณ ์ด๋ฒ PR์์ ์ด๋ค ์ฝ๋๋ค์ด ๋ณ๊ฒฝ๋๋์ง ์ธ์ธํ๊ฒ ์ ์๊ฐ ์๋ค. compare์ธ ๋ธ๋์น๋ฅผ 'dev'๋ก ์ก์์ฃผ๊ณ base ๋ธ๋์น๋ฅผ 'main'์ผ๋ก ์ก์์ฃผ์. Pull Request๋ฅผ ์์ฒญํจ์ผ๋ก์จ dev ๋ธ๋์น์ ์์ ์ฌํญ ๋๋ ์ถ๊ฐ๋ ์ฝ๋๋ค์ด main ๋ธ๋์น์ ์ ์ฉ๋ ์ ์๋์ง ์๋ณธ ๋ ํฌ์งํ ๋ฆฌ ์ฃผ์ธ์ด ํ๋จํ๋ ๊ฒ์ด๋ค.
"create pull request"๋ฅผ ํด๋ฆญํ์.
PR ๋ฉ์์ง๋ ์ฌ์ฉ์๊ฐ ๋ฌด์ผ ์์ ํ๊ณ ์ถ๊ฐํ๋์ง ์ ์ ์๋ ๋ฉ์์ง๋ก ์์ฑํ๋ฉด ๋๋ค.
๋ก์ปฌ ํฐ๋ฏธ๋๋ก ๋ค์ด๊ฐ์ dev ๋ธ๋์น์์ main ๋ธ๋์น ๋ด์ฉ์ ์๋กญ๊ฒ pull(code update) ํด์ค ํ push ํ์.
$ git pull origin main
$ git push -u origin dev
2. Workflow ์์ฑ
์ ์์ ์ผ๋ก PR์ด ๋๊ณ , Merge Conflict๊ฐ ๋ฐ์ํ์ง ์์ ์ํฉ์์์ github actions workflow๋ฅผ ์์ฑํด๋ณด์.
2-1. workflow ์์ฑ
ํ์ฌ ํ๋ก์ ํธ ๊ฒฝ๋ก์ .github/workflows/test.yaml
ํ์ผ์ ๋ง๋ค์ด์ฃผ๋๋ก ํ์.
$ mkdir -p .github/workflows
$ touch .github/workflows/test.yaml
ํ ์คํธ์ฉ workflow๋ฅผ ์์ฑํด๋ณด์.
name: test
on: pull_request
jobs:
test_job:
runs-on: ubuntu-22.04
steps:
- name: "1. Checkout repository"
uses: actions/checkout@v3
- name: "2. Node.js Setup"
uses: actions/setup-node@v3
with:
node-version: "18"
- name: "3. Install npm packages"
run: npm ci
- name: "4. Install and run redis-server"
run: |
sudo apt-get update -y
sudo apt-get install -y redis-server
redis-server --daemonize yes --requirepass test_env --port 6380
- name: "5. Run test"
run: npm run test
- name: "6. test build"
run: npm run build
๐ github actions ๋ฌธ๋ฒ์ ๋ค์ ๊ฒ์๊ธ์์ ํ์ธ ๊ฐ๋ฅํ๋ค.
๐ https://jaehyojjang.dev/categories/github-action-basic
2-2. workflow ๋ฐฐํฌ
workflow ์์ฑ์ด ๋ค ๋๋ฌ์ผ๋ฉด dev ๋ธ๋์น์์ commit & push ํ๋ฉด ๋๋ค.
$ git add .
$ git commit -m "added test github actions workflow"
$ git push -u origin dev
main ๋ธ๋์น๋ก PR ์์ฒญ
main ๋ธ๋์น๋ก PR์ ์์ฒญํ๋ ์์์ ์์ฑํ๋ workflow๊ฐ ์คํ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
2-3. ๋ฐฐํฌ ์ค ์๋ฌ
ํ์ฌ PR๋ก ์ธํด ์คํ๋ github actions trigger๊ฐ ๋ช ๋ถ์งธ ๋
ธ๋์ ๋๊ทธ๋ผ๋ฏธ์์ ๋์ด๊ฐ์ง ์๊ณ ์๋ค.
์ด๋ ํ
์คํธ ์ฝ๋์์ ์ผ๋ถ๋ฌ ์๋ํ ๊ฒ์ด๋ค. ๋ง์ฝ trigger๊ฐ fail์ด ์๋ ์งํ์ค์ธ ์ํ๋ก ๊ณ์ ๋จ์์๋๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊ฒ์ธ์ง์ ๋ํ ํ
์คํธ์๋ค. gitbub actions์์ ์์ฒด์ ์ผ๋ก ๊ธด ์๊ฐ์ด ์์๋๋ ๊ฒฝ์ฐ ํ์์์์ด ๋ฐ์ํ์ฌ ํด๋น trigger๊ฐ ์ข
๋ฃ๋๋ค.
ํ์ฌ PR์์ ์คํ๋ trigger๊ฐ ์ ์์ ์ผ๋ก ์๋ฃ๋์ง ์์์์ ์ ์ ์์.
2-4. ๋ฐฐํฌ ์๋ฌ ํด๊ฒฐ
๋จผ์ pacakge.json์ ์๋์ ์ปค๋งจ๋๋ฅผ ์ถ๊ฐํ์.
"scripts": {
...
"test:ci": "jest"
}
workflows์ 5๋ฒ job์ ์๋์ฒ๋ผ ์์ ํ์.
# vim .github/workflows/test.yaml
...
- name: "5. Run test"
run: npm run test:ci
...
๋ค์ ํธ์ํด๋ณด์.
$ git add .
$ git commit -m "fixed test npm script"
$ git push -u origin dev
๋ค์ PR์ ์์ฒญํด๋ณด๊ณ , github actions trigger๊ฐ ์ ์์ ์ผ๋ก ์งํ๋๋์ง github์์ ํ์ธํด๋ณด์!
trigger๊ฐ ์ ์์ ์ผ๋ก ์คํ๋์ด Merge๊ฐ ๊ฐ๋ฅํด์ง ๊ฒ์ ํ์ธํ ์ ์๋ค.
workflow๊ฐ ์ด๋ป๊ฒ ์งํ๋๋์ง ํ์ธํด๋ณด์.
์ด์ dev ๋ธ๋์น๋ ์ธ๋ชจ ์์ด์ก์ผ๋ Merge ํ ์ญ์ ํ๋๋ก ํ์.
"Delete branch" ํด๋ฆญ.
๋ฌผ๋ก ํฐ๋ฏธ๋ ์์์๋ dev ๋ธ๋์น ์ญ์ ๊ฐ ๊ฐ๋ฅํ๋ค.
$ git push --delete origin dev
๐ฟ ๋ฐฐํฌ
1. Github Secrets
Github Actions VM์์ Lightsail ์ธ์คํด์ค์ ์ ๊ทผํ ์ ์๋๋ก ๋ก์ปฌ์์ ๋ง๋ github_id_rsa ๊ฐ์ธ ํค๋ฅผ Github ํ๋ก์ ํธ ๋ ํฌ์งํ ๋ฆฌ์ Secrets ํ๊ฒฝ ๋ณ์๋ก ๋ฑ๋กํด์ค ๊ฒ์ด๋ค.
์ด๋ ๊ฒ ํจ์ผ๋ก์จ Github Actions Workflows์์ ์์ฑ๋ ๊ฐ์๋จธ์ ์ด Lightsail ์ธ์คํด์ค์ ์ ๊ทผํ ์ ์๊ฒ๋๋ค.
github_id_rsa ssh ํค ์์ฑ์ ์๋ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ์ฌ ์์ฑํ๋ฉด ๋๋ค. ์ด๋ฒ ํฌ์คํ ์์๋ ์๋ตํ์๋๋ฐ ๊ฐ๋จํ ์ค๋ช ํ์๋ฉด ๋ก์ปฌ ๋จธ์ ์ github_id_rsa ๋ผ๋ ๊ฐ์ธ ํค๋ฅผ ์์ฑํ์๊ณ ๊ฐ์ด ์์ฑ๋ public ํค๋ lightsail ์ธ์คํด์ค์ ~/.ssh/authorized_keys์ ๋ฑ๋กํ์๋ค.
๐ SSH ํฐ๋๋ง์ผ๋ก Lightsail ์ธ์คํด์ค ์ ์ํ๊ธฐ -> https://jaehyojjang.dev/linux/ssh-tunneling-to-lightsail/
๋ก์ปฌ์ ~/.ssh/gitub_id_rsa ๊ฐ์ธ ํค๋ฅผ cat
๋ช
๋ น์ด๋ก ์ถ๋ ฅํด๋ณด์.
$ cat ~/.ssh/github_id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbXXXXXXXX
.............
-----END OPENSSH PRIVATE KEY-----
์ ํค๋ฅผ ๋ณต์ฌํ๊ณ github ํ๋ก์ ํธ ๋ ํฌ์งํ ๋ฆฌ - Settings - Secrets and variables ํญ์ผ๋ก ์ด๋ํ ํ "New repository secret"์ ํด๋ฆญํ์ฌ ํ์ํ ํ๊ฒฝ ๋ณ์๋ค์ ์๋์ฒ๋ผ ๋ง๋ค์ด์ฃผ์.
SSH_KNOWN_HOST
์ ๊ฒฝ์ฐ ๋ก์ปฌ์์ssh-keyscan ์๋ฒ_PUBLIC_IP_์ฃผ์
๋ช ๋ น์ ์คํํ์ฌ ์๋ฒ์ ๊ณต๊ฐ ํค๋ฅผ ์์งํ์ฌ ์ถ๋ ฅํ ํ ํด๋น ๊ณต๊ฐ ํค๋ค์ ํ๊ฒฝ ๋ณ์๋ก ๋ฃ์ ๊ฒ์ด๋ค.ssh-keyscan example.com
: ssh-keyscan์ SSH ์๋ฒ์ ๊ณต๊ฐ ํค(public key)๋ฅผ ๊ฒ์ํ๊ณ ์์งํ๋ ์ ํธ๋ฆฌํฐ์ ๋๋ค. SSH ์๋ฒ๋ ํด๋ผ์ด์ธํธ๊ฐ ์ฐ๊ฒฐํ ๋ ๊ณต๊ฐ ํค๋ฅผ ์ ๊ณตํ์ฌ ์๋ฒ ์๋ณ ๋ฐ ์ธ์ฆ์ ์ํํฉ๋๋ค. ssh-keyscan์ ์ง์ ๋ ํธ์คํธ ๋๋ ํธ์คํธ ๋ชฉ๋ก์์ SSH ์๋ฒ์ ๊ณต๊ฐ ํค๋ฅผ ๊ฒ์ํ์ฌ ํด๋น ํธ์คํธ์ ์ ๋ขฐํ ์ ์๋ ํค๋ค์ ์์งํฉ๋๋ค.- ์ผ๋ฐ์ ์ผ๋ก ssh-keyscan์ ๋ณด์ ๋ฐ ์ธ์ฆ์ ๋ชฉ์ ์ผ๋ก ์๋ฒ์ ๊ณต๊ฐ ํค๋ฅผ ์์งํ๊ณ , ์ด๋ฅผ ํด๋ผ์ด์ธํธ์ known_hosts ํ์ผ์ ์ถ๊ฐํ์ฌ ํด๋น ์๋ฒ์ ๋ํ ์ ๋ขฐ์ฑ์ ์ ๊ณตํฉ๋๋ค. ์ด๋ฅผ ํตํด ์๋ฒ๊ฐ ๋ณ๊ฒฝ๋์๊ฑฐ๋ ์ค๊ฐ์ ๊ณต๊ฒฉ(man-in-the-middle attack)์ ์ทจ์ฝํด์ง๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
2. workflow ์์ฑ
- ๋ฐฐํฌ๋ฅผ ์ํ workflow๋ฅผ ์์ฑํด ๋ณผ ๊ฒ์ด๋ค.
๊ทธ์ ์, ์์์ test workflow ๋ฐฐํฌ ๋น์ ๋ฐฐํฌํ๊ณ ๋์ ๊นํ๋ธ ๋ ํฌ์งํ ๋ฆฌ์ ์๋ dev ๋ธ๋์น๋ฅผ ์ญ์ ํ์๋ค.
๋ก์ปฌ์ ํ๋ก์ ํธ ๊ฒฝ๋ก์์๋ dev ๋ธ๋์น๋ฅผ ์ญ์ ํ๊ณ ๋ค์ ์์ฑํด์ผํ๋ค.
๋จผ์ main ๋ธ๋์น์์ ํ์ฌ ์ต์ ์ํ์ ์ฝ๋๋ฅผ pull(update) ๋ฐ๋๋ก ํ์.
git checkout main
git pull origin main
dev ๋ธ๋์น๋ฅผ ์ญ์ ํ์.
git branch -D dev
๋ค์ dev ๋ธ๋์น๋ฅผ ์์ฑํ๊ณ ๊ฑฐ๊ธฐ์ ์๋ deploy.yaml์ ์์ฑํ๋ฉด ๋๋ค.
git checkout -b dev
.github/workflows/deploy.yaml
name: deploy
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-22.04
steps:
- name: "1. Set up SSH"
run: |
mkdir -p ~/.ssh/
echo "${{ secrets.SSH_PRIVATE_KEY }}" | tee ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
- name: "2. Set up Known hosts"
run: |
echo {% raw %} "${{ secrets.SSH_KNOWN_HOST }}" {% endraw %} | tee -a ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: "3. SSH and Deploy"
run: |
ssh -i ~/.ssh/id_rsa {% raw %} ${{ secrets.SSH_USERNAME }}@${{ secrets.SSH_PUBLIC_IP }} {% endraw %}"
cd express
sudo bash scripts/kill-app.sh
git pull
npm install
npm run build
sudo nohup npm run start 1>/dev/null 2>&1 & npx wait-on http://localhost:4000
"
2-1. workflow ๋ฐฐํฌ
workflow ์์ฑ์ด ๋ค ๋๋ฌ์ผ๋ฉด dev ๋ธ๋์น์์ commit & push ํ๋ฉด๋๋ค.
git add .
git commit -m "Created deploy.yaml github actions"
git push -u origin dev
main ๋ธ๋์น๋ก PR ์์ฒญ
ํ
์คํธ trigger๊ฐ ์ ์์ ์ผ๋ก ํต๊ณผ๋์์.
dev ๋ธ๋์น ์ฝ๋๋ฅผ merge ํ ๋ค์ Actions ํญ์์ ์ ์์ ์ผ๋ก deploy trigger๊ฐ ๋์ ํ๋์ง ํ์ธ
2-2 workflow ๋ฐฐํฌ ์๋ฌ
deploy trigger ๋์ ์ค "3. SSH and Deploy" job์ด ๊ณ์ ์คํจํ์์.
SSH ์ ์์ด ๋งํ ๊ฑธ๋ก ์ถ์ธก์ด ๋๋๋ฐ, deploy.yaml ํ์ผ ์ฝ๋์๋ ์๋ฌด ๋ฌธ์ ๊ฐ ์์ด๋ณด์.
ํ์ฐธ์ ์๊ฐํ๋ค๊ฐ '์์ฐจ' ์๋ฆฌ๊ฐ ๋์๋๋ฐ Lightsail Networking์์ 22๋ฒ ํฌํธ(SSH) ์ ์ ๋์ญ์ ๋ด PC ๊ณต์ธ IP ์ธ์๋ ๋ชจ๋ ๋ชป๋ค์ด๋๋ก ๋ง์๋จ์์!
๋ชจ๋ IP ๋์ญ ํ์ฉ์ผ๋ก ๋ฐ๊ฟ์ฃผ๋ ๋ค์๊ณผ ๊ฐ์ด ์ ์์ ์ผ๋ก ๋ฐฐํฌ๋จ!
2-3. main ๋ธ๋์น ๋ณดํธํ๊ธฐ
์์์ ์ค์ต์ ์งํํ ๋ PR์์ test trigger ๋์ ์ค์ test trigger๊ฐ ์๋ฃ๋์ง ์์๋๋ฐ๋ merge๊ฐ ๊ฐ๋ฅํ๋๋ก ๋์ด์์๋ค.
์ด๋ ํ ์คํธ ๊ณผ์ ์์ ์๋ชป๋ ์ฝ๋๊ฐ ์์์์๋ deploy๊ฐ ๊ฐ๋ฅํด์ง๋ค๋ ์ ๊ธฐ์ด๋ฏ๋ก ํ๋ก๋์ ์ ์ฌ๊ฐํ ๋ฌธ์ ๋ฅผ ์ผ๊ธฐํ ์๋ ์๋ ํฐ ๋ฌธ์ ์ด๋ค.
๊ทธ๋ฌ๋ฏ๋ก main ๋ธ๋์น๋ฅผ ๋ณดํธํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ ์์๋ณด๋ ค๊ณ ํ๋ค.
๋จผ์ ๊นํ๋ธ ํ๋ก์ ํธ ๋ ํฌ์งํ ๋ฆฌ - Settings - Branches๋ก ๋ค์ด๊ฐ์ ์๋ 'Require a pull request before merging'์ ์ฒดํฌํด์ฃผ๋๋ก ํ์. ๋ฐฐํฌ ์ PR์ด ํ์์ด๋ฉฐ ๊ฐ์ ๋ก push๋ฅผ ๋ชปํ๋๋ก ๋ง์๋๋ ๊ฒ์ด๋ค.
๊ทธ๋ฆฌ๊ณ ๋๋ฒ์งธ๋ก๋ 'Require status checks to pass before merging'์ ์ฒดํฌํ ํ, test_job์ ๋ฃ์ด์ฃผ๋๋ก ํ์.
test_job ์ํฌํ๋ก์ฐ๊ฐ ํต๊ณผํ๊ธฐ ์ ๊น์ง๋ merge๋ฅผ ํ ์ ์๋๋ก ๋ง๋๋ ๊ฒ์ด๋ค.