feat: 开发测试接口
This commit is contained in:
7
.dockerignore
Normal file
7
.dockerignore
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
__pycache__
|
||||||
|
*.pyc
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.omc
|
||||||
|
README.md
|
||||||
|
LICENSE
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -187,3 +187,6 @@ cython_debug/
|
|||||||
# PyPI configuration file
|
# PyPI configuration file
|
||||||
.pypirc
|
.pypirc
|
||||||
|
|
||||||
|
# oh-my-claudecode
|
||||||
|
.omc/
|
||||||
|
|
||||||
|
|||||||
7
Dockerfile
Normal file
7
Dockerfile
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
FROM python:3.10-slim
|
||||||
|
WORKDIR /app
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
COPY app/ ./app/
|
||||||
|
EXPOSE 8000
|
||||||
|
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||||
0
app/__init__.py
Normal file
0
app/__init__.py
Normal file
15
app/main.py
Normal file
15
app/main.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
from fastapi import FastAPI
|
||||||
|
|
||||||
|
app = FastAPI(title="CI/CD Demo", version="1.0.0")
|
||||||
|
|
||||||
|
@app.get("/")
|
||||||
|
def root():
|
||||||
|
return {"status": "ok", "version": "1.0.0"}
|
||||||
|
|
||||||
|
@app.get("/health")
|
||||||
|
def health():
|
||||||
|
return {"healthy": True}
|
||||||
|
|
||||||
|
@app.get("/items/{item_id}")
|
||||||
|
def get_item(item_id: int):
|
||||||
|
return {"item_id": item_id, "name": f"Item {item_id}"}
|
||||||
23
app/test_main.py
Normal file
23
app/test_main.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
from fastapi.testclient import TestClient
|
||||||
|
from app.main import app
|
||||||
|
|
||||||
|
client = TestClient(app)
|
||||||
|
|
||||||
|
def test_root():
|
||||||
|
response = client.get("/")
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json() == {"status": "ok", "version": "1.0.0"}
|
||||||
|
|
||||||
|
def test_health():
|
||||||
|
response = client.get("/health")
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json() == {"healthy": True}
|
||||||
|
|
||||||
|
def test_get_item():
|
||||||
|
response = client.get("/items/1")
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json() == {"item_id": 1, "name": "Item 1"}
|
||||||
|
|
||||||
|
def test_get_item_invalid():
|
||||||
|
response = client.get("/items/abc")
|
||||||
|
assert response.status_code == 422
|
||||||
20
argocd/application.yaml
Normal file
20
argocd/application.yaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: fastapi-demo
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
source:
|
||||||
|
repoURL: https://git.plfai.cn/root/fastapi-demo.git
|
||||||
|
targetRevision: main
|
||||||
|
path: k8s
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: fastapi-demo
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
53
k8s/deployment.yaml
Normal file
53
k8s/deployment.yaml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: fastapi-demo
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: fastapi-app
|
||||||
|
namespace: fastapi-demo
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: fastapi-app
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: fastapi-app
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: app
|
||||||
|
image: registry.plfai.cn/fastapi-demo:latest
|
||||||
|
ports:
|
||||||
|
- containerPort: 8000
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: 8000
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 256Mi
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: fastapi-app
|
||||||
|
namespace: fastapi-demo
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app: fastapi-app
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 8000
|
||||||
5
k8s/kustomization.yaml
Normal file
5
k8s/kustomization.yaml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- deployment.yaml
|
||||||
4
requirements.txt
Normal file
4
requirements.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
fastapi==0.115.0
|
||||||
|
uvicorn==0.30.0
|
||||||
|
httpx==0.27.0
|
||||||
|
pytest==8.3.0
|
||||||
90
tekton/pipeline.yaml
Normal file
90
tekton/pipeline.yaml
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
apiVersion: tekton.dev/v1
|
||||||
|
kind: Pipeline
|
||||||
|
metadata:
|
||||||
|
name: fastapi-ci
|
||||||
|
namespace: tekton-ci
|
||||||
|
spec:
|
||||||
|
params:
|
||||||
|
- name: git-url
|
||||||
|
type: string
|
||||||
|
- name: git-revision
|
||||||
|
type: string
|
||||||
|
- name: image-tag
|
||||||
|
type: string
|
||||||
|
workspaces:
|
||||||
|
- name: source
|
||||||
|
- name: dockerconfig
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
# 1. 拉取代码
|
||||||
|
- name: git-clone
|
||||||
|
taskRef:
|
||||||
|
name: git-clone
|
||||||
|
params:
|
||||||
|
- name: url
|
||||||
|
value: $(params.git-url)
|
||||||
|
- name: revision
|
||||||
|
value: $(params.git-revision)
|
||||||
|
workspaces:
|
||||||
|
- name: output
|
||||||
|
workspace: source
|
||||||
|
|
||||||
|
# 2. 单元测试
|
||||||
|
- name: pytest
|
||||||
|
runAfter: [git-clone]
|
||||||
|
taskSpec:
|
||||||
|
steps:
|
||||||
|
- name: test
|
||||||
|
image: python:3.10-slim
|
||||||
|
script: |
|
||||||
|
cd $(workspaces.source.path)
|
||||||
|
pip install -r requirements.txt
|
||||||
|
pytest app/test_main.py -v
|
||||||
|
workspaces:
|
||||||
|
- name: source
|
||||||
|
workspace: source
|
||||||
|
|
||||||
|
# 3. 构建并推送镜像 (Kaniko)
|
||||||
|
- name: build-and-push
|
||||||
|
runAfter: [pytest]
|
||||||
|
taskRef:
|
||||||
|
name: kaniko
|
||||||
|
params:
|
||||||
|
- name: IMAGE
|
||||||
|
value: "registry.plfai.cn/fastapi-demo:$(params.image-tag)"
|
||||||
|
workspaces:
|
||||||
|
- name: source
|
||||||
|
workspace: source
|
||||||
|
- name: dockerconfig
|
||||||
|
workspace: dockerconfig
|
||||||
|
|
||||||
|
# 4. 镜像漏洞扫描
|
||||||
|
- name: trivy-scan
|
||||||
|
runAfter: [build-and-push]
|
||||||
|
taskSpec:
|
||||||
|
steps:
|
||||||
|
- name: scan
|
||||||
|
image: aquasec/trivy:latest
|
||||||
|
args:
|
||||||
|
- image
|
||||||
|
- --severity=HIGH,CRITICAL
|
||||||
|
- --exit-code=1
|
||||||
|
- "registry.plfai.cn/fastapi-demo:$(params.image-tag)"
|
||||||
|
|
||||||
|
# 5. 更新部署清单 (GitOps)
|
||||||
|
- name: gitops-update
|
||||||
|
runAfter: [trivy-scan]
|
||||||
|
taskSpec:
|
||||||
|
steps:
|
||||||
|
- name: update-image
|
||||||
|
image: alpine/git
|
||||||
|
script: |
|
||||||
|
git clone $(params.git-url) /workspace/repo
|
||||||
|
cd /workspace/repo
|
||||||
|
sed -i "s|image: registry.plfai.cn/fastapi-demo:.*|image: registry.plfai.cn/fastapi-demo:$(params.image-tag)|" \
|
||||||
|
k8s/deployment.yaml
|
||||||
|
git config user.email "tekton@plfai.cn"
|
||||||
|
git config user.name "Tekton CI"
|
||||||
|
git add k8s/deployment.yaml
|
||||||
|
git commit -m "ci: update image to $(params.image-tag) [skip ci]"
|
||||||
|
git push origin main
|
||||||
11
tekton/pvc.yaml
Normal file
11
tekton/pvc.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: fastapi-ci-cache
|
||||||
|
namespace: tekton-ci
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 2Gi
|
||||||
65
tekton/trigger.yaml
Normal file
65
tekton/trigger.yaml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
apiVersion: triggers.tekton.dev/v1beta1
|
||||||
|
kind: TriggerTemplate
|
||||||
|
metadata:
|
||||||
|
name: fastapi-trigger-template
|
||||||
|
namespace: tekton-ci
|
||||||
|
spec:
|
||||||
|
params:
|
||||||
|
- name: git-url
|
||||||
|
- name: git-revision
|
||||||
|
resourcetemplates:
|
||||||
|
- apiVersion: tekton.dev/v1
|
||||||
|
kind: PipelineRun
|
||||||
|
metadata:
|
||||||
|
generateName: fastapi-ci-run-
|
||||||
|
namespace: tekton-ci
|
||||||
|
spec:
|
||||||
|
pipelineRef:
|
||||||
|
name: fastapi-ci
|
||||||
|
params:
|
||||||
|
- name: git-url
|
||||||
|
value: $(tt.params.git-url)
|
||||||
|
- name: git-revision
|
||||||
|
value: $(tt.params.git-revision)
|
||||||
|
- name: image-tag
|
||||||
|
value: $(tt.params.git-revision)
|
||||||
|
workspaces:
|
||||||
|
- name: source
|
||||||
|
volumeClaimTemplate:
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
- name: dockerconfig
|
||||||
|
secret:
|
||||||
|
secretName: registry-credentials
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: triggers.tekton.dev/v1beta1
|
||||||
|
kind: TriggerBinding
|
||||||
|
metadata:
|
||||||
|
name: fastapi-trigger-binding
|
||||||
|
namespace: tekton-ci
|
||||||
|
spec:
|
||||||
|
params:
|
||||||
|
- name: git-url
|
||||||
|
value: $(body.repository.clone_url)
|
||||||
|
- name: git-revision
|
||||||
|
value: $(body.after)
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: triggers.tekton.dev/v1beta1
|
||||||
|
kind: EventListener
|
||||||
|
metadata:
|
||||||
|
name: fastapi-listener
|
||||||
|
namespace: tekton-ci
|
||||||
|
spec:
|
||||||
|
serviceAccountName: tekton-triggers-sa
|
||||||
|
triggers:
|
||||||
|
- name: fastapi-push
|
||||||
|
bindings:
|
||||||
|
- ref: fastapi-trigger-binding
|
||||||
|
template:
|
||||||
|
ref: fastapi-trigger-template
|
||||||
Reference in New Issue
Block a user