- GitHub Actions๋, Workflow ๋ฑ๋กํ๊ธฐ](./#user-content-1-github-actions๋-workflow-๋ฑ๋กํ๊ธฐ
- GitHub Actions ์ํน ํ๋ก์ธ์ค: Runner, Jobs, Steps, Actions
- Workflow ํ์ผ ์์ฑํ๊ธฐ
- ์ฌ์ฌ์ฉํ๊ธฐ: Reusable Workflow, Runner ํ๊ฒฝ ์บ์ฑํ๊ธฐ
- ํ๊ฒฝ๋ณ์ ์ฌ์ฉํ๊ธฐ: ์ง์ ์ธํ , GitHub ๋ํดํธ ํ๊ฒฝ๋ณ์
- ์ปจํ ์คํธ ๋ณ์ ์ฌ์ฉํ๊ธฐ, ํ๊ฒฝ๋ณ์์์ ์ฐจ์ด์
secrets
์ปจํ ์คํธ๋ฅผ ์ฌ์ฉํ์ฌ ํ๊ฒฝ๋ณ์ ์ธํ ํ๊ธฐ- CI: Webhook์ผ๋ก ์ฝ๋ ์ปจ๋ฒค์ ์๋ ์ฒดํฌ, Actions๋ก ํ ์คํธ์ PR ์๋ํํ๊ธฐ
- CD: SSH๋ก ์๊ฒฉ ์๋ฒ์ ์ ์ํด์ ๋ฐฐํฌํ๊ธฐ
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.
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
์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ ๋ ์ฌ๋ฌ ๊ฐ์ Job๋ค์ด ์คํ๋๋๋ก Workflow๋ฅผ ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ๊ฐ Job์ ์ง์ ํ Runner ์์์ ์คํ๋ฉ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก Job๋ค์ ์์ฐจ๊ฐ ์๋ ๋ณ๋ ฌ์ ์ผ๋ก ์คํ๋ฉ๋๋ค. ํ์ง๋ง needs
ํญ๋ชฉ์ ์ฌ์ฉํด ํน์ Job์ด ์ฑ๊ณตํ์ ๋๋ง ๋ค๋ฅธ Job์ด ์คํ๋๋๋ก ์์ฐจ ์ง์ ํ ์๋ ์์ต๋๋ค.
jobs:
build:
needs: setup # setup์ด ๋๋์ผ build๊ฐ ์คํ๋ฉ๋๋ค
Step์ Job ๋ด์์ ๊ฐ๋ณ ์ ๋ฌด๋ค์ ๋งํฉ๋๋ค. Step์ด๋ผ๋ ์ด๋ฆ์ฒ๋ผ ์ง์ ํ ์์๋๋ก ๋จ๊ณ์ ์ผ๋ก ์คํ๋ฉ๋๋ค. Step์ ํ๋์ Action์ด ๋ ์๋ ์๊ณ , Shell ์ปค๋งจ๋๊ฐ ๋ ์๋ ์์ต๋๋ค.
Action์ Workflow๋ฅผ ์ด๋ฃจ๋ ๊ฐ์ฅ ์์ Work ๋จ์์
๋๋ค. Action์ ์ง์ ๋ง๋ค๊ฑฐ๋, GitHub ์ปค๋ฎค๋ํฐ์์ ์ ๊ณตํ๋ Action๋ค์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ ํฌ์งํ ๋ฆฌ ์ฒดํฌ์์, node
์ค์น ๋ฑ ๊ธฐ๋ณธ์ ์ธ ๊ฑฐ์ ๋ชจ๋ ๋์๊ณผ ์
์
Action๋ค์ด ์ปค๋ฎค๋ํฐ์์ ์ด๋ฏธ ์ ๊ณต๋๊ณ ์์ต๋๋ค.
์ด์ Workflow ํ์ผ ์์ ๋ฅผ ์์ฑํด๋ณด๋ฉด์ ํ์ผ์ ๊ตฌ์ฑํ๋ ๊ธฐ๋ณธ์ ์ธ ๋ฌธ๋ฒ๋ค์ ์ ๋ฆฌํ๋ ค๊ณ ํฉ๋๋ค.
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:
# ...
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:
# ...
๊ฐ 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
์ฌ๋ฌ Workflow์์ ๋์ผํ ์์
์ด ์ฌ์ฉ๋์ด ์์
์ด ์ค๋ณต๋ ๋ ์ด๋ฅผ ํผํ๊ธฐ ์ํด Workflow๋ฅผ ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค. ์์ง ๋ฒ ํ ๋จ๊ณ์ด๋ฉฐ ๋ช๊ฐ์ง ์ ํ์ด ์๊ธฐ ๋๋ฌธ์ Reusing workflows ๋ฌธ์๋ฅผ ๊ผผ๊ผผํ ํ์ธํ์ธ์. ์ ํ์ฌํญ ์ค ์ฃผ๋ชฉํ ๋งํ ๊ฒ์ env
์ปจํ
์คํธ๋ฅผ ๊ณต์ ํ ์ ์๋ค๋ ๊ฒ, ์ฌ์ฌ์ฉ Workflow์์ ๋ค๋ฅธ ์ฌ์ฌ์ฉ Workflow๋ฅผ ์ฌ์ฉํ ์ ์๋ค๋ ๊ฒ์
๋๋ค.
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๊ฐ ๋์์ด ๋์์ต๋๋ค.
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.
๊ธฐ๋ณธ์ ์ธ ๊ฐ๋ค์ GitHub์์ ๋ํดํธ ํ๊ฒฝ๋ณ์๋ก ์ ๊ณตํฉ๋๋ค. ๊ณต์๋ฌธ์์ Default environment variables ์น์ ์์ ๋ชจ๋ ๋ํดํธ ํ๊ฒฝ๋ณ์ ๋ชฉ๋ก์ ํ์ธํ ์ ์์ต๋๋ค.
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"
ํ๋ก๊ทธ๋จ์์ ์ฌ์ฉํ๋ ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ ์ค 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 }}
์ฐ๋ฆฌํ์ Vue2, Yarn์ ์ฌ์ฉํ๊ณ , GitFlow๋ฅผ ๋ณํํ ๋ธ๋์น ์ ๋ต์ ์ฌ์ฉํฉ๋๋ค.
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'],
}
์ ๋ ๋ค์์ 3๊ฐ์ง Workflow ํ์ผ๋ค์ ๋ง๋ค์ด์ CI๋ฅผ ์์ฑํ๊ณ ์, ๋ค์ ์์๋๋ก ํ์ ์น์ ์์ ์์ธํ ๋ค๋ฃน๋๋ค.
reusable-test.yml
: ์๋์ผ๋ก ์คํํ๊ฒฝ์ ์ ์ ํ๊ณ ๋จ์ ํ ์คํธ๋ฅผ ์คํdevelop.yml
:feature
/hotfix
๋ธ๋์น์ ํํดpush
์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ ๋,reusable-test.yml
์ ํธ์ถํด์ ํ ์คํธํ ํdevelop
๋ธ๋์น๋ก PR์ ์์ฑmaster.yml
:develop
๋ธ๋์น์ PR์ด ๋จธ์ง๋์ด ์ข ๋ฃ๋์์ ๋,reusable-test.yml
์ ํธ์ถํด์ ํ ์คํธํ ํmaster
๋ธ๋์น๋ก PR์ ์์ฑ
์ฌ์ฌ์ฉ 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
actions/checkout@v2
๋ฅผ ์ฌ์ฉํด์ ์ด ๋ ํฌ์งํ ๋ฆฌ์ ์ฒดํฌ์์, Runner์ ๋ค์ด๋ก๋actions/setup-node@v2
๋ฅผ ์ฌ์ฉํด์ Runner์8
/10
/14
๋ฒ์ ์node
์ค์นnode
์ ํจ๊ป ์ค์น๋npm
์ปค๋งจ๋๋ฅผ ์ฌ์ฉํด์yarn
์ ์ค์นsecrets
์ปจํ ์คํธ๋ฅผ ์ฌ์ฉํด์ ํ๊ฒฝ๋ณ์ ์ธํyarn
์ปค๋งจ๋๋ฅผ ์ฌ์ฉํด์ ์์กดํ๋ ๋ชจ๋ ํจํค์ง๋ฅผ ์ค์นtest:unit
์คํฌ๋ฆฝํธ๋ฅผ ์คํํด์ ๋จ์ ํ ์คํธ๋ฅผ ์งํbuild
์คํฌ๋ฆฝํธ๋ฅผ ์คํํด์ ๋น๋๋ฅผ ์งํ (๋น๋ ํ ์คํธ๋ฅผ ์ํด)
ํ
์คํธ๋ฅผ ์ํด Reusable Workflow๋ฅผ ํธ์ถํฉ๋๋ค. uses
ํค๋ฅผ ์ฌ์ฉํ๊ณ , {owner}/{repo}/{path}/{filename}@{ref}
๋ฌธ๋ฒ์ผ๋ก ์ฐธ์กฐํฉ๋๋ค. ๊ทธ ๋ค์, pr
Job์ ๋ค์ 3๋จ๊ณ๋ก ๊ตฌ์ฑํฉ๋๋ค.
- ๋ ํฌ์งํ ๋ฆฌ์ ์ฒดํฌ์์ ๋ฐ ๋ค์ด๋ก๋
chuhlomin/render-template@v1.2
๋ฅผ ์ฌ์ฉํด์ PR ํ ํ๋ฆฟ์ ์ฌ์ฉํ์ฌ PR ๋ฉ์์ง ์์ฑ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 }}
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 }}
appleboy/ssh-action
๊ณผ ๊ฐ์ด ์ฝ๊ฒ SSH ์ ์์ ์ง์ํ๋ ์จ๋ํํฐ Action๋ค์ด ์๊ธฐ๋ ํ์ง๋ง, ์๊ฒฉ ์๋ฒ์์ ์คํํ Shell ์ปค๋งจ๋๋ค์ ํ๋์ Step์ ๋ฌถ์ด์ผํ๋ ๋ฑ ์ ํ์ด ๋ฐ๋ฆ
๋๋ค. ์ ๋ Job์ ์ฌ๋ฌ ๋จ๊ณ์ Step์ผ๋ก ๋๋๊ณ ์ถ์ด์ ssh
์ปค๋งจ๋๋ฅผ ์ง์ ์คํํ๋ ๋ฐฉ๋ฒ์ผ๋ก CD ๊ตฌ์ถ์ ํ์ต๋๋ค.
์ผ๋จ ๋น๋ฐ๋ฒํธ๋ฅผ ์ฌ์ฉํ์ฌ ์๊ฒฉ ์๋ฒ์ SSH ์ ์์ ํฉ๋๋ค!
ssh username@host
๋ณดํต SSH ํค๋ ๊ธฐ๋ณธ์ ์ผ๋ก ~/.ssh
๋๋ ํ ๋ฆฌ์ ์์ต๋๋ค. ์ ์ํ ์๊ฒฉ ์๋ฒ์์ ์ด ๋๋ ํ ๋ฆฌ๋ฅผ ๋ฆฌ์คํ
ํด๋ณด๋ฉด ์ด๋ฏธ SSH ํค๊ฐ ์กด์ฌํ๋์ง ํ์ธํ ์ ์์ต๋๋ค. ๋ง์ฝ id_rsa
์ ๊ฐ์ ์ด๋ฆ์ ํ์ผ๊ณผ ๋์ผํ ํ์ผ๋ช
์ .pub
ํ์ฅ์ ํ์ผ์ด ํ๋ ๋ ์๋ค๋ฉด SSH ๊ฐ์ธํค์ ๊ณต๊ฐํค๊ฐ ๋ชจ๋ ์๋ ๊ฒ์
๋๋ค. ๊ฐ์ธํค๋ ์ง์ ๋ ์ฌ์ฉ์๋ง ์ฌ์ฉํ ์ ์๊ธฐ ๋๋ฌธ์ ์์ ํ๊ฒ ๋ณด๊ดํด์ผํ๋ ํค์ด๊ณ , ๊ณต๊ฐํค๋ ์ด๋์๋ ์ฌ์ฉํ ์ ์๋ ํค์
๋๋ค. .pub
ํ์ฅ์ ํ์ผ์ด ๊ณต๊ฐํค ํ์ผ์
๋๋ค.
ls ~/.ssh
๋ง์ฝ 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
๊ฐ์ธํค๋ ์์ ํ๊ฒ ๋ณด๊ดํ๊ธฐ ์ํด 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 }}
๊ตฌ๋ฌธ์ ์ฌ์ฉํ์ฌ ์ ๊ทผํ ์ ์์ต๋๋ค.
์ด์ 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"
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 }}
์ด ๋จ๊ณ์์๋ ์์ ํ๊ฒฝ๋ณ์๋ค์ด ํ์ํฉ๋๋ค.
mkdir -p ~/.ssh
chmod 700 ~/.ssh
๋จผ์ ~/.ssh
๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑํฉ๋๋ค. ~/.ssh
๋๋ ํ ๋ฆฌ๋ ssh
์ปค๋งจ๋๋ฅผ ์ต์ด๋ก ์ฌ์ฉํ ๋ ์์ฑ๋๊ธฐ ๋๋ฌธ์ ์์ง ์ด ๋๋ ํ ๋ฆฌ๋ ์กด์ฌํ์ง ์๊ธฐ ๋๋ฌธ์
๋๋ค. ๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑํ๊ณ , chmod 700
์ปค๋งจ๋๋ฅผ ์ฌ์ฉํ์ฌ ์์ ์๊ฐ ์ฝ๊ณ , ์ฐ๊ณ , ์คํํ ์ ์๋๋ก ์ฌ์ฉ์ ๊ถํ์ ์์ ํฉ๋๋ค.
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
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
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์์ ๊ธฐ๋ณธ์ผ๋ก ์ ๊ณตํ๋ ์ปจํ
์คํธ ๋ณ์์
๋๋ค.
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"
๋ง์ง๋ง์ผ๋ก ํจํค์ง๋ฅผ ์ค์นํ๊ณ ์ฑ์ ๋น๋ํฉ๋๋ค!
- Continuous Integration - Martin Fowler
- Software Delivery Guide - Martin Fowler
- Deployment Pipelines (CI/CD) in Software Engineering - Dan Merron
- Understanding GitHub Actions | GitHub Docs
- About GitHub-hosted runners | GitHub Docs
- Essential features of GitHub Actions | GitHub Docs
- Reusing workflows | GitHub Docs
- About webhooks | GitHub Docs
- Github Actions์ผ๋ก ๋ฐฐํฌ ์๋ํํ๊ธฐ | NHN Cloud Meetup
- [Github Action] Github Action ๋ง๋ณด๊ณ , AWS S3์ Vue ์๋์ผ๋ก ๋ฐฐํฌํ๊ธฐ | ๋น์ด์ ๊ฐ๋ฐ ๋ธ๋ก๊ทธ
- <Linux> SSH key์ ๊ธฐ๋ณธ ์๋ ์๋ฆฌ์ SSH ์ ์ ์ key๋ก ์ ์ํ๋ ๋ฒ | DanTheTech
- Deploying to a server via SSH and Rsync in a Github Action | Zellwk
- GitHub Actions: How to run SSH commands (without third-party actions)
- Unix/Linux Shell Quoting for remote shells
- Using the SSH Config File