使用说明
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:
- proxmox-ve-mcp - Proxmox VE management MCP server
- unifi-network-mcp - UniFi Network management MCP server
- unifi-protect-mcp - UniFi Protect management MCP server
- high-command-mcp - High Command MCP server
For detailed information about each server, see docs/MCP_SERVERS_REVIEW.md.
Prerequisites
- Kubernetes cluster access
kubectlconfigured- Container images available at Harbor registry:
harbor.dataknife.net/library/proxmox-ve-mcp:latestharbor.dataknife.net/library/unifi-network-mcp:latestharbor.dataknife.net/library/unifi-protect-mcp:latestharbor.dataknife.net/library/high-command-mcp:latest
- Harbor registry credentials with pull access
Quick Start
Using Kustomize (Recommended)
-
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-serversAlternative: 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 -
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! -
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 -
Deploy everything:
kubectl apply -k .
Using Individual Files
-
Create the namespace:
kubectl apply -f namespace.yaml -
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 -
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:
-
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 -
Deploy via GitHub Actions: Run the workflow
.github/workflows/deploy-harbor-secret.ymlwhich 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=httpMCP_HTTP_ADDR=:8000LOG_LEVEL(from ConfigMap, default: "info")
Server-Specific Configuration
Proxmox VE MCP
- ConfigMap:
proxmox-ve-mcp-configLOG_LEVEL(default: "info")PROXMOX_SKIP_SSL_VERIFY(default: "false")
- Secrets:
proxmox-ve-mcp-secretsPROXMOX_BASE_URL- Proxmox server URLPROXMOX_API_USER- API userPROXMOX_API_TOKEN_ID- API token IDPROXMOX_API_TOKEN_SECRET- API token secret
UniFi Network MCP
- ConfigMap:
unifi-network-mcp-configLOG_LEVEL(default: "info")UNIFI_BASE_URL(default: "https://192.168.1.1")UNIFI_SKIP_SSL_VERIFY(default: "false")
- Secrets:
unifi-network-mcp-secretsUNIFI_API_KEY- API key
UniFi Protect MCP
- ConfigMap:
unifi-protect-mcp-configLOG_LEVEL(default: "info")UNIFI_BASE_URL(default: "https://192.168.1.1")UNIFI_SKIP_SSL_VERIFY(default: "false")
- Secrets:
unifi-protect-mcp-secretsUNIFI_API_KEY- API key
UniFi Manager MCP
High Command MCP
- ConfigMap:
high-command-mcp-configLOG_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
/healthevery 30 seconds - Readiness Probe: HTTP GET
/healthevery 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:8000unifi-network-mcp.mcp-servers.svc.cluster.local:8000unifi-protect-mcp.mcp-servers.svc.cluster.local:8000high-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: 2GBcaps 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 withpg_basebackupand 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-rustfssecret inhigh-command(keysACCESS_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
- MCP Servers Review - Detailed review of all HTTP MCP servers
- Repository Structure - Guide to the repository organization
- Contributing - Guidelines for contributing to this project
- Code of Conduct - Community standards and expectations
- Security Policy - Security reporting and best practices
- Changelog - History of changes and updates
File Organization
Each MCP server has its own directory with:
deployment.yaml- Deployment manifestservice.yaml- Service manifestconfigmap.yaml- Non-sensitive configurationsecret.yaml.example- Secret template (copy tosecret.yamland 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.