๊ฐ๋ฐ ์ด๋ณด์๋ฅผ ์ํ GitHub Actions๋ก Node.js ํ๋ก์ ํธ ์๋ ํ ์คํธยท๋ฐฐํฌ(CI/CD) ์ฒ์๋ถํฐ ์ค์ ํ๊ธฐ
๊ฐ๋ฐ ์ด๋ณด์๋ฅผ ์ํ GitHub Actions๋ก Node.js ํ๋ก์ ํธ ์๋ ํ ์คํธยท๋ฐฐํฌ(CI/CD) ์ฒ์๋ถํฐ ์ค์ ํ๊ธฐ ์ฒ์์ โ๋ก์ปฌ์์...
๊ฐ๋ฐ ์ด๋ณด์๋ฅผ ์ํ GitHub Actions๋ก Node.js ํ๋ก์ ํธ ์๋ ํ ์คํธยท๋ฐฐํฌ(CI/CD) ์ฒ์๋ถํฐ ์ค์ ํ๊ธฐ
์ฒ์์ โ๋ก์ปฌ์์ ์ ๋๋๋ฐ ์๋ฒ์์๋ง ์ ๊นจ์ง์ง?โ๊ฐ ๋ฐ๋ณต๋ฉ๋๋ค. ๋ ํฐ ๋ฌธ์ ๋, ๋ฐฐํฌํ ๋๋ง๋ค ์์ผ๋ก ํ ์คํธํ๊ณ ํ์ผ ์ฌ๋ฆฌ๋ค ๋ณด๋ฉด ์ค์๋ ์ธ์ ๊ฐ ๋ฐ๋์ ๋๋ค๋ ๊ฒ. ๊ทธ๋์ ์ค๋์ Node.js ํ๋ก์ ํธ์ GitHub Actions๋ก ์๋ ํ ์คํธ์ ๋ฐฐํฌ ํ๋ฆ์ ์ด๋ณด์ ๋๋์ด์์ ํ ๋ฒ์ ์ก์๋ณด๊ฒ ์ต๋๋ค. ํ ๋ฒ๋ง ์ ๋๋ก ์ค์ ํด๋๋ฉด, ์ดํ์ ์ฝ๋ ํธ์ โ ํ ์คํธ โ ๋ฐฐํฌ๊ฐ ์์ฐ์ค๋ฝ๊ฒ ๊ตด๋ฌ๊ฐ๋๋ค.
์ค๋น๋ฌผ ์ฒดํฌ๋ฆฌ์คํธ
- GitHub ์ ์ฅ์(Repository)
- Node.js ํ๋ก์ ํธ(์: Express)
- package.json์ ํ ์คํธ ์คํฌ๋ฆฝํธ ์กด์ฌ(์์ผ๋ฉด ๋ง๋ค์ด๋ ๋จ)
- ๋ฐฐํฌ ๋์(์: ๋ฆฌ๋ ์ค ์๋ฒ, ๋๋ ๋น๋ ์ฐ์ถ๋ฌผ ์ ๋ก๋)
์์ ํ๋ก์ ํธ ์คํฌ๋ฆฝํธ(์ต์ ๊ตฌ์ฑ)
{
"scripts": {
"test": "node -e \"console.log('test ok')\"",
"build": "node -e \"console.log('build ok')\""
}
}
ํ ์คํธ๊ฐ ์์ง ์๋ค๋ฉด ์์ฒ๋ผ ์์๋ก๋ผ๋ ์์ํด ๋๊ณ , ๋์ค์ Jest ๊ฐ์ ํ ์คํธ ๋๊ตฌ๋ก ํ์ฅํ๋ฉด ๋ฉ๋๋ค.
GitHub Actions ๊ธฐ๋ณธ ๊ตฌ์กฐ ์ดํดํ๊ธฐ
GitHub Actions๋ ์ ์ฅ์์ .github/workflows/ ํด๋์ ์๋ YAML ํ์ผ์ ์ฝ์ด ์๋ ์คํํฉ๋๋ค.
- on: ์ธ์ ์คํํ ์ง(ํธ์, PR ๋ฑ)
- jobs: ์ด๋ค ์์ ์ ํ ์ง
- steps: ์์ ์ ์ด๋ฃจ๋ ๋จ๊ณ๋ค(์ฒดํฌ์์, ์ค์น, ํ ์คํธ ๋ฑ)
1๋จ๊ณ: ์๋ ํ ์คํธ(CI) ์ํฌํ๋ก ๋ง๋ค๊ธฐ
ํ์ผ ์์ฑ: .github/workflows/ci.yml
name: CI
on:
pull_request:
push:
branches: ["main"]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20]
steps:
- name: ์ฒดํฌ์์
uses: actions/checkout@v4
- name: Node.js ์ค์
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: "npm"
- name: ์์กด์ฑ ์ค์น
run: npm ci
- name: ํ
์คํธ ์คํ
run: npm test
์ฌ๊ธฐ์ ์ด๋ณด์๊ฐ ์์ฃผ ๋งํ๋ ํฌ์ธํธ
- npm install ๋์ npm ci: ์ ๊ธ ํ์ผ(package-lock.json) ๊ธฐ์ค์ผ๋ก ๋ ์์ ์ ์ผ๋ก ์ค์นํฉ๋๋ค.
- pull_request์๋ ์คํ: PR ๋จ๊ณ์์ ๋ฏธ๋ฆฌ ๊นจ์ง๋ ๊ฑธ ์ก์์ค๋๋ค.
- Node ๋ฒ์ 2๊ฐ ๋๋ฆฌ๊ธฐ: โ๋ด ์ปดํจํฐ ๋ฒ์ ์์๋ง ๋๋โ ์ํฉ์ ์ค์ฌ์ค๋๋ค.
2๋จ๊ณ: ์๋ ๋ฐฐํฌ(CD)๊น์ง ์ฐ๊ฒฐํ๊ธฐ
๋ฐฐํฌ๋ ํ๊ฒฝ์ด ๋ค์ํฉ๋๋ค. ์ฌ๊ธฐ์๋ ์๋ฒ์ SSH๋ก ์ ์ํด์ ๋ฐฐํฌํ๋ ๋ฐฉ์์ ์์๋ก ์ก๊ฒ ์ต๋๋ค. (๊ฐ์ฅ ํํ๊ณ ์ดํด๋ ์ฌ์)
์๋ฒ ๋ฐฐํฌ ํ๋ฆ(์์)
- main ๋ธ๋์น์ ํธ์
- ํ ์คํธ ํต๊ณผ
- ์๋ฒ์ ์ ์
- ์ฝ๋ ์ ๋ฐ์ดํธ + ์ค์น + ๋น๋ + ์ฌ์์ ํ์ผ ์์ฑ: .github/workflows/cd.yml
name: CD
on:
push:
branches: ["main"]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: ์ฒดํฌ์์
uses: actions/checkout@v4
- name: Node.js ์ค์
uses: actions/setup-node@v4
with:
node-version: 20
cache: "npm"
- name: ์์กด์ฑ ์ค์น
run: npm ci
- name: ํ
์คํธ ์คํ
run: npm test
- name: ๋น๋(ํ์ํ ๊ฒฝ์ฐ)
run: npm run build --if-present
- name: ์๋ฒ ๋ฐฐํฌ(SSH)
env:
HOST: ${{ secrets.DEPLOY_HOST
Secrets ์ค์ (์ค์)
์ ์ฅ์ ์ค์ ์์ Secrets์ ์๋ ๊ฐ์ ๋ฑ๋กํฉ๋๋ค.
- DEPLOY_HOST: ์๋ฒ ์ฃผ์
- DEPLOY_USER: ์ ์ ์ฌ์ฉ์
- DEPLOY_SSH_KEY: ๊ฐ์ธํค(Private Key) ๊ฐ์ธํค๋ ์ ์ถ๋๋ฉด ๋์ฅ์ ๋๋ค. ์ ๋ ์ฝ๋์ ์ง์ ์ ์ง ๋ง๊ณ , ๋ฐ๋์ Secrets๋ก๋ง ๋ค๋ฃจ์ธ์.
์ค์ ํ: ์คํจํ์ ๋ ๋น ๋ฅด๊ฒ ์์ธ ์ฐพ๋ ๋ฒ
1) โ์์กด์ฑ ์ค์น์์ ์คํจโ
- package-lock.json์ด ์ต์ ์ธ์ง ํ์ธ
- Node ๋ฒ์ ํธํ์ฑ ํ์ธ(๋ก์ปฌ๊ณผ CI์ ๋ฒ์ ์ฐจ์ด)
2) โ์๋ฒ์์ pm2 ๋ช ๋ น์ด ์๋คโ
- ์๋ฒ์ pm2 ์ค์น ํ์: npm i -g pm2
- ๋๋ systemd ๋ฑ ๋ณธ์ธ ๋ฐฉ์์ ๋ง๊ฒ ์ฌ์์ ๋ช ๋ น์ ๋ฐ๊พธ๊ธฐ
3) โ๊ถํ/๊ฒฝ๋ก ๋ฌธ์ โ
- ์๋ฒ์ ๋ฐฐํฌ ํด๋(/var/www/myapp) ๊ถํ ํ์ธ
- git pull์ด ๊ฐ๋ฅํ ๊ณ์ ์ธ์ง ํ์ธ
๋ง๋ฌด๋ฆฌ: ํ ๋ฒ ๋ง๋ค์ด๋๋ฉด ๋ฐฐํฌ๊ฐ โ์ต๊ดโ์ด ๋ฉ๋๋ค
๊ฐ๋ฐ ์ด๋ณด ์์ ์ ๊ธฐ๋ฅ ํ๋ ์ถ๊ฐํ๊ณ ๋ ๋ฐฐํฌ๊ฐ ๋ถ๋ด์ ๋๋ค. ํ์ง๋ง GitHub Actions๋ก ํ ์คํธ ์๋ํ + ๋ฐฐํฌ ์๋ํ๊น์ง ์ฐ๊ฒฐํด๋๋ฉด, ์์ ํ๋ฆ์ด ๊น๋ํด์ง๊ณ ์ค์๋ ์ค์ด๋ญ๋๋ค. ์ค๋์ SSH ๋ฐฐํฌ ์์๋ก ์์ํ์ง๋ง, ์ต์ํด์ง๋ฉด ๋น๋ ์ฐ์ถ๋ฌผ ์ ๋ก๋, ์ปจํ ์ด๋ ๋ฐฐํฌ ๋ฑ์ผ๋ก ์์ฐ์ค๋ฝ๊ฒ ํ์ฅํ ์ ์์ด์.
๋ค์ ๋จ๊ณ๋ก๋ ํ ์คํธ ๋๊ตฌ(Jest) ๋์ , ํ๊ฒฝ๋ณ์ ๋ถ๋ฆฌ, ๋ฐฐํฌ ์ ์ฉ ์ฌ์ฉ์/๊ถํ ์ต์ํ๋ฅผ ํด๋ณด๋ฉด ๋ ํํํด์ง๋๋ค.
โฌ๏ธ ์ด ๊ธ์ด ๋์์ด ๋์ จ๋ค๋ฉด, ์๋ ๊ด๊ณ ๋ฅผ ํ ๋ฒ๋ง ํด๋ฆญํด์ฃผ์ธ์! ์ ์๊ฒ ํฐ ํ์ด ๋ฉ๋๋ค ๐โโ๏ธ โฌ๏ธ