-
Github Action์ผ๋ก EC2 ๋ฐฐํฌ ์๋ํํ๊ธฐDevelop/DevOps 2022. 12. 16. 23:33
๐ก Github Actions์ด๋?
Github Action์
build, test, deployment์ ๊ฐ์ workflow๋ฅผ ์๋ํํ ์ ์๋ CI/CD ํ๋ซํผ
์ผ๋ก,
github repository์์ ๋ฐ์ํ๋๋ชจ๋ ์ด๋ฒคํธ(push, pull request, merge ๋ฑ)์ ๋ํ์ฌ ์ ํด์ง ๋์์ ์คํ
์ํค๋๋ก ํ ์ ์๋ค.์งํ์ค์ธ ํ๋ก์ ํธ์์๋
docker compose
๋ฅผ ์ด์ฉํด ์๋น์ค ์ปจํ ์ด๋๋ค์ ๊ด๋ฆฌํ๊ณ ์๋ค.
์์ค์ฝ๋๊ฐ ์์ ๋ ๋๋ง๋ค ์๋์ผ๋ก ์ปจํ ์ด๋๋ฅผ ์ญ์ ํ๊ณ ๋น๋ํ๋ ๋ฐฉ์์ผ๋ก ํ ์คํธ ์๋ฒ๋ฅผ ์ด์ํ๋ค๊ฐGithub action
์ ์ฌ์ฉํ์ฌ CI/CD๋ฅผ ์๋ํํด๋ณด๊ธฐ๋ก ํ๋ค.๐ค CI/CD ํ๋ก์ธ์ค ์ค๊ณํด๋ณด๊ธฐ
๋ค์๊ณผ ๊ฐ์ ํ๋ก์ธ์ค๋ค์ ์๋ํ์ํค๋ ค ํ์๋ค.
.github/workflow์ YAMLํ์ผ ์์ฑ 1. ์์ฑ๋ pull request์ ๋ํ์ฌ
์๋์ผ๋ก build ํ ์คํธ๋ฅผ ์ํ
→ ์คํจ์ merge ๋ถ๊ฐ2. main branch์ pull request๊ฐ merge๋ ๊ฒฝ์ฐ,
a) production ์๋ฒ์ ๋์ํ๋ ์ปจํ ์ด๋๋ฅผ ์ค์ง / dangling image๋ฅผ ์ญ์ ํ์ฌ ์๋ฒ ์ฌ์ ๊ณต๊ฐ ํ๋ณด
b) production ์๋ฒ์์๋ก์ด container๋ค์ ๋น๋
c) container๊ฐ ์ ์์ ์ผ๋ก ๋์ํ์ง ์๋ ๊ฒฝ์ฐ,rollback
3. pull request๋ฅผ ํ์ฉํ ์์ค์ฝ๋
release, tag ์์ฑ ๋ฐ ๊ด๋ฆฌ ์๋ํ
๐ Github๋ฅผ ํ์ฉํ CI/CD ํ๊ฒฝ ๊ด๋ฆฌ
Repository > Settings > Secrets
๋ฅผ ์ฌ์ฉํ์ฌ ํ๊ฒฝ๋ณ์๋ฅผ ์ธํ ํ๋ค.
workflow์์ env ํ์ผ์ ์์ฑํ๊ณ secrets๊ฐ์ ๋๊ฒจ์ฃผ๋ ๋ฐฉ์์ผ๋ก ๊ด๋ฆฌํ๋ค.Self-Hosted Runner
๋ฅผ ๋ฑ๋กํ์ฌ ๊ด๋ฆฌ ์ค์ธ ์๋ฒ์์ ์๋์ผ๋ก ๋น๋์ ๋ฐฐํฌ๋ฅผ ์ํํ๋๋ก ํ์๋ค.
runner๋ ํ๋ก์ ํธ์ EC2 instance์์ daemon์ผ๋ก ๋์ํ๊ณ ์๋ค.โ๏ธ Workflow ๊ตฌํํ๊ธฐ
1.
build.yml
- ์์ฑ๋ pull request์ ๋ํ์ฌ ์๋์ผ๋ก build ํ ์คํธ๋ฅผ ์ํํ๋ workflow
- ubuntu ํ๊ฒฝ ๊ตฌ์ฑ / container์ ๋์์ ๊ด๋ฆฌํ๋ shell script๋ฅผ ์ํํ๋ step์ ์คํํ๋๋ก ๊ตฌํname: Build Test # pull request event์ ๋ํ์ฌ trigger๋๋ workflow on: [pull_request] jobs: build: runs-on: ubuntu-latest steps: # ํ๋ก์ ํธ ์์ค์ฝ๋๋ฅผ ๋ฆฌ๋ ์ค ํ๊ฒฝ์ checkoutํ๊ณ ์คํํ๋๋ก ๋ช ์ - name: Checkout source code uses: actions/checkout@v3 # ํด๋น workflow๋ฅผ python3.8 ํ๊ฒฝ์์ ์คํํ๊ฒ ๋ค๊ณ ๋ช ์ - name: Setup python uses: actions/setup-python@v3 with: python-version: "3.8" # ๋ฆฌ๋ ์ค ํ๊ฒฝ์ docker๋ฅผ ์ธํ ํ๋ shell script๋ฅผ ์คํ - name: Setup Docker run: sh scripts/setup-docker.sh # ${{ secrets.* }} ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ Settings > Secrets > Actions์ ์ ์ํ ๊ฐ์ ๊ฐ์ ธ์ค๊ณ # .envํ์ผ์ ์์ฑํ์ฌ devํ๊ฒฝ์ ํ๊ฒฝ๋ณ์๋ฅผ ๊ด๋ฆฌ - name: Create env file run: | touch ${{ secrets.ENV_PATH }} { echo SECRET_KEY="\"${{ secrets.SECRET_KEY }}"\" echo RUN_ENV="\"${{ secrets.RUN_ENV }}"\" echo DOMAIN="\"${{ secrets.DOMAIN }}"\" echo PROD_ALLOWED_HOSTS='${{ secrets.PROD_ALLOWED_HOSTS }}' echo CORS_ORIGIN_WHITELIST='${{ secrets.CORS_ORIGIN_WHITELIST }}' ... } >> ${{ secrets.ENV_PATH }} # containter๋ฅผ ๋น๋ํ๊ณ ๋ฐฐํฌํ๋ shell script๋ฅผ ์ํ - name: Build Docker containers run: sudo kill `sudo lsof -t -i:8084` && sh scripts/build-docker-compose.sh # container์ ๋์ ์ํ๋ฅผ ํ์ธํ ๋ค job์ ์ข ๋ฃ - name: Check container running state run: | if [ $(docker ps --format "{{.Names}} {{.Status}}" | grep "Up" | wc -l) -ne 3 ] then echo "Build error while running docker-compose" exit 1 else echo "Deploy Complete" fi
2.
schedule-deploy.yml
- production ์๋ฒ์ ๋์ํ๋ ์ปจํ ์ด๋๋ฅผ ์ค์ง / dangling image๋ฅผ ์ญ์ ํ์ฌ ์๋ฒ ๊ณต๊ฐ์ ํ๋ณดํ๋ ๋์์ ๋ณ๋์ shell script๋ก ์์ฑํ์ฌ workflow์ step์์ ์คํ
- production ์๋ฒ์ ์๋ก์ด container๋ค์ ๋น๋ ๋ฐ ๋ฐฐํฌํ๋ค ๋์ ์ํ๋ฅผ ํ์ธ
- ์ ์์ ์ผ๋ก ๋์ํ์ง ์๋ ๊ฒฝ์ฐ, ์ด์ ๋ฒ์ ์ release๋ก rollbackname: Schedule Deployment # main branch๋ฅผ target์ผ๋ก ํ๋ pull request๊ฐ closed๋์์ ๊ฒฝ์ฐ์๋ง ๋์ํ๋ workflow on: pull_request: branches: - main types: - closed jobs: checkout: # ํ๋ก์ ํธ๋ฅผ buildํ machine(runner)๋ฅผ ๋ช ์ runs-on: [ self-hosted, label-go ] # pull request๊ฐ merge๋ ๊ฒฝ์ฐ์๋ง checkout job์ ์ํ if: ${{ github.event.pull_request.merged == true }} steps: # runner๊ฐ workflow๋ฅผ ์ํํ ์ ์๋๋ก workspace์ permission ๋ถ์ฌ - name: Set Permissions run: sudo chown -R $USER:$USER ${{ github.workspace }} # ํ๋ก์ ํธ ์์ค์ฝ๋๋ฅผ ๋ฆฌ๋ ์ค ํ๊ฒฝ์ checkoutํ๊ณ ์คํํ๋๋ก ๋ช ์ - name: Checkout source code uses: actions/checkout@v3 # ํด๋น workflow๋ฅผ python3.8 ํ๊ฒฝ์์ ์คํํ๊ฒ ๋ค๊ณ ๋ช ์ - name: Setup python uses: actions/setup-python@v3 with: python-version: "3.8" # ๋ฆฌ๋ ์ค ํ๊ฒฝ์ docker๋ฅผ ์ธํ ํ๋ shell script๋ฅผ ์คํ - name: Setup Docker run: sh scripts/setup-docker.sh deploy: runs-on: [ self-hosted, label-go ] # checkout job์ด ์๋ฃ๋์์ ๊ฒฝ์ฐ ๋์ํ๋๋ก ์์กด๊ด๊ณ๋ฅผ ์ค์ needs: checkout if: ${{ github.event.pull_request.merged == true }} steps: # ${{ secrets.* }} ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ Settings > Secrets > Actions์ ์ ์ํ ๊ฐ์ ๊ฐ์ ธ์ค๊ณ # .envํ์ผ์ ์์ฑํ์ฌ devํ๊ฒฝ์ ํ๊ฒฝ๋ณ์๋ฅผ ๊ด๋ฆฌ - name: Create env file run: | touch ${{ secrets.ENV_PATH }} { echo SECRET_KEY="\"${{ secrets.SECRET_KEY }}"\" echo RUN_ENV="\"${{ secrets.RUN_ENV }}"\" echo DOMAIN="\"${{ secrets.DOMAIN }}"\" echo PROD_ALLOWED_HOSTS='${{ secrets.PROD_ALLOWED_HOSTS }}' echo CORS_ORIGIN_WHITELIST='${{ secrets.CORS_ORIGIN_WHITELIST }}' ... } >> ${{ secrets.ENV_PATH }} # container๋ฅผ ๋น๋ํ๊ณ ๋ฐฐํฌํ๋ shell script๋ฅผ ์ํ - name: Build Docker containers run: sh scripts/build-docker-compose.sh # container์ ๋์ ์ํ๋ฅผ ํ์ธํ ๋ค job์ ์ข ๋ฃ - name: Check container running state run: | if [ $(docker ps --format "{{.Names}} {{.Status}}" | grep "Up" | wc -l) -ne 3 ] then echo "Build error while running docker-compose" exit 1 else echo "Deploy Complete" fi rollback: runs-on: [ self-hosted, label-go ] # checkout, deploy job์ด ๋ชจ๋ ์๋ฃ๋์์ ๊ฒฝ์ฐ ๋์ํ๋๋ก ์์กด๊ด๊ณ๋ฅผ ์ค์ needs: [ checkout, deploy ] # ์์กด๊ด๊ณ๊ฐ ์ค์ ๋์ด ์๋ job๋ค ์ค ํ๋๋ผ๋ ์คํจํ์์ ๊ฒฝ์ฐ ๋์ํ๋๋ก ์กฐ๊ฑด ์ค์ if: ${{ always() && contains(needs.*.result, 'failure') }} steps: # runner๊ฐ workflow๋ฅผ ์ํํ ์ ์๋๋ก workspace์ permission ๋ถ์ฌ - name: Set Action Runner Permissions run: sudo chown -R $USER:$USER ${{ github.workspace }} # rollback job์ ์ํํ๊ธฐ ์ํ์ฌ ๋ง์ง๋ง์ผ๋ก release๋ ๋ฒ์ ์ ์์ค์ฝ๋๋ฅผ fetch - name: Fetch Latest Release id: fetch-latest uses: thebritican/fetch-latest-release@v1.0.3 with: github_token: ${{ secrets.GITHUB_TOKEN }} # fetch-latest step์์ fetchํ ๋ฒ์ ์ ์์ค์ฝ๋๋ก checkout - name: Checkout Latest Release source code uses: actions/checkout@v3 with: ref: ${{ steps.fetch-latest.outputs.tag_name }} # container๋ฅผ ๋น๋ํ๊ณ ๋ฐฐํฌํ๋ shell script๋ฅผ ์ํ - name: Build Docker containers run: sh scripts/build-docker-compose.sh # container์ ๋์ ์ํ๋ฅผ ํ์ธํ ๋ค job์ ์ข ๋ฃ - name: Check container running state run: | if [ $(docker ps --format "{{.Names}} {{.Status}}" | grep "Up" | wc -l) -ne 3 ] then echo "Build error while running docker-compose" exit 1 else echo "Deploy Complete" fi
3.
auto-release.yml
- pull request๋ฅผ ํ์ฉํ ์์ค์ฝ๋ release, tag ์์ฑ ๋ฐ ๊ด๋ฆฌ ์๋ํname: Auto Release # pull request๊ฐ opened / reopened / synchronize / edited / closed๋์์ ๋ # ๋์ํ๋ workflow on: pull_request: types: [opened, reopened, synchronize, edited, closed] jobs: release: runs-on: ubuntu-latest # pull request๊ฐ target์ผ๋ก ํ๋ branch๊ฐ main์ผ ๊ฒฝ์ฐ์๋ง ์ํ๋๋๋ก ์กฐ๊ฑด์ ์ค์ if: ${{ contains(github.base_ref, 'main') || contains(github.ref, 'main') }} steps: # workflow๋ฅผ ์คํํ๊ธฐ ์ํด ํ์ํ ์ฝ๋์ ๋ํด์๋ง sparse checkout ์ํ - name: Sparse-checkout uses: lablup/sparse-checkout@v1 with: patterns: | scripts # releaseํ version๋ช ์ output์ผ๋ก ์ ์ฅํ๋ step ์ํ - name: Extract version id: extract-version run: | # release๋ช ์ pull request์ title์ ๋ช ์๋ '์ซ์.์ซ์.์ซ์' ํฌ๋งท์ผ๋ก ์ค์ # ํด๋น ๊ท์น์ ์ค์ํ release๋ช ์ด ์กด์ฌํ์ง ์๊ฑฐ๋, ์๋ชป๋ ๊ฐ์ด ์ ๋ ฅ๋์ด ์๋ ๊ฒฝ์ฐ์๋ ์ดํ์ step์ ๋ชจ๋ skip version=$(echo '${{ github.event.pull_request.title }}' | egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}') echo "::set-output name=version::$version" # ํ์ฌ branch์ ์ด์ ๋ฒ์ release ์ฌ์ด์ commit log๋ค์ CHANGELOG_RELEASE.md์ ์ ์ฅํ๊ณ # ์กด์ฌํ๋ CHANGELOG.md๋ฅผ ์ ๋ฐ์ดํธํ๋ python script๋ฅผ ์คํ - name: Auto Generate Changelog id: changelog if: ${{ steps.extract-version.outputs.version }} run: | python3 ./scripts/generate_changelog.py --version "${{ steps.extract-version.outputs.version }}" --tag "${{ github.head_ref }}" # CHANGELOG_RELEASE.md์ ๋ณ๊ฒฝ๋ด์ฉ์ด ์กด์ฌํ๋์ง, ์ฆ ์๋ก์ด ๋ฒ์ ์ release๋ฅผ ์์ฑํ ํ์๊ฐ ์๋์ง ํ์ธ # ํด๋น workflow์์ ์ค์ ํ github action(pull request)๊ฐ close๋๊ณ , # extract-version step์์ ์ฌ๋ฐ๋ฅธ ํํ์ ๋ฒ์ ๋ช ์ ์ป์ด๋ธ ๊ฒฝ์ฐ์๋ง ์ํํ๋๋ก ์กฐ๊ฑด์ ์ค์ - name: Get Changed Files id: changed-files if: ${{ github.event.action != 'closed' && steps.extract-version.outputs.version }} uses: tj-actions/changed-files@v31 # ์ด์ step์ธ changed-files์์ ๋ณ๊ฒฝ๋ ํ์ผ์ด ์๋ ๊ฒฝ์ฐ, ํ์ผ์ staged ์ํ๋ก ์ ํํ๋ค ์๋์ผ๋ก ์ปค๋ฐ # ์ด ๋, ์ปค๋ฐํ ํ์ผ(CHANGELOG.md)๊ณผ ์ปค๋ฐ ๋ฉ์ธ์ง๋ with ๊ตฌ๋ฌธ์ ์ฌ์ฉํ์ฌ ์ง์ - name: Auto Commit Updated Changelog id: auto-commit-push if: ${{ github.event.action != 'closed' && steps.changed-files.outputs.any_changed == true && steps.extract-version.outputs.version }} uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: "update: CHANGELOG.md" file_pattern: "CHANGELOG.md" # ์กฐ๊ฑด์ ๋ง์กฑํ๋ ๊ฒฝ์ฐ, ์๋ก์ด ๋ฒ์ ์ release์ tag๋ฅผ ์์ฑ - name: Create Release with Tag if: ${{ github.event.action == 'closed' && github.event.pull_request.merged == true && steps.extract-version.outputs.version == true && contains(github.event.pull_request.title, 'release') }} uses: ncipollo/release-action@v1 with: tag: ${{ steps.extract-version.outputs.version }} name: ${{ steps.extract-version.outputs.version }} bodyFile: "./CHANGELOG_RELEASE.md" skipIfReleaseExists: true
๐ ๋ง๋ฌด๋ฆฌ
schedule deploy workflow ์ํ๊ฒฐ๊ณผ ์ด๋ ๊ฒ
Github Action
์ ์ฌ์ฉํ์ฌ ๋น๋ ๋ฐ ๋ฐฐํฌ๋ฟ๋ง ์๋๋ผ ๋ฒ์ ๊ด๋ฆฌ๊น์ง ์๋ํํ ์ ์์๋ค.YAML
๋ฌธ๋ฒ์ ์ฌ์ฉํ์ฌ workflow๋ฅผ ์์ฑํ ์ ์๊ณ github ๊ณต์ ๋ํ๋จผํธ๊ฐ ๋งค์ฐ ์ ์ ๋ฆฌ๋์ด ์์ด์ ํ์ฉ์ด ๋งค์ฐ ํธ๋ฆฌํ๋ค.
๋ค์์๋ ์๋ํํ๊ณ ์ถ์ action์ ์ง์ github marketplace์ ๋ฐฐํฌํด๋ณด๋ ๊ฒ์ด ๋ชฉํ๋ค!ใ ใ 'Develop > DevOps' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Vagrant๋ก VM ๊ฐ๋ฐํ๊ฒฝ ๊ตฌ์ฑ (0) 2022.09.18 ๋ณด์์ ์ํ AWS network ๊ตฌ์ฑํ๊ธฐ (0) 2021.10.23