MCP服务器Kubernetes部署

通过GitOps方式在Kubernetes集群中部署和管理多个HTTP MCP服务器的配置清单集合,涵盖高可用、健康检查与安全加固。

  • by DataKnifeAI
  • 混合部署
  • 更新于
在 GitHub 查看 DataKnifeAI/gitops-mcp

使用说明

GitOps MCP - Kubernetes Deployments

Note: This project was built with Cursor and the Composer model, demonstrating AI-assisted development for Kubernetes infrastructure as code.

This repository contains Kubernetes deployment manifests for HTTP MCP servers in a dedicated mcp-servers namespace.

Repository Structure

gitops-mcp/
├── namespace.yaml                    # MCP servers namespace
├── kustomization.yaml                # Kustomize configuration
├── README.md                          # This file
├── .cursorrules                      # Cursor IDE instructions
├── .gitignore                         # Git ignore rules
├── docs/                              # Documentation
│   ├── MCP_SERVERS_REVIEW.md         # Server review and details
│   └── STRUCTURE.md                   # Repository structure guide
└── mcp-servers/                      # MCP server deployments
    ├── proxmox-ve-mcp/
    │   ├── deployment.yaml
    │   ├── service.yaml
    │   ├── configmap.yaml
    │   └── secret.yaml.example
    ├── unifi-network-mcp/
    │   ├── deployment.yaml
    │   ├── service.yaml
    │   ├── configmap.yaml
    │   └── secret.yaml.example
    ├── unifi-protect-mcp/
    │   ├── deployment.yaml
    │   ├── service.yaml
    │   ├── configmap.yaml
    │   └── secret.yaml.example
    └── high-command-mcp/
        ├── deployment.yaml
        ├── service.yaml
        ├── configmap.yaml
        └── secret.yaml.example

MCP Servers

The following HTTP MCP servers are configured:

  1. proxmox-ve-mcp - Proxmox VE management MCP server
  2. unifi-network-mcp - UniFi Network management MCP server
  3. unifi-protect-mcp - UniFi Protect management MCP server
  4. high-command-mcp - High Command MCP server

For detailed information about each server, see docs/MCP_SERVERS_REVIEW.md.

Prerequisites

  1. Kubernetes cluster access
  2. kubectl configured
  3. Container images available at Harbor registry:
    • harbor.dataknife.net/library/proxmox-ve-mcp:latest
    • harbor.dataknife.net/library/unifi-network-mcp:latest
    • harbor.dataknife.net/library/unifi-protect-mcp:latest
    • harbor.dataknife.net/library/high-command-mcp:latest
  4. Harbor registry credentials with pull access

Quick Start

Using Kustomize (Recommended)

  1. Create Harbor Registry Secret (required for pulling images):

    # Create the Harbor registry secret in the mcp-servers namespace
    kubectl create secret docker-registry harbor-registry-secret \
      --docker-server=harbor.dataknife.net \
      --docker-username=<your-harbor-username> \
      --docker-password=<your-harbor-password> \
      --docker-email=<your-email@example.com> \
      --namespace=mcp-servers
    
    # Verify the secret was created
    kubectl get secret harbor-registry-secret -n mcp-servers
    

    Alternative: Use the example template and apply it manually:

    # Edit mcp-servers/harbor-registry-secret.yaml.example with your credentials
    # Then apply it
    kubectl apply -f mcp-servers/harbor-registry-secret.yaml
    
  2. Create Application Secrets (one-time setup):

    # Copy example secrets and fill in your values
    cp mcp-servers/proxmox-ve-mcp/secret.yaml.example mcp-servers/proxmox-ve-mcp/secret.yaml
    cp mcp-servers/unifi-network-mcp/secret.yaml.example mcp-servers/unifi-network-mcp/secret.yaml
    cp mcp-servers/unifi-protect-mcp/secret.yaml.example mcp-servers/unifi-protect-mcp/secret.yaml
    
    # Edit each secret.yaml file with your actual credentials
    # DO NOT commit these files to git!
    
  3. Update kustomization.yaml to include secrets:

    resources:
      # ... existing resources ...
      - mcp-servers/proxmox-ve-mcp/secret.yaml
      - mcp-servers/unifi-network-mcp/secret.yaml
      - mcp-servers/unifi-protect-mcp/secret.yaml
    
  4. Deploy everything:

    kubectl apply -k .
    

Using Individual Files

  1. Create the namespace:

    kubectl apply -f namespace.yaml
    
  2. Create Harbor Registry Secret (required for pulling images):

    kubectl create secret docker-registry harbor-registry-secret \
      --docker-server=harbor.dataknife.net \
      --docker-username=<your-harbor-username> \
      --docker-password=<your-harbor-password> \
      --docker-email=<your-email@example.com> \
      --namespace=mcp-servers
    
  3. Deploy each MCP server:

    # Proxmox VE MCP
    kubectl apply -f mcp-servers/proxmox-ve-mcp/configmap.yaml
    kubectl apply -f mcp-servers/proxmox-ve-mcp/secret.yaml  # After creating from example
    kubectl apply -f mcp-servers/proxmox-ve-mcp/deployment.yaml
    kubectl apply -f mcp-servers/proxmox-ve-mcp/service.yaml
    
    # Repeat for other MCP servers...
    

Configuration

Namespace

All resources are deployed to the mcp-servers namespace, which is created automatically.

Harbor Registry Authentication

All deployments are configured to use Harbor registry (harbor.dataknife.net) and require authentication to pull images. The harbor-registry-secret must be created in the mcp-servers namespace before deploying.

Harbor serves a Let's Encrypt certificate, so nodes trust it via the public CA chain — there is no custom Harbor CA DaemonSet (containerd-harbor-cert-config) or harbor-ca-cert secret in this repo. If Fleet keepResources: true leaves those objects on prd-apps after sync, delete them manually in mcp-servers:

kubectl delete daemonset containerd-harbor-cert-config -n mcp-servers --context=prd-apps --ignore-not-found
kubectl delete secret harbor-ca-cert -n mcp-servers --context=prd-apps --ignore-not-found

Creating the Harbor Registry Secret:

kubectl create secret docker-registry harbor-registry-secret \
  --docker-server=harbor.dataknife.net \
  --docker-username=<your-harbor-username> \
  --docker-password=<your-harbor-password> \
  --docker-email=<your-email@example.com> \
  --namespace=mcp-servers

Note: If using a Harbor robot account (recommended for CI/CD), use the robot account username and token. Robot account format: robot$library+botname.

Using GitHub CLI and Actions:

  1. Set up secrets using GitHub CLI:

    # Use the interactive setup script
    ./scripts/setup-harbor-secrets.sh
    
    # Or manually set secrets
    echo "robot\$library+ci-bot" | gh secret set HARBOR_USERNAME
    echo "your-token" | gh secret set HARBOR_PASSWORD
    
  2. Deploy via GitHub Actions: Run the workflow .github/workflows/deploy-harbor-secret.yml which will automatically pull secrets and create the Kubernetes secret.

All deployments include imagePullSecrets referencing this secret.

Environment Variables

All servers use HTTP transport mode with the following common settings:

  • MCP_TRANSPORT=http
  • MCP_HTTP_ADDR=:8000
  • LOG_LEVEL (from ConfigMap, default: "info")

Server-Specific Configuration

Proxmox VE MCP

  • ConfigMap: proxmox-ve-mcp-config
    • LOG_LEVEL (default: "info")
    • PROXMOX_SKIP_SSL_VERIFY (default: "false")
  • Secrets: proxmox-ve-mcp-secrets
    • PROXMOX_BASE_URL - Proxmox server URL
    • PROXMOX_API_USER - API user
    • PROXMOX_API_TOKEN_ID - API token ID
    • PROXMOX_API_TOKEN_SECRET - API token secret

UniFi Network MCP

  • ConfigMap: unifi-network-mcp-config
    • LOG_LEVEL (default: "info")
    • UNIFI_BASE_URL (default: "https://192.168.1.1")
    • UNIFI_SKIP_SSL_VERIFY (default: "false")
  • Secrets: unifi-network-mcp-secrets
    • UNIFI_API_KEY - API key

UniFi Protect MCP

  • ConfigMap: unifi-protect-mcp-config
    • LOG_LEVEL (default: "info")
    • UNIFI_BASE_URL (default: "https://192.168.1.1")
    • UNIFI_SKIP_SSL_VERIFY (default: "false")
  • Secrets: unifi-protect-mcp-secrets
    • UNIFI_API_KEY - API key

UniFi Manager MCP

High Command MCP

  • ConfigMap: high-command-mcp-config
    • LOG_LEVEL (default: "info")
    • MCP_WORKERS (default: "4")
    • X_SUPER_CLIENT (default: "hc.mcp-servers.cluster")
    • X_SUPER_CONTACT (default: "ops@example.com")

Health Checks

All deployments include:

  • Liveness Probe: HTTP GET /health every 30 seconds
  • Readiness Probe: HTTP GET /health every 10 seconds

Resource Limits

Each pod has:

  • Requests: 100m CPU, 128Mi memory
  • Limits: 500m CPU, 512Mi memory

Security

All deployments use:

  • Non-root user (UID 1000)
  • Read-only root filesystem
  • Dropped capabilities
  • No privilege escalation
  • Dedicated namespace for isolation

High Availability

  • 2 replicas per deployment
  • Pod anti-affinity to spread pods across nodes
  • Health checks for automatic recovery

Service Endpoints

All services are exposed on port 8000 in the mcp-servers namespace:

  • proxmox-ve-mcp.mcp-servers.svc.cluster.local:8000
  • unifi-network-mcp.mcp-servers.svc.cluster.local:8000
  • unifi-protect-mcp.mcp-servers.svc.cluster.local:8000
  • high-command-mcp.mcp-servers.svc.cluster.local:8000

Monitoring

Check deployment status:

# All MCP servers
kubectl get deployments -n mcp-servers
kubectl get pods -n mcp-servers -l component=mcp-server
kubectl get services -n mcp-servers -l component=mcp-server

# Specific server
kubectl get pods -n mcp-servers -l app=proxmox-ve-mcp

Troubleshooting

View logs:

# All pods in namespace
kubectl logs -n mcp-servers -l component=mcp-server

# Specific server
kubectl logs -n mcp-servers -l app=proxmox-ve-mcp

# Specific pod
kubectl logs -n mcp-servers <pod-name>

Describe resources:

kubectl describe pod -n mcp-servers <pod-name>
kubectl describe deployment -n mcp-servers proxmox-ve-mcp

Check events:

kubectl get events -n mcp-servers --sort-by='.lastTimestamp'

GitOps

This repository is designed for GitOps workflows. Update the manifests and apply changes through your GitOps tool (ArgoCD, Flux, Fleet, etc.).

Fleet Compatibility

Note: The kustomization.yaml file has been renamed to .kustomization.yaml to prevent Rancher Fleet from auto-detecting it and attempting to use Kustomize post-rendering, which was causing deployment failures.

Fleet will process all Kubernetes YAML manifests directly, which works because:

  • All manifests already have namespaces and labels specified
  • Individual resource files are self-contained and valid
  • Fleet can apply Kubernetes manifests directly without Kustomize

For local Kustomize usage, temporarily rename the file:

mv .kustomization.yaml kustomization.yaml
kubectl kustomize .
mv kustomization.yaml .kustomization.yaml

Important: Never commit secret.yaml files to the repository. Use a secrets management solution like:

  • Sealed Secrets
  • External Secrets Operator
  • Vault
  • Your GitOps tool's secret management

High Command database (CloudNativePG)

k8s/high-command/ holds the high-command-postgres CloudNativePG Cluster (3 instances, 10Gi, database highcommand) and its high-command-postgres-pooler PgBouncer Pooler in the high-command namespace. Both were originally applied by hand and are adopted by Fleet via helm.takeOwnership in fleet.yaml. The Cluster spec deliberately mirrors the live object, including operator-defaulted fields. Keep it that way: under Helm adoption, any field dropped from the manifest is removed from the live object.

  • high-command-postgres-credentials (username, password) is created by hand, not in git.
  • max_slot_wal_keep_size: 2GB caps WAL retained for a lagging or broken replica, so a dead replication slot cannot fill the volume.
  • Rebuild a single broken replica with kubectl cnpg destroy high-command-postgres <n> -n high-command. CNPG re-clones it with pg_basebackup and drops the old slot.
  • Helm patches custom resources with a two-way merge (previous manifest to new manifest), so a field changed live and not in git is never corrected unless the manifest changes it.

Backups

WAL is archived continuously and a base backup runs daily at 09:30 UTC through the Barman Cloud plugin, installed by gitops-core cnpg-barman-cloud. The config is in k8s/high-command/objectstore.yaml (ObjectStore + ScheduledBackup) and the plugins section of the Cluster.

  • Where: s3://rke2-backups/cnpg/prd-apps/high-command-postgres/ on rustfs (https://rustfs.dataknife.net:30292), gzip, 14 day retention.
  • Credentials: cnpg-backup-rustfs secret in high-command (keys ACCESS_KEY_ID, ACCESS_SECRET_KEY), created by hand, not in git.
kubectl cnpg status high-command-postgres -n high-command
kubectl -n high-command get backups.postgresql.cnpg.io
kubectl cnpg backup high-command-postgres -n high-command --method=plugin --plugin-name=barman-cloud.cloudnative-pg.io

Restore (PITR possible): create a new Cluster with bootstrap.recovery.source set to an externalClusters entry that uses plugin barman-cloud.cloudnative-pg.io with barmanObjectName: high-command-postgres-rustfs and serverName: high-command-postgres. Then point the Pooler (spec.cluster.name) or the apps at the new cluster. A full example is in the gitops-core cnpg-barman-cloud README.

Documentation

File Organization

Each MCP server has its own directory with:

  • deployment.yaml - Deployment manifest
  • service.yaml - Service manifest
  • configmap.yaml - Non-sensitive configuration
  • secret.yaml.example - Secret template (copy to secret.yaml and fill in)

This organization makes it easy to:

  • Manage individual servers independently
  • Apply changes to specific servers
  • Understand the structure at a glance
  • Scale to additional MCP servers

For more details, see docs/STRUCTURE.md.

Development

This project uses Cursor IDE with the Composer model for AI-assisted development. See .cursorrules for project-specific coding guidelines and patterns.