Skip to content

Latest commit

ย 

History

History
867 lines (628 loc) ยท 35.5 KB

actions.md

File metadata and controls

867 lines (628 loc) ยท 35.5 KB

GitHub Webhook์œผ๋กœ ์ฝ”๋“œ ์ปจ๋ฒค์…˜ ์ฒดํฌ, Actions๋กœ ํ”„๋ก ํŠธ์—”๋“œ CI/CD ๊ตฌ์ถ•ํ•˜๊ธฐ


  1. GitHub Actions๋ž€, Workflow ๋“ฑ๋กํ•˜๊ธฐ](./#user-content-1-github-actions๋ž€-workflow-๋“ฑ๋กํ•˜๊ธฐ
  2. GitHub Actions ์›Œํ‚น ํ”„๋กœ์„ธ์Šค: Runner, Jobs, Steps, Actions
  3. Workflow ํŒŒ์ผ ์ž‘์„ฑํ•˜๊ธฐ
  4. ์žฌ์‚ฌ์šฉํ•˜๊ธฐ: Reusable Workflow, Runner ํ™˜๊ฒฝ ์บ์‹ฑํ•˜๊ธฐ
  5. ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์‚ฌ์šฉํ•˜๊ธฐ: ์ง์ ‘ ์„ธํŒ…, GitHub ๋””ํดํŠธ ํ™˜๊ฒฝ๋ณ€์ˆ˜
  6. ์ปจํ…์ŠคํŠธ ๋ณ€์ˆ˜ ์‚ฌ์šฉํ•˜๊ธฐ, ํ™˜๊ฒฝ๋ณ€์ˆ˜์™€์˜ ์ฐจ์ด์ 
  7. secrets ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ธํŒ…ํ•˜๊ธฐ
  8. CI: Webhook์œผ๋กœ ์ฝ”๋“œ ์ปจ๋ฒค์…˜ ์ž๋™ ์ฒดํฌ, Actions๋กœ ํ…Œ์ŠคํŠธ์™€ PR ์ž๋™ํ™”ํ•˜๊ธฐ
  9. CD: SSH๋กœ ์›๊ฒฉ ์„œ๋ฒ„์— ์ ‘์†ํ•ด์„œ ๋ฐฐํฌํ•˜๊ธฐ

1. GitHub Actions๋ž€, Workflow ๋“ฑ๋กํ•˜๊ธฐ

GitHub Actions๋Š” Workflow ์ž๋™ํ™” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ, ๋นŒ๋“œ, ๋ฐฐํฌ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์›ํ•˜๋Š” ์–ด๋–ค ์ž‘์—…์ด๋˜ Workflow์— ํฌํ•จ์‹œ์ผœ์„œ ์ž๋™ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•œ ๋ฒˆ์— ๊ฐ™์ด ์‹คํ–‰์‹œํ‚ฌ ์ผ๋“ค์„ ๋ชจ์•„ ํ•˜๋‚˜์˜ Job์œผ๋กœ ๊ตฌ์„ฑํ•ด๋†“๊ณ ์š”, push, pull_request ๋“ฑ ํŠน์ • ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ Job์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ˆ„๊ตฐ๊ฐ€ ํŠน์ • ๋ธŒ๋žœ์น˜์— PR(Pull request)์„ ์ƒ์„ฑํ•˜๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, ํ…Œ์ŠคํŠธ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ž๋™์œผ๋กœ ์‹คํ–‰๋˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.



์‹คํ–‰ํ•  Workflow๋Š” yml(Yaml) ํฌ๋งท ํŒŒ์ผ๋กœ ์ž‘์„ฑํ•˜์—ฌ ํ”„๋กœ๊ทธ๋žจ์˜ /.github/workflows/ ๊ฒฝ๋กœ์— ๋‘ก๋‹ˆ๋‹ค. ์ด ํŒŒ์ผ ์ž‘์„ฑ์„ ์™„๋ฃŒํ•˜๊ณ  GitHub ๋ ˆํฌ์ง€ํ† ๋ฆฌ์— pushํ•˜๋ฉด ์™„๋ฃŒ์ž…๋‹ˆ๋‹ค. ์ดํ›„๋ถ€ํ„ฐ ํŒŒ์ผ์— ์„ค์ •ํ•œ๋Œ€๋กœ Workflow๊ฐ€ ์ž๋™์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋˜๋Š” GitHub ๋ ˆํฌ์ง€ํ† ๋ฆฌ์˜ Actions ํƒญ์œผ๋กœ ์ด๋™, Workflow ์…‹์—… ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ GitHub์—์„œ ํ•ด๋‹น ํŒŒ์ผ์„ ์ง์ ‘ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์€ GitHub์—์„œ ์ œ๊ณตํ•˜๋Š” ์ƒ˜ํ”Œ ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.

# This is a basic workflow to help you get started with Actions

name: CI

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the master branch
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2

      # Runs a single command using the runners shell
      - name: Run a one-line script
        run: echo Hello, world!

      # Runs a set of commands using the runners shell
      - name: Run a multi-line script
        run: |
          echo Add other actions to build,
          echo test, and deploy your project.

2. GitHub Actions ์›Œํ‚น ํ”„๋กœ์„ธ์Šค: Runner, Jobs, Steps, Actions

2-1. Runner

Runner๋Š” Job์˜ ์‹คํ–‰ ํ™˜๊ฒฝ์ด ์„ค์น˜๋œ ์„œ๋ฒ„๋ฅผ ๋งํ•ฉ๋‹ˆ๋‹ค. GitHub์—์„œ ํ˜ธ์ŠคํŒ…ํ•˜๋Š” Runner๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ ์š”, ์ง์ ‘ Runner๋ฅผ ํ˜ธ์ŠคํŒ…ํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค. GitHub์—์„œ ํ˜ธ์ŠคํŒ…ํ•˜๋Š” Runner๋Š” ๊ฐ€์ƒ๋จธ์‹ ์˜ ํ˜•ํƒœ๋กœ ์ œ๊ณต๋˜๊ณ ์š”, Ubuntu Linux, Windows, macOS ํ™˜๊ฒฝ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. About GitHub-hosted runners ๋ฌธ์„œ์—์„œ ๋” ์ž์„ธํ•œ ์„ค๋ช…๊ณผ OS๋ณ„ ํ•˜๋“œ์›จ์–ด ์‚ฌ์–‘, ๊ฐ ํ™˜๊ฒฝ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ Workflow ํŒŒ์ผ ๋‚ด ์„ค์ •๊ฐ’ ๋“ฑ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•  Runner๋ฅผ Workflow ํŒŒ์ผ(yml)์— ๋ช…์‹œํ•˜๋ฉด Workflow๊ฐ€ ์‹คํ–‰๋  ๋•Œ ํ•ด๋‹น Runner๊ฐ€ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, macOS Big Sur 11 ํ™˜๊ฒฝ์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด runs-on ํ•ญ๋ชฉ์— macos-11์ด๋ผ๊ณ  ์ง€์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

jobs:
  build:
    runs-on: macos-11

2-2. Jobs, Steps, Actions

2-2-1. Jobs

์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ Job๋“ค์ด ์‹คํ–‰๋˜๋„๋ก Workflow๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ Job์€ ์ง€์ •ํ•œ Runner ์œ„์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.



๊ธฐ๋ณธ์ ์œผ๋กœ Job๋“ค์€ ์ˆœ์ฐจ๊ฐ€ ์•„๋‹Œ ๋ณ‘๋ ฌ์ ์œผ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ needs ํ•ญ๋ชฉ์„ ์‚ฌ์šฉํ•ด ํŠน์ • Job์ด ์„ฑ๊ณตํ–ˆ์„ ๋•Œ๋งŒ ๋‹ค๋ฅธ Job์ด ์‹คํ–‰๋˜๋„๋ก ์ˆœ์ฐจ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

jobs:
  build:
    needs: setup # setup์ด ๋๋‚˜์•ผ build๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค

2-2-2. Steps

Step์€ Job ๋‚ด์—์„œ ๊ฐœ๋ณ„ ์—…๋ฌด๋“ค์„ ๋งํ•ฉ๋‹ˆ๋‹ค. Step์ด๋ผ๋Š” ์ด๋ฆ„์ฒ˜๋Ÿผ ์ง€์ •ํ•œ ์ˆœ์„œ๋Œ€๋กœ ๋‹จ๊ณ„์ ์œผ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. Step์€ ํ•˜๋‚˜์˜ Action์ด ๋  ์ˆ˜๋„ ์žˆ๊ณ , Shell ์ปค๋งจ๋“œ๊ฐ€ ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.


2-2-3. Actions

Action์€ Workflow๋ฅผ ์ด๋ฃจ๋Š” ๊ฐ€์žฅ ์ž‘์€ Work ๋‹จ์œ„์ž…๋‹ˆ๋‹ค. Action์„ ์ง์ ‘ ๋งŒ๋“ค๊ฑฐ๋‚˜, GitHub ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ์ œ๊ณตํ•˜๋Š” Action๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ ˆํฌ์ง€ํ† ๋ฆฌ ์ฒดํฌ์•„์›ƒ, node ์„ค์น˜ ๋“ฑ ๊ธฐ๋ณธ์ ์ธ ๊ฑฐ์˜ ๋ชจ๋“  ๋™์ž‘๊ณผ ์…‹์—… Action๋“ค์ด ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ์ด๋ฏธ ์ œ๊ณต๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.


3. Workflow ํŒŒ์ผ ์ž‘์„ฑํ•˜๊ธฐ

์ด์ œ Workflow ํŒŒ์ผ ์˜ˆ์ œ๋ฅผ ์ž‘์„ฑํ•ด๋ณด๋ฉด์„œ ํŒŒ์ผ์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ธฐ๋ณธ์ ์ธ ๋ฌธ๋ฒ•๋“ค์„ ์ •๋ฆฌํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.


3-1. ์ตœ์ƒ์œ„ ๋ ˆ๋ฒจ: name, on, jobs

Workflow ํŒŒ์ผ์˜ ๊ฐ€์žฅ ์ƒ์œ„ ๋ ˆ๋ฒจ ํ‚ค๋“ค์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ชจ๋“  ํ‚ค์™€ ํ•˜์œ„ ํ‚ค์— ๋Œ€ํ•œ ํŒŒ์ผ ์ž‘์„ฑ ๋ฌธ๋ฒ•์€ Workflow syntax for GitHub Actions ๋ฌธ์„œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • name: GitHub Actions ํƒญ์— ํ‘œ์‹œ๋˜๋Š” Workflow์˜ ์ด๋ฆ„์ž…๋‹ˆ๋‹ค. Optional ํ‚ค.
  • on: Workflow๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•  ์ด๋ฒคํŠธ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ ์ข…๋ฅ˜๋Š” Events that trigger workflows, ๋ธŒ๋žœ์น˜ ์ œํ•œ ๋ฌธ๋ฒ•์€ on.<push|pull_request>.<branches|tags>์„ ํ™•์ธํ•˜์„ธ์š”.
  • jobs: ์ด Workflow์—์„œ ์‹คํ–‰ํ•  ๋ชจ๋“  Job๋“ค์„ ์ง€์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ•˜๋ฉด ์กฐ๊ฑด์— ํ•ด๋‹นํ•˜๋Š” ๋ธŒ๋žœ์น˜์— push ๋˜์—ˆ์„ ๋•Œ CI Workflow๊ฐ€ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋กœ์ปฌ์—์„œ feature/#23/MEAL-14 ๋ธŒ๋žœ์น˜๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ž‘์—…ํ•œ ํ›„ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋กœ pushํ•˜๋ฉด Workflow๊ฐ€ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.

# test.yml
name: CI
on:
  push:
    branches:
      - 'feature/**'
      - 'hotfix/**'
jobs:
  # ...

3-2. Job ๊ตฌ์„ฑ: needs, runs-on, strategy: matrix, steps

  • needs: ๋‹ค๋ฅธ Job์ด ์„ฑ๊ณตํ•ด์•ผ๋งŒ ์‹คํ–‰๋˜๋„๋ก ์˜์กด์„ฑ์„ ๊ฐ–๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
  • runs-on: Job์„ ์‹คํ–‰ํ•  Runner๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
  • strategy: matrix : Job์„ ์—ฌ๋Ÿฌ ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์œ„ํ•ด Matrix๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค. matrix ์ปจํ…์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์—ฌ๊ธฐ์„œ ์ง€์ •ํ•œ ๊ฐ’์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • steps: Job ๋‚ด์—์„œ ์‹คํ–‰๋  Step๋“ค์„ ์ˆœ์„œ๋Œ€๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
jobs:
  test: # job ์ด๋ฆ„
    runs-on: macos-11 # runner
    strategy:
      matrix:
        node-version: [8, 10, 14] # node 8, 10, 14 ํ™˜๊ฒฝ์—์„œ ๊ฐ๊ฐ job์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค
    steps:
      # ...

  build: # job ์ด๋ฆ„
    needs: setup # test๊ฐ€ ์„ฑ๊ณตํ•ด์•ผ build๋„ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค
    runs-on: macos-11 
    steps:
    # ...

3-3. Step ๊ตฌ์„ฑ: name, uses, run

๊ฐ Step์€ ํ•˜์ดํ”ˆ(-)์„ ์‚ฌ์šฉํ•˜์—ฌ ๋‹จ๊ณ„๋ฅผ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. ๋” ์ž์„ธํ•œ ๋ฌธ๋ฒ•์€ Workflow Syntax ๋ฌธ์„œ์—์„œ ํ™•์ธํ•˜์„ธ์š”.

  • name: GitHub Actions ํƒญ์— ํ‘œ์‹œ๋˜๋Š” ๊ฐ Step์˜ ์ด๋ฆ„์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
  • id: ๋‹ค๋ฅธ Step์—์„œ ํŠน์ • Step์„ ์ฐธ์กฐํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. steps ์ปจํ…์ŠคํŠธ๋ฅผ ํ†ตํ•ด ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค.
  • uses: ์‚ฌ์šฉํ•  Action์„ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
  • with: Action๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํ•„์š”ํ•œ ํ‚ค ๊ฐ’๋“ค์„ ์ง€์ •ํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • run: Runner์—์„œ ์‹คํ–‰ํ•  Shell ์ปค๋งจ๋“œ๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑํ•˜๋ฉด, ์ด 4 ๋‹จ๊ณ„์˜ Step์œผ๋กœ ๊ตฌ์„ฑ๋œ setup Job์ด ์™„์„ฑ๋ฉ๋‹ˆ๋‹ค.

jobs:
  setup:
    runs-on: macos-11
    strategy:
      matrix:
        node-version: [8, 10, 14] # or [ 8.x, 10.x, 14.x ]
    steps:
      - name: Checkout repo and download # step 1
        uses: actions/checkout@v2 

      - name: Install node # step 2
        uses: actions/setup-node@v2
        with:
          node-version: ${{ matrix.node-version }}

      - name: Install yarn # step 3
        run: npm install -g yarn

      - name: Install all dependencies using yarn # step 4
        run: yarn install

4. ์žฌ์‚ฌ์šฉํ•˜๊ธฐ: Reusable Workflow, Runner ํ™˜๊ฒฝ ์บ์‹ฑํ•˜๊ธฐ

4-1. Reusable Workflow

์—ฌ๋Ÿฌ Workflow์—์„œ ๋™์ผํ•œ ์ž‘์—…์ด ์‚ฌ์šฉ๋˜์–ด ์ž‘์—…์ด ์ค‘๋ณต๋  ๋•Œ ์ด๋ฅผ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด Workflow๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„์ง ๋ฒ ํƒ€ ๋‹จ๊ณ„์ด๋ฉฐ ๋ช‡๊ฐ€์ง€ ์ œํ•œ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— Reusing workflows ๋ฌธ์„œ๋ฅผ ๊ผผ๊ผผํžˆ ํ™•์ธํ•˜์„ธ์š”. ์ œํ•œ์‚ฌํ•ญ ์ค‘ ์ฃผ๋ชฉํ• ๋งŒํ•œ ๊ฒƒ์€ env ์ปจํ…์ŠคํŠธ๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ, ์žฌ์‚ฌ์šฉ Workflow์—์„œ ๋‹ค๋ฅธ ์žฌ์‚ฌ์šฉ Workflow๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.


4-2. Runner ํ™˜๊ฒฝ ์บ์‹ฑํ•˜๊ธฐ

GitHub Actions๋Š” Runner์— ๋งค๋ฒˆ ์ƒˆ๋กญ๊ฒŒ ํ™˜๊ฒฝ์„ ์…‹์—…ํ•˜๊ณ  Workflow๋ฅผ ์‹คํ–‰ํ•˜๋ฏ€๋กœ, ์ข…์†์„ฑ ํŒŒ์ผ๋“ค์„ ์บ์‹ฑํ•˜์—ฌ ํ…Œ์ŠคํŠธ์™€ ๋นŒ๋“œ ์†๋„๋ฅผ ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์บ์‹œ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ํ•ด๋‹น ๋ ˆํฌ์ง€ํ† ๋ฆฌ์˜ ๋ชจ๋“  Workflow์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ ์š”. ์ปค๋ฎค๋‹ˆํ‹ฐ์˜ actions/cache@v2๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํŠน์ • ๊ฒฝ๋กœ์™€ ํŒŒ์ผ์„ ์บ์‹ฑํ•˜๋Š” Step์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋กœ, ํŒจํ‚ค์ง€๋“ค์ด ์„ค์น˜๋œ node_modules ๊ฒฝ๋กœ์™€ yarn์˜ ์ „์—ญ ์„ค์น˜ ๊ฒฝ๋กœ๋ฅผ ์บ์‹ฑํ•  ์ˆ˜ ์žˆ๊ฒ ์ฃ . ์•„๋ž˜๋Š” Node - Yarn ์บ์‹ฑ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.


- name: Get yarn cache directory path
  id: yarn-cache-dir-path
  run: echo "::set-output name=dir::$(yarn cache dir)"

- uses: actions/cache@v2
  id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
  with:
    path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
    key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
    restore-keys: |
      ${{ runner.os }}-yarn-

Use Case๋กœ๋Š” Github Actions์œผ๋กœ ๋ฐฐํฌ ์ž๋™ํ™”ํ•˜๊ธฐ | NHN Cloud Meetup๊ฐ€ ๋„์›€์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.


5. ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์‚ฌ์šฉํ•˜๊ธฐ: ์ง์ ‘ ์„ธํŒ…, GitHub ๋””ํดํŠธ ํ™˜๊ฒฝ๋ณ€์ˆ˜

5-1. ์ง์ ‘ ์„ธํŒ…

Step, Job, ๋˜๋Š” Workflow ์ „์ฒด๋ฅผ ์œ„ํ•œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ๋ฒ”์œ„์— ๋งž๊ฒŒ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์›ํ•˜๋Š” ๋ฒ”์œ„์—์„œ env ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ •์˜ํ•˜๋ฉด ๋˜๊ณ ์š”, ๋™๋ช…์˜ ํ™˜๊ฒฝ๋ณ€์ˆ˜๊ฐ€ ์‚ฌ์šฉ๋  ๋•Œ๋Š” Step > Job > Workflow ์ˆœ์œผ๋กœ ์šฐ์„ ํ•ฉ๋‹ˆ๋‹ค. Workflow ๋ ˆ๋ฒจ์—์„œ ์ •์˜ํ•œ ํ™˜๊ฒฝ๋ณ€์ˆ˜์™€ ๋™์ผํ•œ ์ด๋ฆ„์˜ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ Step ๋ ˆ๋ฒจ์—์„œ ์ •์˜ํ•  ๊ฒฝ์šฐ, ํ•ด๋‹น Step์ด ์‹คํ–‰๋˜๋Š” ๋™์•ˆ Step์—์„œ ์ •์˜ํ•œ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๊ฐ’์ด Workflow ๋ ˆ๋ฒจ์—์„œ ์ •์˜ํ•œ ๊ฐ’์„ ๋ฎ์–ด์”๋‹ˆ๋‹ค.

jobs:
  test:
    runs-on: macos-11
    env:
      MODE: test
    steps:
      - name: "Set environment variables to test Vue app"
        if: ${{ env.MODE == 'test' }} # env ์ปจํ…์ŠคํŠธ์—์„œ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค
        env:
          USER_NAME: Tester
        run: echo "User name is $USER_NAME"

Workflow ํŒŒ์ผ ๋‚ด์—์„œ ์ •์˜๋œ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด env ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, MODE ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ env.MODE ์ด๋Ÿฐ์‹์œผ๋กœ์š”. ์œ„ ์˜ˆ์ œ์—์„œ if ํ•ญ๋ชฉ ๋ถ€๋ถ„์„ ์ฐธ๊ณ ํ•˜์„ธ์š”. run ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Runner์—์„œ ์ง์ ‘ ์ปค๋งจ๋“œ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ๋Š”, ํ•ด๋‹น Runner ๋‚ด์—์„œ ์ •์˜ํ•œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ env ์ปจํ…์ŠคํŠธ ์—†์ด $NODE ์ด๋ ‡๊ฒŒ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ Environment variables ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

If you use the workflow file's run key to read environment variables from within the runner operating system (as shown in the example above), the variable is substituted in the runner operating system after the job is sent to the runner. For other parts of a workflow file, you must use the env context to read environment variables; this is because workflow keys (such as if) require the variable to be substituted during workflow processing before it is sent to the runner.


5-2. GitHub ๋””ํดํŠธ ํ™˜๊ฒฝ๋ณ€์ˆ˜

๊ธฐ๋ณธ์ ์ธ ๊ฐ’๋“ค์€ GitHub์—์„œ ๋””ํดํŠธ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๊ณต์‹๋ฌธ์„œ์˜ Default environment variables ์„น์…˜์—์„œ ๋ชจ๋“  ๋””ํดํŠธ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋ชฉ๋ก์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


6. ์ปจํ…์ŠคํŠธ ๋ณ€์ˆ˜ ์‚ฌ์šฉํ•˜๊ธฐ, ํ™˜๊ฒฝ๋ณ€์ˆ˜์™€์˜ ์ฐจ์ด์ 

GitHub Actions๋Š” ์ปจํ…์ŠคํŠธ ๋ณ€์ˆ˜๋„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํ˜„์žฌ Runner์˜ OS ์ •๋ณด๋ฅผ ์ฐธ์กฐํ•˜๋ ค๋ฉด runner.os ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด ์ปจํ…์ŠคํŠธ ๋ณ€์ˆ˜๋“ค์€ ๋””ํดํŠธ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋“ค๊ณผ ๊ฝค ๊ฒน์น˜๋Š”๋ฐ์š”, ๊ฐ๊ฐ ๋‹ค๋ฅธ ์šฉ๋„๋กœ ์˜๋„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

  • ๋””ํดํŠธ ํ™˜๊ฒฝ๋ณ€์ˆ˜ : ํ˜„์žฌ ์‹คํ–‰์ค‘์ธ Job์˜ Runner ๋‚ด์—์„œ๋งŒ ์กด์žฌ
  • ์ปจํ…์ŠคํŠธ ๋ณ€์ˆ˜ : Workflow์˜ ์–ด๋Š ๊ณณ์—์„œ๋‚˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

๋‹ค์Œ์€ ์ด ๋‘˜์˜ ์ฐจ์ด์ ์„ ๋‚˜ํƒ€๋‚ด๋Š” ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค. ๋””ํดํŠธ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋Š” ์‹คํ–‰์ค‘์ธ ํ˜„์žฌ Job์— ๋Œ€ํ•œ ์ •๋ณด๋งŒ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ํฌ์ธํŠธ์ž…๋‹ˆ๋‹ค.

name: CI
on: push
jobs:
  prod-check:
    if: ${{ github.ref == 'refs/heads/main' }}
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying to production server on branch $GITHUB_REF"

7. secrets ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ธํŒ…ํ•˜๊ธฐ

ํ”„๋กœ๊ทธ๋žจ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ GitHub์˜ Secrets๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€๋ น, Vue ์•ฑ์—์„œ ์‚ฌ์šฉํ•  API์˜ ๋„๋ฉ”์ธ(VUE_APP_API_URL)์„ Secrets๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด๊ด€ํ•˜๊ณ  ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Secret์„ ์ถ”๊ฐ€ํ•  ๋ ˆํฌ์ง€ํ† ๋ฆฌ์—์„œ Settings ํƒญ์œผ๋กœ ์ด๋™, Secrets ๋ฉ”๋‰ด์—์„œ New repository secret ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ Secret์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.



Secret์€ GitHub Actions์˜ Workflow๋ฅผ ๊ตฌ์„ฑํ•  ๋•Œ secrets ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„ ์˜ˆ์‹œ์—์„œ Secret์œผ๋กœ ์ถ”๊ฐ€ํ•œ VUE_APP_API_URL ๊ฐ’์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

steps:
  - name: Set environment variables
    env: 
      VUE_APP_API_URL: ${{ secrets.VUE_APP_API_URL }}

8. CI: Webhook์œผ๋กœ ์ฝ”๋“œ ์ปจ๋ฒค์…˜ ์ž๋™ ์ฒดํฌ, Actions๋กœ ํ…Œ์ŠคํŠธ์™€ PR ์ž๋™ํ™”ํ•˜๊ธฐ

์šฐ๋ฆฌํŒ€์€ Vue2, Yarn์„ ์‚ฌ์šฉํ•˜๊ณ , GitFlow๋ฅผ ๋ณ€ํ˜•ํ•œ ๋ธŒ๋žœ์น˜ ์ „๋žต์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.


8-1. Webhook์œผ๋กœ ์ฝ”๋“œ ์ปจ๋ฒค์…˜ ์ž๋™ ์ฒดํฌํ•˜๊ธฐ

GitHub Webhook์„ ์‚ฌ์šฉํ•ด์„œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ปค๋ฐ‹ํ•  ๋•Œ ์ฝ”๋“œ ์ปจ๋ฒค์…˜์„ ์ž๋™์œผ๋กœ ์ฒดํฌํ•œ ํ›„, ์ปจ๋ฒค์…˜์„ ํ†ต๊ณผํ•ด์•ผ๋งŒ ์ปค๋ฐ‹๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €๋Š” Webhook ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋ชจ์•„์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” yorkie๋ฅผ ์‚ฌ์šฉํ–ˆ๊ณ ์š”, ์ฝ”๋“œ ์ปจ๋ฒค์…˜ ์ฒดํฌ๋Š” lint-staged๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. package.json์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ญ๋ชฉ์„ ์ถ”๊ฐ€ํ•˜๋ฉด, git commit์„ ์‹œ๋„ํ•  ๋•Œ๋งˆ๋‹ค lint-staged๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

"gitHooks": {
  "pre-commit": "lint-staged"
}

๋‹ค์Œ์€ lint-staged ์„ค์ •ํŒŒ์ผ์ธ lint-staged.config.js ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

module.exports = {
  '*.js': ['yarn lint:eslint', 'yarn lint:prettier', 'yarn test:unit:file'],
  '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': [
    'yarn lint:prettier --parser json',
  ],
  'package.json': ['yarn lint:prettier'],
  '*.vue': [
    'yarn lint:eslint',
    'yarn lint:stylelint',
    'yarn lint:prettier',
    'yarn test:unit:file',
  ],
  '*.scss': ['yarn lint:stylelint', 'yarn lint:prettier'],
  '*.md': ['yarn lint:markdownlint', 'yarn lint:prettier'],
  // '*.{png,jpeg,jpg,gif,svg}': ['imagemin-lint-staged'],
}

8-2. Actions๋กœ ํ…Œ์ŠคํŠธ์™€ PR ์ž๋™ํ™”ํ•˜๊ธฐ

์ €๋Š” ๋‹ค์Œ์˜ 3๊ฐ€์ง€ Workflow ํŒŒ์ผ๋“ค์„ ๋งŒ๋“ค์–ด์„œ CI๋ฅผ ์™„์„ฑํ–ˆ๊ณ ์š”, ๋‹ค์Œ ์ˆœ์„œ๋Œ€๋กœ ํ•˜์œ„ ์„น์…˜์—์„œ ์ž์„ธํžˆ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

  1. reusable-test.yml: ์ž๋™์œผ๋กœ ์‹คํ–‰ํ™˜๊ฒฝ์„ ์…‹์—…ํ•˜๊ณ  ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰
  2. develop.yml: feature/hotfix ๋ธŒ๋žœ์น˜์— ํ•œํ•ด push ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ, reusable-test.yml์„ ํ˜ธ์ถœํ•ด์„œ ํ…Œ์ŠคํŠธํ•œ ํ›„ develop ๋ธŒ๋žœ์น˜๋กœ PR์„ ์ƒ์„ฑ
  3. master.yml: develop ๋ธŒ๋žœ์น˜์˜ PR์ด ๋จธ์ง€๋˜์–ด ์ข…๋ฃŒ๋˜์—ˆ์„ ๋•Œ, reusable-test.yml์„ ํ˜ธ์ถœํ•ด์„œ ํ…Œ์ŠคํŠธํ•œ ํ›„ master ๋ธŒ๋žœ์น˜๋กœ PR์„ ์ƒ์„ฑ

reusable-test.yml

์žฌ์‚ฌ์šฉ Workflow๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋ฌธ๋ฒ•์€ Reusing workflows๋ฅผ ์ฐธ๊ณ ํ•ฉ๋‹ˆ๋‹ค.

name: Reusable - setup and test
on:
  workflow_call:
    secrets:
      token:
        required: false
jobs:
  test:
    runs-on: macos-11
    strategy:
      matrix:
        node-version: [ 14.x ]
    steps:
      - name: Checkout repo and download # step 1
        uses: actions/checkout@v2 

      - name: Install node # step 2
        uses: actions/setup-node@v2
        with:
          node-version: ${{ matrix.node-version }}

      - name: Install yarn # step 3
        run: npm install -g yarn

      - name: Set environment variables # step 4
        env: 
          VUE_APP_API_URL: ${{ secrets.VUE_APP_API_URL }}

      - name: Install all dependencies using yarn # step 5
        run: yarn install

      - name: Do unit test # step 6
        run: yarn test:unit

      - name: Do build test # step 7
        run: yarn build
  1. actions/checkout@v2๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ด ๋ ˆํฌ์ง€ํ† ๋ฆฌ์— ์ฒดํฌ์•„์›ƒ, Runner์— ๋‹ค์šด๋กœ๋“œ
  2. actions/setup-node@v2๋ฅผ ์‚ฌ์šฉํ•ด์„œ Runner์— 8/10/14 ๋ฒ„์ „์˜ node ์„ค์น˜
  3. node์™€ ํ•จ๊ป˜ ์„ค์น˜๋  npm ์ปค๋งจ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ yarn์„ ์„ค์น˜
  4. secrets ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ธํŒ…
  5. yarn ์ปค๋งจ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์˜์กดํ•˜๋Š” ๋ชจ๋“  ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜
  6. test:unit ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•ด์„œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰
  7. build ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•ด์„œ ๋นŒ๋“œ๋ฅผ ์ง„ํ–‰ (๋นŒ๋“œ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด)

develop.yml

ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด Reusable Workflow๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. uses ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , {owner}/{repo}/{path}/{filename}@{ref} ๋ฌธ๋ฒ•์œผ๋กœ ์ฐธ์กฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ๋‹ค์Œ, pr Job์€ ๋‹ค์Œ 3๋‹จ๊ณ„๋กœ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

  1. ๋ ˆํฌ์ง€ํ† ๋ฆฌ์— ์ฒดํฌ์•„์›ƒ ๋ฐ ๋‹ค์šด๋กœ๋“œ
  2. chuhlomin/render-template@v1.2๋ฅผ ์‚ฌ์šฉํ•ด์„œ PR ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜์—ฌ PR ๋ฉ”์‹œ์ง€ ์™„์„ฑ
  3. peter-evans/create-pull-request@v3๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ฝ”๋“œ๋ฆฌ๋ทฐ๋ฅผ ์œ„ํ•œ PR์„ ์ƒ์„ฑ

name: CI - feature & hotfix test
on:
  push:
    branches:
      - 'feature/**'
      - 'hotfix/**'
jobs:
  call-test:
    uses: meallo/meallo_vip/.github/workflows/reusable-test.yml@v1
  pr:
    needs: call-test
    runs-on: macos-11
    steps:
      - name: Checkout repo and download # step 1
        uses: actions/checkout@v2 

      - name: Render PR template # step 2
        id: template
        uses: chuhlomin/render-template@v1.2 # https://github.com/chuhlomin/render-template
        with:
          template: .github/PULL_REQUEST_TEMPLATE/develop.md
          var: |
            works: ...
            context: ...

      - name: Create PR to develop # step 3
        uses: peter-evans/create-pull-request@v3 # https://github.com/marketplace/actions/create-pull-request
        with:
          title: ${{ .. }}
          body: ${{ steps.template.outputs.result }}
          branch: develop
          delete-branch: false
          reviewers: ${{ secrets.DEVELOP_REVIEWER }}

master.yml

feature, develop, release ๋ธŒ๋žœ์น˜๋“ค์ด PR์„ ํ†ต๊ณผํ•˜์—ฌ develop ๋ธŒ๋žœ์น˜๋กœ ๋จธ์ง€๋  ๋•Œ๋งˆ๋‹ค reusable-test.yml Workflow๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋งˆ์ง€๋ง‰ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•œ ํ›„, master ๋ธŒ๋žœ์น˜๋กœ ์ž๋™ PR์„ ์ƒ์„ฑํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

name: CI - test and pr to master
on:
  pull_request:
    branches: [ develop ]
    types: [ closed ]
jobs:
  call-test:
    uses: meallo/meallo_vip/.github/workflows/reusable-test.yml@v1
  master-pr:
    needs: call-test
    runs-on: macos-11
    steps:
      - name: Checkout repo and download # step 1
        uses: actions/checkout@v2 

    steps:
      - name: Render PR template # step 2
        id: template
        uses: chuhlomin/render-template@v1.2
        with:
          template: .github/PULL_REQUEST_TEMPLATE/master.md
          var: |
            description: ..

      - name: Create PR to master # step 3
        uses: peter-evans/create-pull-request@v3
        with:
          title: PR to master
          body: ${{ steps.template.outputs.result }}
          branch: master
          delete-branch: false
          reviewers: ${{ secrets.MASTER_REVIEWER }}

9. CD: SSH๋กœ ์›๊ฒฉ ์„œ๋ฒ„์— ์ ‘์†ํ•ด์„œ ๋ฐฐํฌํ•˜๊ธฐ

appleboy/ssh-action๊ณผ ๊ฐ™์ด ์‰ฝ๊ฒŒ SSH ์ ‘์†์„ ์ง€์›ํ•˜๋Š” ์จ๋“œํŒŒํ‹ฐ Action๋“ค์ด ์žˆ๊ธฐ๋Š” ํ•˜์ง€๋งŒ, ์›๊ฒฉ ์„œ๋ฒ„์—์„œ ์‹คํ–‰ํ•  Shell ์ปค๋งจ๋“œ๋“ค์„ ํ•˜๋‚˜์˜ Step์— ๋ฌถ์–ด์•ผํ•˜๋Š” ๋“ฑ ์ œํ•œ์ด ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. ์ €๋Š” Job์„ ์—ฌ๋Ÿฌ ๋‹จ๊ณ„์˜ Step์œผ๋กœ ๋‚˜๋ˆ„๊ณ ์‹ถ์–ด์„œ ssh ์ปค๋งจ๋“œ๋ฅผ ์ง์ ‘ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ CD ๊ตฌ์ถ•์„ ํ–ˆ์Šต๋‹ˆ๋‹ค.


9-1. ์›๊ฒฉ ์„œ๋ฒ„์— SSH ํ‚ค๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ

์ผ๋‹จ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์›๊ฒฉ ์„œ๋ฒ„์— SSH ์ ‘์†์„ ํ•ฉ๋‹ˆ๋‹ค!

ssh username@host

๋ณดํ†ต SSH ํ‚ค๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ~/.ssh ๋””๋ ‰ํ† ๋ฆฌ์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ ‘์†ํ•œ ์›๊ฒฉ ์„œ๋ฒ„์—์„œ ์ด ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋ฆฌ์ŠคํŒ…ํ•ด๋ณด๋ฉด ์ด๋ฏธ SSH ํ‚ค๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ id_rsa์™€ ๊ฐ™์€ ์ด๋ฆ„์˜ ํŒŒ์ผ๊ณผ ๋™์ผํ•œ ํŒŒ์ผ๋ช…์˜ .pub ํ™•์žฅ์ž ํŒŒ์ผ์ด ํ•˜๋‚˜ ๋” ์žˆ๋‹ค๋ฉด SSH ๊ฐœ์ธํ‚ค์™€ ๊ณต๊ฐœํ‚ค๊ฐ€ ๋ชจ๋‘ ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐœ์ธํ‚ค๋Š” ์ง€์ •๋œ ์‚ฌ์šฉ์ž๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด๊ด€ํ•ด์•ผํ•˜๋Š” ํ‚ค์ด๊ณ , ๊ณต๊ฐœํ‚ค๋Š” ์–ด๋””์„œ๋‚˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ‚ค์ž…๋‹ˆ๋‹ค. .pub ํ™•์žฅ์ž ํŒŒ์ผ์ด ๊ณต๊ฐœํ‚ค ํŒŒ์ผ์ž…๋‹ˆ๋‹ค.

ls ~/.ssh

9-2. SSH ํ‚ค ์ƒ์„ฑํ•˜๊ธฐ: ssh-keygen

๋งŒ์•ฝ SSH ํ‚ค๊ฐ€ ์—†๋‹ค๋ฉด ssh-keygen์„ ์‚ฌ์šฉํ•˜์—ฌ ํ‚ค๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ssh-keygen์€ Linux, macOS์˜ OpenSSH ํŒจํ‚ค์ง€์— ๊ธฐ๋ณธ์œผ๋กœ ํฌํ•จ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ssh-keygen -t rsa -b 4096 -C "user@email.com"

์œ„ ์ปค๋งจ๋“œ์— ์‚ฌ์šฉ๋œ ์˜ต์…˜๋“ค์€ ๊ฐ๊ฐ ๋‹ค์Œ์„ ์˜๋ฏธํ•˜๋Š”๋ฐ์š”, SSH ํ‚ค๋ฅผ ์ƒ์„ฑํ•˜๋ฉด์„œ ๊ธฐ์กด์˜ ํ‚ค ํŒŒ์ผ์„ ๋ฎ์–ด์“ฐ์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ์„œ๋ฒ„์™€์˜ ์—ฐ๊ฒฐ์— ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

  • -t: ์•”ํ˜ธํ™” ํƒ€์ž…, ๋””ํดํŠธ ๊ฐ’์€ rsa (RSA ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์‚ฌ์šฉ)
  • -b: ์•”ํ˜ธ์˜ bit ์ˆ˜, ๋””ํดํŠธ ๊ฐ’์€ 2048
  • -f: ์ €์žฅํ•  ํŒŒ์ผ ์œ„์น˜์™€ ํŒŒ์ผ๋ช… (-f path/file_name)
  • -C: ์ฃผ์„

์ปค๋งจ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด passphrase๋ฅผ ์ž…๋ ฅ๋ž€์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ์˜ต์…˜์ด๋ฏ€๋กœ ๋นˆ์นธ์œผ๋กœ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๊ณ , ๋งŒ์•ฝ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๊ฐœ์ธํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ ‘์†์„ ์‹œ๋„ํ•  ๋•Œ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ์„ ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค.

Enter passphrase (empty for no passphrase):
Enter same passphrase again:

ํ‚ค ์ƒ์„ฑ์ด ์™„๋ฃŒ๋˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์•ˆ๋‚ด๋ฌธ๊ตฌ๊ฐ€ ์ถœ๋ ฅ๋˜๊ณ ์š”, ๋ณ„๋„๋กœ -f ์˜ต์…˜์„ ๋ช…์‹œํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด ๋””ํดํŠธ ํŒŒ์ผ๊ฒฝ๋กœ๋Š” ~/.ssh/id_rsa, ~/.ssh/id_rsa.pub์ด ๋ฉ๋‹ˆ๋‹ค.

Your identification has been saved in /home/user/.ssh/id_rsa.
Your public key has been saved in /home/user/.ssh/id_rsa.pub.
The key fingerprint is:
...
The key's randomart image is:
+---[RSA 4096]----+
|           o*=*++|
|           + +=+.|
|            o=E. |
|             .O o|
|      . S   .o +o|
|     . * o ..o ..|
|      * + +  .+. |
|     . * +   .o. |
|      . *=o .oo. |
+----[SHA256]-----+

์ƒ์„ฑ๋œ ํŒŒ์ผ์„ ์—ด์–ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด -----BEGIN RSA PRIVATE KEY-----๋กœ ์‹œ์ž‘ํ•˜๋Š” PEM ํฌ๋งท์˜ ํ‚ค ํŒŒ์ผ์ด ์ž˜ ๋งŒ๋“ค์–ด์กŒ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----

์ฐธ๊ณ ๋กœ, ์ƒ์„ฑ๋œ ๊ณต๊ฐœํ‚ค์˜ ๊ฐ’์€ authorized_keys์— ๋ช…์‹œํ•ด์•ผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

cd ~/.ssh
cat id_rsa.pub >> authorized_keys

9-3. SSH ๊ฐœ์ธํ‚ค๋ฅผ Github Secret์— ๋“ฑ๋ก

๊ฐœ์ธํ‚ค๋Š” ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด๊ด€ํ•˜๊ธฐ ์œ„ํ•ด Github Secrets์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ~/.ssh/id_rsa ํŒŒ์ผ์„ ์—ด์–ด ๋‚ด์šฉ์„ ๋ชจ๋‘ ๋ณต์‚ฌํ•œ ํ›„, ๊ทธ๋Œ€๋กœ ๋ณด๊ด€ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด๋•Œ ํ‚ค ๊ฐ’๋งŒ ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, -----BEGIN RSA PRIVATE KEY-----์™€ -----END RSA PRIVATE KEY-----๋ฅผ ํฌํ•จํ•œ PEM ํฌ๋งท์˜ ํŒŒ์ผ ๋‚ด์šฉ ์ „์ฒด๋ฅผ ๊ทธ๋Œ€๋กœ ์ €์žฅํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. Github Actions Workflow์—์„œ SSH ์ ‘์†์— ์‚ฌ์šฉํ•  pem ํŒŒ์ผ์„ ์ƒ์„ฑํ•  ๋•Œ ์ด Secret ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•จ์ด์ฃ .


์ €๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด PROD_SERVER_SSH_PRIVATEKEY๋ผ๋Š” ์ด๋ฆ„์œผ๋กœ ์ถ”๊ฐ€ํ–ˆ๊ณ ์š”, Workflow์—์„œ ${{ secrets.PROD_SERVER_SSH_PRIVATEKEY }} ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.



9-4. Job ์ž‘์„ฑํ•˜๊ธฐ

์ด์ œ Job์„ ์ž‘์„ฑํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์ œ๊ฐ€ ์ž‘์„ฑํ•œ Job์ž…๋‹ˆ๋‹ค.

name: CD

on:
  pull_request:
    branches: [ master ]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      # 1: Checks-out your repository
      - uses: actions/checkout@v2
      
      # 2: Configure SSH
      - name: Configure SSH
        env:
          PROD_SERVER_IP: ${{ secrets.PROD_SERVER_IP }}
          PROD_SERVER_SSH_USERNAME: ${{ secrets.PROD_SERVER_SSH_USERNAME }}
          PROD_SERVER_SSH_PRIVATEKEY: ${{ secrets.PROD_SERVER_SSH_PRIVATEKEY }}
        run: |
          mkdir -p ~/.ssh
          chmod 700 ~/.ssh
          echo "$PROD_SERVER_SSH_PRIVATEKEY" > ~/.ssh/keyname.pem
          chmod 600 ~/.ssh/keyname.pem
          cat <<EOF >> ~/.ssh/config
          Host hostname
            HostName $PROD_SERVER_IP
            User $PROD_SERVER_SSH_USERNAME
            IdentityFile ~/.ssh/keyname.pem
            StrictHostKeyChecking no
          EOF
          chmod 700 ~/.ssh/config

      # 3: Connect to server, git pull
      - name: Git pull
        env:
          GH_USER_NAME: ${{ secrets.GH_USER_NAME }}
          ORIGIN_URL: https://${{ secrets.GH_USER_TOKEN }}@github.com/${{ github.repository }}.git
        run: |
          ssh hostname "cd appname && 
          git config user.name ${GH_USERNAME} && 
          git remote set-url origin ${ORIGIN_URL} &&
          sudo git checkout master &&
          sudo git pull"

      # 4: Connect to server, set env
      - name: Set env
        env:
          VUE_APP_API_URL: ${{ secrets.VUE_APP_API_URL }}
        run: |
          ssh hostname "cd appname && 
          echo VUE_APP_API_URL=${VUE_APP_API_URL} > .env"

      # 5: Connect to server, install packages and build app
      - name: Install packages & Build
        run: |
        ssh hostname "cd appname && 
        sudo yarn install && 
        sudo yarn build"

SSH ์„ค์ •

env:
  PROD_SERVER_IP: ${{ secrets.PROD_SERVER_IP }}
  PROD_SERVER_SSH_USERNAME: ${{ secrets.PROD_SERVER_SSH_USERNAME }}
  PROD_SERVER_SSH_PRIVATEKEY: ${{ secrets.PROD_SERVER_SSH_PRIVATEKEY }}

์ด ๋‹จ๊ณ„์—์„œ๋Š” ์œ„์˜ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋“ค์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.


~/.ssh ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ
mkdir -p ~/.ssh
chmod 700 ~/.ssh

๋จผ์ € ~/.ssh ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ~/.ssh ๋””๋ ‰ํ† ๋ฆฌ๋Š” ssh ์ปค๋งจ๋“œ๋ฅผ ์ตœ์ดˆ๋กœ ์‚ฌ์šฉํ•  ๋•Œ ์ƒ์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์•„์ง ์ด ๋””๋ ‰ํ† ๋ฆฌ๋Š” ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๊ณ , chmod 700 ์ปค๋งจ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์†Œ์œ ์ž๊ฐ€ ์ฝ๊ณ , ์“ฐ๊ณ , ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์‚ฌ์šฉ์ž ๊ถŒํ•œ์„ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.


SSH ํ‚คํŒŒ์ผ ์ƒ์„ฑ
echo "$PROD_SERVER_SSH_PRIVATEKEY" > ~/.ssh/keyname.pem
chmod 600 ~/.ssh/keyname.pem

์ด์ œ echo ์ปค๋งจ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ~/.ssh/keyname.pem ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ , $PROD_SERVER_SSH_PRIVATEKEY ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ํŒŒ์ผ ๋‚ด์šฉ์œผ๋กœ Redirect ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ "$PROD_SERVER_SSH_PRIVATEKEY"์—์„œ ์Œ๋”ฐ์˜ดํ‘œ(")๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” $PROD_SERVER_SSH_PRIVATEKEY ๋ณ€์ˆ˜์˜ ์น˜ํ™˜๊ฐ’์— ์ค„๋ฐ”๊ฟˆ ์—ฌ๋ฐฑ์ด ํฌํ•จ๋˜์–ด ์žˆ์–ด ํ•˜๋‚˜์˜ ๋ฌธ์ž์—ด๋กœ ๋ฌถ์–ด์ค˜์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.


๊ทธ๋‹ค์Œ chmod 600 ์ปค๋งจ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ํŒŒ์ผ์˜ ์†Œ์œ ์ž๋งŒ ์ฝ๊ณ  ์“ธ ์ˆ˜ ์žˆ๋„๋ก ์‚ฌ์šฉ์ž ๊ถŒํ•œ์„ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค. ๋””ํดํŠธ ๊ถŒํ•œ์ธ 644๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ์ „ํ•˜์ง€ ์•Š๋‹ค๊ณ  ๋ณด๊ธฐ ๋•Œ๋ฌธ์— SSH ์ ‘์†์‹œ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ SSH ์‚ฌ์šฉ์„ ์‹œ๋„ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ๊ณ ๊ฐ€ ๋‚˜ํƒ€๋‚˜๊ณ  ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž…๋ ฅ์ด ๊ฐ•์ œ๋ฉ๋‹ˆ๋‹ค.

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '~/.ssh/keyname.pem' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "~/.ssh/keyname.pem": bad permissions

SSH ํ˜ธ์ŠคํŠธ ์ •๋ณด ์ €์žฅ
cat <<EOF >> ~/.ssh/config
Host hostname
  HostName $PROD_SERVER_IP
  User $PROD_SERVER_SSH_USERNAME
  IdentityFile ~/.ssh/keyname
  StrictHostKeyChecking no
EOF
chmod 700 ~/.ssh/config

~/.ssh/config๋Š” SSH ์„ค์ • ํŒŒ์ผ์ž…๋‹ˆ๋‹ค. ํ˜ธ์ŠคํŠธ๋ณ„๋กœ ์ •๋ณด๋ฅผ ์ €์žฅํ•ด๋†“๊ณ , ssh ์ปค๋งจ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํ˜ธ์ŠคํŠธ ๋ณ„๋ช…์œผ๋กœ ๊ฐ„ํŽธํ•˜๊ฒŒ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. <<EOF๋Š” EOF ํ‚ค์›Œ๋“œ๊ฐ€ ๋‚˜์˜ค๊ธฐ ์ „๊นŒ์ง€์˜ ๋‚ด์šฉ์„ ์ž…๋ ฅํ•œ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.


์•„๋ž˜๋Š” ~/.ssh/config ํŒŒ์ผ์˜ ์œ ํšจ ํ˜•์‹์ž…๋‹ˆ๋‹ค. ์ด ํŒŒ์ผ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์„ค๋ช…์ด ํ•„์š”ํ•˜์‹œ๋‹ค๋ฉด Using the SSH Config File | Linuxize ๋ฌธ์„œ๊ฐ€ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

Host hostname1
    SSH_OPTION value
    SSH_OPTION value

Host hostname2
    SSH_OPTION value

Host *
    SSH_OPTION value

Git Pull

env:
  GH_USER_NAME: ${{ secrets.GH_USER_NAME }}
  ORIGIN_URL: https://${{ secrets.GH_USER_TOKEN }}@github.com/${{ github.repository }}.git

์ด์ œ SSH ์„ค์ •์ด ์™„๋ฃŒ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์—, SSH๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐํฌ์šฉ ์„œ๋ฒ„์— ์ ‘์†ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด ๋‹จ๊ณ„์—์„œ๋Š” git pull์„ ํ•˜๊ธฐ ์œ„ํ•ด ์œ„์˜ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋“ค์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ €๋Š” Github ๋ ˆํฌ Authentication์— ํ•„์š”ํ•œ ์‚ฌ์šฉ์ž ์ด๋ฆ„๊ณผ ํ•ด๋‹น ์‚ฌ์šฉ์ž์˜ Access Token์„ Secrets์— ๋ฏธ๋ฆฌ ์ถ”๊ฐ€ํ•ด๋‘์—ˆ์Šต๋‹ˆ๋‹ค. (GH_USER_NAME, GH_USER_TOKEN)


๊ทธ๋ฆฌ๊ณ  Git์˜ ์›๊ฒฉ ๋ ˆํฌ์ง€ํ† ๋ฆฌ URL๋กœ ์‚ฌ์šฉํ•  ํ™˜๊ฒฝ๋ณ€์ˆ˜ ORIGIN_URL์„ ์œ„์™€ ๊ฐ™์ด ์„ธํŒ…ํ–ˆ๋Š”๋ฐ์š”, ์›๊ฒฉ ๋ ˆํฌ์ง€ํ† ๋ฆฌ URL์— Access Token์„ ํฌํ•จํ•ด๋‘๋ฉด git ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋งค๋ฒˆ ํ† ํฐ์„ ์ž…๋ ฅํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค! ์ฐธ๊ณ ๋กœ github.repository๋Š” Github Actions์—์„œ ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ์ปจํ…์ŠคํŠธ ๋ณ€์ˆ˜์ž…๋‹ˆ๋‹ค.


SSH๋กœ ๋ฐฐํฌ์šฉ ์„œ๋ฒ„์— ์—ฐ๊ฒฐ
run: |
  ssh hostname "cd appname && 
  git config user.name ${GH_USERNAME} && 
  git remote set-url origin ${ORIGIN_URL} &&
  sudo git checkout master &&
  sudo git pull"

์ด์ œ ssh hostname ์ปค๋งจ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐฐํฌ์šฉ ์„œ๋ฒ„์— ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค. ์—ฐ๊ฒฐ๋œ ์„œ๋ฒ„์—์„œ ์‹คํ–‰ํ•  ์ปค๋งจ๋“œ๋Š” ์Œ๋”ฐ์˜ดํ‘œ(") ์•ˆ์— ์ž‘์„ฑํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด๋•Œ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์น˜ํ™˜๊ฐ’์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํ™€๋”ฐ์˜ดํ‘œ(')๊ฐ€ ์•„๋‹Œ ์Œ๋”ฐ์˜ดํ‘œ(")๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. Bash ์‰˜์˜ ๋”ฐ์˜ดํ‘œ ๋ฌธ๋ฒ•์— ๋Œ€ํ•œ ์„ค๋ช…์ด ํ•„์š”ํ•˜์‹œ๋ฉด Unix/Linux Shell Quoting for remote shells ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•ด๋ณด์„ธ์š”.


๋ฐฐํฌ์šฉ ์„œ๋ฒ„์— ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์ถ”๊ฐ€

env:
  VUE_APP_API_URL: ${{ secrets.VUE_APP_API_URL }}

run: |
  ssh hostname "cd appname && 
  echo VUE_APP_API_URL=${VUE_APP_API_URL} > .env"

์ด์ œ ์œ„์™€ ๊ฐ™์ด ์•ฑ ์‹คํ–‰์— ํ•„์š”ํ•œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋“ค์„ .env ํŒŒ์ผ์— ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ๋Š” echo > ์ปค๋งจ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ๋‹ค์Œ ๋ณ€์ˆ˜๋ถ€ํ„ฐ๋Š” ํŒŒ์ผ์„ ๋ฎ์–ด์“ฐ์ง€ ์•Š๊ณ  Appendํ•˜๊ธฐ ์œ„ํ•ด >>๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.


ํŒจํ‚ค์ง€ ์„ค์น˜ & ๋นŒ๋“œ

ssh hostname "cd appname && 
        sudo yarn install && 
        sudo yarn build"

๋งˆ์ง€๋ง‰์œผ๋กœ ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•˜๊ณ  ์•ฑ์„ ๋นŒ๋“œํ•ฉ๋‹ˆ๋‹ค!



References