Add CI/CD workflow examples and serving manifest
CI - Lint & Test / lint-and-test (push) Has been cancelled Details

- ci.yaml: lint (ruff) + test (pytest) on push/PR
- train.yaml: dvc pull → train → dvc push → docker build → deploy
- dvc-data-update.yaml: data validation on .dvc file changes
- manifests/deployment.yaml: example serving Deployment + Service

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Cloud User 2026-02-25 15:32:09 +09:00
parent 4f7c3da543
commit b606ed18ae
5 changed files with 242 additions and 7 deletions

30
.gitea/workflows/ci.yaml Normal file
View File

@ -0,0 +1,30 @@
name: CI - Lint & Test
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
lint-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install ruff pytest
- name: Lint
run: ruff check .
- name: Test
run: pytest tests/ -v

View File

@ -0,0 +1,40 @@
name: DVC Data Validation
on:
push:
paths:
- "**.dvc"
- "dvc.yaml"
- "dvc.lock"
jobs:
validate-data:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install dependencies
run: |
pip install dvc pandas
- name: Pull updated data
run: dvc pull
- name: Validate data
run: |
python -c "
import pandas as pd
import sys
# TODO: 실제 데이터 경로와 검증 로직으로 수정
# df = pd.read_csv('data/dataset.csv')
# assert len(df) > 0, 'Dataset is empty'
# assert df.isnull().sum().sum() == 0, 'Dataset has null values'
print('Data validation passed')
"

View File

@ -0,0 +1,75 @@
name: Train & Deploy
on:
push:
branches: [main]
paths:
- "src/**"
- "configs/**"
- "dvc.yaml"
jobs:
train:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.10"
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install dvc
- name: Pull data from DVC
run: dvc pull
- name: Train model
run: python src/train.py
- name: Track model with DVC
run: |
dvc add models/
dvc push
- name: Commit DVC metadata
run: |
git config user.name "gitea-runner"
git config user.email "runner@mlops"
git add models/*.dvc models/.gitignore
git diff --cached --quiet || git commit -m "Update model - $(date +%Y%m%d-%H%M%S)"
git push
build-and-deploy:
needs: train
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: main
- name: Build Docker image
run: |
IMAGE_TAG="${{ github.sha }}"
docker build -t $REGISTRY_URL/mlops-serving:${IMAGE_TAG} .
docker push $REGISTRY_URL/mlops-serving:${IMAGE_TAG}
env:
REGISTRY_URL: ${{ vars.REGISTRY_URL }}
- name: Update manifest
run: |
IMAGE_TAG="${{ github.sha }}"
sed -i "s|image:.*mlops-serving.*|image: $REGISTRY_URL/mlops-serving:${IMAGE_TAG}|" manifests/deployment.yaml
git config user.name "gitea-runner"
git config user.email "runner@mlops"
git add manifests/
git commit -m "Deploy model ${IMAGE_TAG:0:7}"
git push
env:
REGISTRY_URL: ${{ vars.REGISTRY_URL }}
# ↑ manifests/ 변경 → ArgoCD가 자동 감지 → soo ns에 배포

View File

@ -163,20 +163,58 @@ dvc version
--- ---
## 5. CI/CD 워크플로우
`.gitea/workflows/` 에 정의. Gitea Runner가 실행합니다.
### ci.yaml — 코드 push 시 린트 + 테스트
```
trigger: push to main/develop, PR to main
동작: ruff lint → pytest
```
### train.yaml — 모델 학습 + 배포
```
trigger: src/, configs/, dvc.yaml 변경 시
동작:
1. dvc pull (NAS에서 데이터 가져오기)
2. python src/train.py (학습)
3. dvc add + dvc push (모델 → NAS)
4. Docker build + push (서빙 이미지)
5. manifests/ 이미지 태그 업데이트 → git push
6. → ArgoCD 자동 감지 → soo ns에 배포
```
### dvc-data-update.yaml — 데이터 변경 시 검증
```
trigger: .dvc 파일, dvc.yaml, dvc.lock 변경 시
동작: dvc pull → 데이터 검증 스크립트 실행
```
---
## 파일 구조 ## 파일 구조
``` ```
mlops_architecture/ mlops_architecture/
├── .env # 접속 정보, 시크릿 (git 제외) ├── .env # 접속 정보, 시크릿 (git 제외)
├── .gitignore ├── .gitignore
├── config.yaml # 인프라 구성 정보 ├── .dvc/ # DVC 설정 (remote 등)
├── README.md # 설치 가이드 (이 파일) ├── .gitea/workflows/ # CI/CD 파이프라인
├── .dvc/ # DVC 설정 (remote 등) │ ├── ci.yaml # 린트 + 테스트
│ ├── train.yaml # 학습 → 빌드 → 배포
│ └── dvc-data-update.yaml # 데이터 검증
├── argocd/ ├── argocd/
│ └── application.yaml # ArgoCD Application 정의 │ └── application.yaml # ArgoCD Application 정의
├── config.yaml # 인프라 구성 정보
├── gitea-runner/ ├── gitea-runner/
│ └── deployment.yaml # Gitea Runner K8s 배포 (Secret+ConfigMap+Deployment) │ └── deployment.yaml # Gitea Runner K8s 배포
└── manifests/ # K8s 배포 manifest (ArgoCD가 감시) ├── manifests/ # K8s 배포 manifest (ArgoCD 감시)
│ └── deployment.yaml # 서빙 Deployment + Service
└── README.md # 설치 가이드 (이 파일)
``` ```
## 설정 파일 사용법 ## 설정 파일 사용법

52
manifests/deployment.yaml Normal file
View File

@ -0,0 +1,52 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: mlops-serving
namespace: soo
labels:
app: mlops-serving
spec:
replicas: 1
selector:
matchLabels:
app: mlops-serving
template:
metadata:
labels:
app: mlops-serving
spec:
containers:
- name: serving
image: ${REGISTRY_URL}/mlops-serving:latest # CI에서 자동 업데이트
ports:
- containerPort: 8080
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "2"
memory: 2Gi
# env:
# - name: MODEL_PATH
# value: /models/model.pt
# volumeMounts:
# - name: model-storage
# mountPath: /models
# volumes:
# - name: model-storage
# persistentVolumeClaim:
# claimName: mlops-model-pvc
---
apiVersion: v1
kind: Service
metadata:
name: mlops-serving
namespace: soo
spec:
selector:
app: mlops-serving
ports:
- port: 80
targetPort: 8080
type: ClusterIP