Cloud Dev 1st CI AI - 100-hours-a-week/KTB4-1st-wiki GitHub Wiki
2๋จ๊ณ. CI(์ง์์ ํตํฉ) ํ์ดํ๋ผ์ธ ์ค๊ณ์์ ์ ํ CI Trigger๋ฅผ KTB4_1st_AI ๋ ํฌ์ ์ค์ ๋ก ๊ตฌํํ ๋ด์ฉ์ด๋ค.
- ๋์ ๋ ํฌ:
KTB4_1st_AI(FastAPI) - ์ํฌํ๋ก์ฐ ํ์ผ:
ai-pr-check.yml,ai-docker-publish.yml
| ํ์ผ | ํธ๋ฆฌ๊ฑฐ | ์คํ ํญ๋ชฉ |
|---|---|---|
ai-pr-check.yml |
feat โ dev, hotfix โ main PR |
Ruff ์ ์ ๋ถ์, ๋น๋ ๊ฒ์ฆ(์ฑ ์ํฌํธ), Docker Image ๋น๋(push ์์) |
ai-docker-publish.yml |
dev push(merge) |
Docker Image ๋น๋ + GHCR push (latest, dev-<short SHA>) |
ai-docker-publish.yml |
release ํ๊ทธ(v*.*.*) push |
Docker Image ๋น๋ + GHCR push (Semantic Version) |
name: AI CI - PR Check
# feat -> dev PR, hotfix -> main PR: ์ ์ ๋ถ์, (๋จ์ ํ
์คํธ - ํ
์คํธ ์ฝ๋ ์์ด ํ์ฌ ์ ์ธ), ๋น๋ ๊ฒ์ฆ, Docker Image ๋น๋(push ์์)
on:
pull_request:
branches:
- dev
- main
# ๋์ผ PR์ ์ฐ์ Push ๋ฐ์ ์ ์งํ ์ค์ด๋ ์ด์ ์คํ ์๋ ์ทจ์
concurrency:
group: ai-pr-check-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
verify:
name: ์ ์ ๋ถ์ ๋ฐ ๋น๋ ๊ฒ์ฆ
runs-on: ubuntu-latest
steps:
- name: Checkout # ์์ค ์ฝ๋ ๋ค์ด๋ก๋
uses: actions/checkout@v7
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.13.13"
cache: pip
- name: ์์กด์ฑ ์ค์น
run: pip install --no-cache-dir -r requirements.txt ruff
- name: ์ ์ ๋ถ์ (Ruff Lint)
run: ruff check .
- name: ์ ์ ๋ถ์ (Ruff Format)
run: ruff format --check .
# ๋จ์ ํ
์คํธ - ํ์ฌ ํ
์คํธ ์ฝ๋๊ฐ ์์ด ์๋ต
- name: ๋น๋ ๊ฒ์ฆ (์ฑ ์ํฌํธ)
run: python -c "from main import app"
docker-build:
name: Docker Image ๋น๋ (๊ฒ์ฆ์ฉ, push ์์)
needs: verify
# ARM64 ์ ์ฉ GitHub Hosted ๋ฌ๋ ์ฌ์ฉ
runs-on: ubuntu-24.04-arm
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Docker Image ๋น๋ (push ์์)
uses: docker/build-push-action@v7
with:
context: . # ๋น๋ ์ปจํ
์คํธ ๊ฒฝ๋ก
push: false
tags: ktb4-1st-ai:pr-${{ github.event.pull_request.number }}
์ธ๋ถ ๊ฒฐ์ ์ฌํญ
-
์ ์ ๋ถ์: Ruff
-
ํ์
-๊ฐ์ด๋-v1์์ FastAPI ํํธ์ CI ํ์ง ๊ฒ์ดํธ ๋๊ตฌ๋ก ์ง์ ๋จ. ๋ณ๋ ์ค์ ํ์ผ(
pyproject.toml๋ฑ)์ ์ถ๊ฐํ์ง ์๊ณ Ruff ๊ธฐ๋ณธ ๋ฃฐ์ ์ ๊ทธ๋๋ก ์ฌ์ฉํ๋ค. - ์ค๊ณ ๋ฌธ์(2๋จ๊ณ)์์ ์ธ๊ธํ "import ์ ๋ฆฌ"๋ ๊ธฐ๋ณธ ๋ฃฐ์ ์๋ ํฌํจ๋์ง ์์ง๋ง, ํ์ด ์ ์์ผ๋ก ํฉ์ํ๊ธฐ ์ ๊น์ง๋ ์์๋ก ํ๋ก์ ํธ ์ค์ ํ์ผ์ ์ถ๊ฐํ์ง ์๊ธฐ๋ก ํ๋ค.
-
ํ์
-๊ฐ์ด๋-v1์์ FastAPI ํํธ์ CI ํ์ง ๊ฒ์ดํธ ๋๊ตฌ๋ก ์ง์ ๋จ. ๋ณ๋ ์ค์ ํ์ผ(
- Python ๋ฒ์ ๊ณ ์ (3.13.13)
-
๋น๋ ๋จ๊ณ๋ฅผ ์ฑ ์ํฌํธ๋ก ๋์ฒด
- Python์ ์ปดํ์ผ ๋จ๊ณ๊ฐ ์๊ธฐ ๋๋ฌธ์
python -c "from main import app"์ผ๋ก FastAPI ์ฑ์ด ๋ฌธ๋ฒ/์ํฌํธ ์ค๋ฅ ์์ด ๋ก๋๋๋์ง ํ์ธํด ๊ฐ์ ๋ชฉ์ (๋น๋ ์คํจ ์กฐ๊ธฐ ๋ฐ๊ฒฌ)์ ๋ฌ์ฑํ๋ค.
- Python์ ์ปดํ์ผ ๋จ๊ณ๊ฐ ์๊ธฐ ๋๋ฌธ์
-
๋จ์ ํ
์คํธ ์ ์ธ
- ํ์ฌ ํ ์คํธ ์ฝ๋๊ฐ ์์ด ์๋ต
-
PR ๋จ๊ณ Docker ๋น๋๋ push ์ ํจ
- PR์ merge๊ฐ ๊ฑฐ์ ๋์ด ์ฝ๋๊ฐ ๋ฐ๋ ์ ์์ผ๋ฏ๋ก, ๋น๋ ์ฑ๊ณต ์ฌ๋ถ๋ง ํ์ธํ๊ณ ๋ ์ง์คํธ๋ฆฌ์๋ ์ฌ๋ฆฌ์ง ์๋๋ค.
name: AI Docker Image Publish
# dev push(merge): Docker Image ๋น๋ ๋ฐ GHCR(100-hours-a-week ์กฐ์ง ์์ ํจํค์ง) Push
# - latest(๋ก์ปฌ ํ
์คํธ์ฉ ํฌ์ธํฐ), dev-<short SHA>(๋ถ๋ณ ์ถ์ ์ฉ) ํ๊ทธ
# release tag(v*.*.*) push: ๋ฐฐํฌ์ฉ Docker Image ๋น๋ ๋ฐ GHCR Push
# - main์ผ๋ก dev/hotfix๊ฐ merge๋ ๋ค, ํด๋น ์ปค๋ฐ์ Semantic Version ํ๊ทธ(์: v1.0.1)๋ฅผ pushํ๋ฉด ํธ๋ฆฌ๊ฑฐ๋จ
# - Semantic Version ํ๊ทธ๋ง ์ด๋ฏธ์ง ํ๊ทธ๋ก ์ฌ์ฉ
on:
push:
branches:
- dev
tags:
- "v*.*.*"
# ๋์ผ ๋ธ๋์น/ํ๊ทธ์ ์ฐ์ Push ๋ฐ์ ์ ์งํ ์ค์ด๋ ์ด์ ์คํ ์๋ ์ทจ์
concurrency:
group: ai-docker-publish-${{ github.ref }} # dev์ pushํ๋ฉด refs/heads/dev, ํ๊ทธ pushํ๋ฉด refs/tags/v1.0.1
cancel-in-progress: true
env:
REGISTRY: ghcr.io
# github.repository๋ "100-hours-a-week/KTB4_1st_AI" ํํ(docker/metadata-action์ด images ๊ฐ์ ์๋์ผ๋ก ์๋ฌธ์ ๋ณํ)
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
name: Docker Image ๋น๋ ๋ฐ GHCR Push
# ARM64 ์ ์ฉ GitHub Hosted ๋ฌ๋ ์ฌ์ฉ
runs-on: ubuntu-24.04-arm
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to GHCR
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN }}
- name: Docker ๋ฉํ๋ฐ์ดํฐ(ํ๊ทธ/๋ผ๋ฒจ) ์์ฑ
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# dev : latest(๋ก์ปฌ ํ
์คํธ์ฉ ํฌ์ธํฐ), dev-<short SHA>(๋ถ๋ณ ์ถ์ ์ฉ)
# release tag : push๋ ํ๊ทธ(v1.0.1)์์ v๋ฅผ ๋ Semantic Version์ ๊ทธ๋๋ก ํ๊ทธ๋ก ์ฌ์ฉ
tags: |
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/dev' }}
type=sha,format=short,prefix=dev-,enable=${{ github.ref == 'refs/heads/dev' }}
type=semver,pattern={{version}}
labels: |
org.opencontainers.image.authors=${{ github.actor }}
- name: Docker Image ๋น๋ ๋ฐ Push
id: build-push
run: |
set -e
# ํ๊ทธ ๋ณํ
TAG_ARGS=()
while IFS= read -r tag; do
[ -z "$tag" ] && continue
TAG_ARGS+=(--tag "$tag")
done <<< "${{ steps.meta.outputs.tags }}"
# ๋ผ๋ฒจ ๋ณํ
LABEL_ARGS=()
while IFS= read -r label; do
[ -z "$label" ] && continue
LABEL_ARGS+=(--label "$label")
done <<< "${{ steps.meta.outputs.labels }}"
# ์ด๋ฏธ์ง ๋น๋ + GHCR push
docker buildx build \
--push \
"${TAG_ARGS[@]}" \
"${LABEL_ARGS[@]}" \
.
์ธ๋ถ ๊ฒฐ์ ์ฌํญ
-
dev ํ๊ทธ:
latest(๋ก์ปฌ ํ ์คํธ์ฉ ํฌ์ธํฐ),dev-<short SHA>(๋ถ๋ณ ์ถ์ ์ฉ). ์ค๊ณ ๋ฌธ์(2๋จ๊ณ) ๊ทธ๋๋ก ์ ์ง. -
main ๋ฐฐํฌ ๋ฒ์ = Git tag ๊ธฐ๋ฐ Semantic Version (์ค๊ณ ๋ฌธ์ ๋๋น ๋ณ๊ฒฝ๋ ๋ถ๋ถ, ์๋ "์ค๊ณ ๋ฌธ์์ ๋ฌ๋ผ์ง ์ " ์ฐธ๊ณ )
-
docker/metadata-action์type=semver,pattern={{version}}์ด push๋ ํ๊ทธ(์:v1.0.1)์์v์ ๋์ด๋ฅผ ๋1.0.1์ ์๋์ผ๋ก ์ด๋ฏธ์ง ํ๊ทธ๋ก ์ถ์ถํ๋ค. -
v์ ๋์ด๋ฅผ ๋ผ๋ ์ด์ : Git/GitHub ์ชฝ์ ๋ฒ์ ํ๊ทธ์v๋ฅผ ๋ถ์ด๋ ๊ฒ ๊ด๋ก(v1.0.1)์ธ ๋ฐ๋ฉด, Docker ์ด๋ฏธ์ง ํ๊ทธ๋ ์ ๋์ด ์์ด ์ซ์๋ง ์ฐ๋ ๊ฒ ๊ด๋ก(์:python:3.13.13)๋ผ, ๋ ์ํ๊ณ์ ์ฐจ์ด๋ฅผmetadata-action์ด ์๋์ผ๋ก ๋ง์ถฐ์ค๋ค. - main์ผ๋ก ๋ณํฉ๋ง ํด์๋ ์ด๋ฏธ์ง๊ฐ ๋ง๋ค์ด์ง์ง ์๋๋ค. ๋ฐ๋์ ํ๊ทธ๋ฅผ pushํด์ผ ํธ๋ฆฌ๊ฑฐ๋๋ค.
-
-
๋ฆด๋ฆฌ์ฆ ์ ์ฐจ (dev/hotfix โ main PR merge ์ดํ)
- GitHub ์ ์ฅ์ โ Releases โ Draft a new release
- Target:
main, ์ ํ๊ทธ๋ฅผv1.0.1ํ์์ผ๋ก ์ ๋ ฅ ํ ์์ฑ - Publish release ํด๋ฆญ โ ํ๊ทธ๊ฐ push๋์ด ์ํฌํ๋ก์ฐ๊ฐ ์๋ ์คํ๋จ
- CLI๋ก
git tag/git pushํด๋ ๋์ผํ๊ฒ ๋์ํ์ง๋ง, GitHub Release ์ชฝ์ด CLI ์์ด ๋ธ๋ผ์ฐ์ ์์ ๋๋๊ณ ๋ฆด๋ฆฌ์ฆ ๋ ธํธ๋ ํจ๊ป ๋จ์ ์ด ๋ฐฉ๋ฒ์ ๊ถ์ฅํ๋ค. - ์ด๋ค ์๋ฆฌ(MAJOR/MINOR/PATCH)๋ฅผ ์ฌ๋ฆด์ง๋ ์ค๊ณ ๋ฌธ์์ ๊ธฐ์กด ๊ท์น์ ๊ทธ๋๋ก ๋ฐ๋ฅธ๋ค: hotfix๋ ํญ์ PATCH, ์ ๊ธฐ ๋ฐฐํฌ๋ ๊ทธ ์ฃผ ๋ณ๊ฒฝ ์ค ์ํฅ๋๊ฐ ๊ฐ์ฅ ํฐ ๋ฑ๊ธ.
-
๋ผ๋ฒจ ์์ฑ์ ์ ๋ณด:
github.event.head_commit.author.name๋์github.actor๋ฅผ ์ฌ์ฉํ๋ค. Annotated tag๋ฅผ pushํ๋ ์ด๋ฒคํธ์์๋head_commit์ด ๋น์ด ์์ ์ ์์ด(GitHub ์นํ ํน์ฑ), ํญ์ ๊ฐ์ด ์ฑ์์ง๋github.actor(ํ๊ทธ๋ฅผ pushํ ์ฌ๋)๋ก ๋์ฒดํ๋ค.
| ํญ๋ชฉ | ์ค๊ณ ๋ฌธ์(2๋จ๊ณ) | ์ค์ ๊ตฌํ | ์ฌ์ |
|---|---|---|---|
| ๋จ์ ํ ์คํธ (PR ๋จ๊ณ) | ํฌํจ | ์ ์ธ | ํ์ฌ ํ ์คํธ ์ฝ๋ ์์ |
dev โ main PR ์ ์ฒด ํ
์คํธ ์ํฌํ๋ก์ฐ |
ํฌํจ | ๋ฏธ๊ตฌํ | ํ์ฌ ํ ์คํธ ์ฝ๋ ์์ |
| main ๋ฐฐํฌ ๋ฒ์ ๊ด๋ฆฌ | ๋ช ์ ์ ๋จ(Semantic Version ํ๊ทธ ์ฌ์ฉ๋ง ๊ธฐ์ ) | Git tag(v*.*.*) push ๊ธฐ๋ฐ, GitHub Release๋ก ์์ฑ |
๋ฒ์ ์ ์ฝ๋ ํ์ผ(package.json๋ฅ)๋ก ๊ด๋ฆฌํ๋ฉด ๋งค ๋ฐฐํฌ๋ง๋ค ๊ทธ ํ์ผ์ ๊ณ ์น๋ PR์ด ๋ณ๋๋ก ํ์ํจ. Git tag๋ฅผ ๋จ์ผ ์ง์ค ๊ณต๊ธ์์ผ๋ก ์ผ์ผ๋ฉด ๊ทธ ์ ์ฐจ๊ฐ ์์ด์ง๊ณ , "ํ๊ทธ push = ๋ฐฐํฌ ํธ๋ฆฌ๊ฑฐ"๋ก ์์ฐ์ค๋ฝ๊ฒ ๋ถ๋ฆฌ๋๋ค. |
| main push(merge) ํธ๋ฆฌ๊ฑฐ |
main push(merge) ์ ์ด๋ฏธ์ง ๋น๋ |
release ํ๊ทธ(v*.*.*) push ์ ์ด๋ฏธ์ง ๋น๋ |
์ ๋ฒ์ ๊ด๋ฆฌ ๋ฐฉ์ ๋ณ๊ฒฝ์ ๋ฐ๋ฅธ ํธ๋ฆฌ๊ฑฐ ๋ณ๊ฒฝ. main์ ๋ณํฉํ๋ ์์ ๊ณผ, ์ค์ ๋ก ๋ฐฐํฌ์ฉ ์ด๋ฏธ์ง๋ฅผ ๋ง๋๋ ์์ (ํ๊ทธ๋ฅผ ๋ถ์ด๋ ์์ )์ ์๋์ ์ผ๋ก ๋ถ๋ฆฌํ๋ค. |
- Cloud-Design-2nd - 2๋จ๊ณ CI ํ์ดํ๋ผ์ธ ์ค๊ณ (Trigger, CI Stages, ์คํจ ์ฒ๋ฆฌ ์ ์ฑ ๋ฑ ๊ทผ๊ฑฐ)
- Cloud-Dev-v1-Dockerfile - AI Dockerfile ๊ตฌ์ฑ