From fb3a674eb8a779aac7b6d69b9e4378ffaf823049 Mon Sep 17 00:00:00 2001 From: kappa Date: Sat, 7 Feb 2026 22:19:32 +0900 Subject: [PATCH] feat: Add CI/CD pipeline with Docker build and K8s deployment Add Dockerfile (multi-stage, python:3.11-slim + uv), K8s manifests (Deployment + Service), and extend CI workflow with build-push-deploy stages targeting Gitea registry and K3s. Co-Authored-By: Claude Opus 4.6 --- .gitea/workflows/ci.yml | 56 +++++++++++++++++++++++++++++++++++------ Dockerfile | 23 +++++++++++++++++ k8s/deployment.yaml | 55 ++++++++++++++++++++++++++++++++++++++++ k8s/service.yaml | 16 ++++++++++++ 4 files changed, 143 insertions(+), 7 deletions(-) create mode 100644 Dockerfile create mode 100644 k8s/deployment.yaml create mode 100644 k8s/service.yaml diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index d4dd8ae..5c53ca3 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,4 +1,4 @@ -name: Python CI +name: CI/CD on: push: @@ -11,20 +11,62 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - + - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.11' - + - name: Install uv run: pip install uv - + - name: Install dependencies - run: uv pip install --system -e ".[dev]" || uv pip install --system -e . - + run: uv pip install --system -e "haproxy_mcp[dev]" || uv pip install --system -e haproxy_mcp + - name: Lint with ruff run: ruff check . || true - + - name: Type check run: mypy . --ignore-missing-imports || true + + build-and-deploy: + needs: test + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Gitea Registry + run: echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login gitea.anvil.it.com -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin + + - name: Build and push Docker image + run: | + IMAGE=gitea.anvil.it.com/kaffa/haproxy-mcp + TAG=${GITHUB_SHA::8} + docker buildx build \ + --platform linux/amd64 \ + --tag ${IMAGE}:${TAG} \ + --tag ${IMAGE}:latest \ + --push \ + . + + - name: Deploy to K8s + env: + KUBECONFIG_DATA: ${{ secrets.KUBECONFIG }} + run: | + mkdir -p ~/.kube + echo "${KUBECONFIG_DATA}" | base64 -d > ~/.kube/config + chmod 600 ~/.kube/config + + IMAGE=gitea.anvil.it.com/kaffa/haproxy-mcp + TAG=${GITHUB_SHA::8} + + kubectl set image deployment/haproxy-mcp \ + haproxy-mcp=${IMAGE}:${TAG} \ + -n default + + kubectl rollout status deployment/haproxy-mcp \ + -n default --timeout=120s diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f624164 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM python:3.11-slim AS builder + +WORKDIR /app + +COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv + +COPY haproxy_mcp/pyproject.toml haproxy_mcp/uv.lock ./haproxy_mcp/ + +RUN cd haproxy_mcp && uv pip install --system --no-cache -e . + +COPY haproxy_mcp/ ./haproxy_mcp/ + +FROM python:3.11-slim + +WORKDIR /app + +COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages +COPY --from=builder /usr/local/bin /usr/local/bin +COPY --from=builder /app/haproxy_mcp ./haproxy_mcp + +EXPOSE 8000 + +ENTRYPOINT ["python", "-m", "haproxy_mcp"] diff --git a/k8s/deployment.yaml b/k8s/deployment.yaml new file mode 100644 index 0000000..72abb16 --- /dev/null +++ b/k8s/deployment.yaml @@ -0,0 +1,55 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: haproxy-mcp + namespace: default + labels: + app: haproxy-mcp +spec: + replicas: 1 + selector: + matchLabels: + app: haproxy-mcp + template: + metadata: + labels: + app: haproxy-mcp + spec: + imagePullSecrets: + - name: gitea-registry + containers: + - name: haproxy-mcp + image: gitea.anvil.it.com/kaffa/haproxy-mcp:latest + ports: + - containerPort: 8000 + protocol: TCP + env: + - name: MCP_HOST + value: "0.0.0.0" + - name: MCP_PORT + value: "8000" + - name: HAPROXY_HOST + value: "10.253.100.107" + - name: HAPROXY_PORT + value: "9999" + - name: LOG_LEVEL + value: "INFO" + readinessProbe: + httpGet: + path: /mcp + port: 8000 + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /mcp + port: 8000 + initialDelaySeconds: 10 + periodSeconds: 30 + resources: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "256Mi" + cpu: "500m" diff --git a/k8s/service.yaml b/k8s/service.yaml new file mode 100644 index 0000000..ba54d46 --- /dev/null +++ b/k8s/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: haproxy-mcp + namespace: default + labels: + app: haproxy-mcp +spec: + type: ClusterIP + selector: + app: haproxy-mcp + ports: + - port: 8000 + targetPort: 8000 + protocol: TCP + name: mcp