κ°λ° μ΄λ³΄μλ₯Ό μν 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 }}
USER: ${{ secrets.DEPLOY_USER }}
KEY: ${{ secrets.DEPLOY_SSH_KEY }}
run: |
mkdir -p ~/.ssh
echo "$KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh -o StrictHostKeyChecking=no $USER@$HOST "cd /var/www/myapp && git pull && npm ci && npm run build --if-present && pm2 reload myapp || pm2 start server.js --name myapp"
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) λμ , νκ²½λ³μ λΆλ¦¬, λ°°ν¬ μ μ© μ¬μ©μ/κΆν μ΅μνλ₯Ό ν΄λ³΄λ©΄ λ ννν΄μ§λλ€.
β¬οΈ μ΄ κΈμ΄ λμμ΄ λμ ¨λ€λ©΄, μλ κ΄κ³ λ₯Ό ν λ²λ§ ν΄λ¦ν΄μ£ΌμΈμ! μ μκ² ν° νμ΄ λ©λλ€ πββοΈ β¬οΈ