docs: comprehensive documentation update for Helm chart and MCP sidecars
- Added MCP sidecar configuration documentation across all docs - Migrated from kustomize to Helm-based deployment instructions - Updated Makefile with new helm-* targets, removed outdated k8s-* targets - Rewrote DEPLOYMENT.md to focus on Helm chart deployment - Transformed VARIABLES.md into complete Helm values reference - Added MCP sidecar section to README.md with configuration examples Key improvements: - Clear instructions for enabling/disabling MCP servers - Consistent Helm-based deployment throughout documentation - Comprehensive values reference with examples - Better organization for different deployment scenarios Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -33,12 +33,14 @@ make clean # Remove volumes
|
||||
### Kubernetes Deployment
|
||||
|
||||
```bash
|
||||
make k8s-deploy # Deploy via kustomize
|
||||
kubectl apply -k k8s/ # Direct kustomize apply
|
||||
make k8s-delete # Tear down
|
||||
make k8s-port-forward # Forward port 5800 to localhost
|
||||
make k8s-logs # Stream container logs
|
||||
make k8s-shell # Open interactive shell in pod
|
||||
GITHUB_REPO="https://github.com/user/repo" make helm-deploy # Deploy with Helm
|
||||
make helm-delete # Tear down Helm release
|
||||
make helm-port-forward # Forward port 5800 to localhost
|
||||
make helm-logs # Stream container logs
|
||||
make helm-shell # Open interactive shell in pod
|
||||
|
||||
# Or use Helm directly
|
||||
helm install mydev ./chart --set name=mydev --set githubRepo=https://github.com/user/repo
|
||||
```
|
||||
|
||||
### Other Useful Targets
|
||||
@@ -86,6 +88,35 @@ Kubernetes and Flux MCP servers run as sidecar containers in the pod, inheriting
|
||||
|
||||
Both are enabled by default and configurable via `mcpSidecars` in `values.yaml`. Playwright MCP remains an external service.
|
||||
|
||||
#### Enabling/Disabling MCP Servers
|
||||
|
||||
To control MCP sidecars, set the `enabled` flag in your values override:
|
||||
|
||||
```yaml
|
||||
# Disable both MCP sidecars
|
||||
mcpSidecars:
|
||||
kubernetes:
|
||||
enabled: false
|
||||
flux:
|
||||
enabled: false
|
||||
|
||||
# Or selectively enable/disable
|
||||
mcpSidecars:
|
||||
kubernetes:
|
||||
enabled: true # Keep Kubernetes MCP enabled
|
||||
flux:
|
||||
enabled: false # Disable Flux MCP
|
||||
```
|
||||
|
||||
When deploying via Helm:
|
||||
```bash
|
||||
# Using --set flag
|
||||
helm install my-devcontainer ./chart --set mcpSidecars.kubernetes.enabled=false --set mcpSidecars.flux.enabled=false
|
||||
|
||||
# Or with a values file
|
||||
helm install my-devcontainer ./chart -f custom-values.yaml
|
||||
```
|
||||
|
||||
### Storage Model
|
||||
|
||||
- `/config` — ReadWriteMany PVC (persists across pod restarts, holds user config/dotfiles)
|
||||
|
||||
+356
-364
@@ -1,436 +1,428 @@
|
||||
# Deployment Guide
|
||||
|
||||
This guide provides step-by-step instructions for deploying the Antigravity Dev Container to Kubernetes.
|
||||
This guide provides step-by-step instructions for deploying the Antigravity Dev Container using Helm.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes cluster with Gateway API support
|
||||
- Kubernetes cluster (1.19+)
|
||||
- `kubectl` configured to access your cluster
|
||||
- `helm` CLI installed (3.0+)
|
||||
- ReadWriteMany storage class available (e.g., `ceph-filesystem`, `nfs-client`, `efs-sc`)
|
||||
- Sealed Secrets controller installed (for secret encryption)
|
||||
- GitHub Container Registry access (images are public)
|
||||
|
||||
## Required Configuration Variables
|
||||
## Quick Start
|
||||
|
||||
Before deploying, you need to provide the following configuration:
|
||||
|
||||
### 1. Storage Configuration
|
||||
|
||||
**Variable:** `storageClassName`
|
||||
**Location:** `k8s/statefulset.yaml` (line ~117)
|
||||
**Description:** The ReadWriteMany storage class name in your cluster
|
||||
**Example values:**
|
||||
- `ceph-filesystem` (Rook-Ceph)
|
||||
- `nfs-client` (NFS)
|
||||
- `efs-sc` (AWS EFS)
|
||||
- `azurefile` (Azure Files)
|
||||
- `filestore` (GCP Filestore)
|
||||
|
||||
**How to find your storage class:**
|
||||
```bash
|
||||
kubectl get storageclass
|
||||
```
|
||||
|
||||
Look for a storage class that supports `ReadWriteMany` access mode.
|
||||
|
||||
### 2. GitHub Repository (Required)
|
||||
|
||||
**Variable:** `github-repo`
|
||||
**Location:** `k8s/configmap.yaml` (line ~9)
|
||||
**Description:** The GitHub repository URL to clone on container startup
|
||||
**Format:** `https://github.com/username/repository`
|
||||
**Example:** `https://github.com/cpfarhood/my-project`
|
||||
|
||||
### 3. GitHub Token (Optional, for private repos)
|
||||
|
||||
**Variable:** `github-token`
|
||||
**Location:** `k8s/secrets-example.yaml` (sealed secret)
|
||||
**Description:** GitHub Personal Access Token for cloning private repositories
|
||||
**Format:** `ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
|
||||
**Required:** Only if cloning a private repository
|
||||
|
||||
**How to create a GitHub token:**
|
||||
1. Go to https://github.com/settings/tokens
|
||||
2. Click "Generate new token (classic)"
|
||||
3. Select scopes: `repo` (for private repos)
|
||||
4. Generate and copy the token
|
||||
|
||||
### 4. VNC Password (Optional)
|
||||
|
||||
**Variable:** `vnc-password`
|
||||
**Location:** `k8s/secrets-example.yaml` (sealed secret)
|
||||
**Description:** Password for accessing the VNC web interface
|
||||
**Format:** Any string (recommend 12+ characters)
|
||||
**Required:** Optional, but recommended for security
|
||||
|
||||
### 5. Gateway Configuration (Required for external access)
|
||||
|
||||
**Variables:**
|
||||
- `parentRefs.name` - Your Gateway resource name
|
||||
- `parentRefs.namespace` - Namespace where Gateway is deployed
|
||||
- `hostnames` - Domain name for accessing the container
|
||||
|
||||
**Location:** `k8s/httproute.yaml`
|
||||
**Example:**
|
||||
```yaml
|
||||
parentRefs:
|
||||
- name: cilium-gateway # Your Gateway name
|
||||
namespace: kube-system # Your Gateway namespace
|
||||
hostnames:
|
||||
- "devcontainer.example.com" # Your domain
|
||||
```
|
||||
|
||||
### 6. Namespace (Optional)
|
||||
|
||||
**Variable:** `namespace`
|
||||
**Location:** `k8s/kustomization.yaml` (line ~5)
|
||||
**Description:** Kubernetes namespace to deploy into
|
||||
**Default:** `default`
|
||||
**Example:** `devcontainer`, `development`, `team-workspaces`
|
||||
|
||||
### 7. Container Image (Optional)
|
||||
|
||||
**Variable:** `image`
|
||||
**Location:** `k8s/statefulset.yaml` (line ~32)
|
||||
**Description:** Docker image to use
|
||||
**Default:** `ghcr.io/cpfarhood/devcontainer:latest`
|
||||
**Format:** `registry/repository:tag`
|
||||
|
||||
### 8. Resource Limits (Optional)
|
||||
|
||||
**Variables:**
|
||||
- `resources.requests.memory` (default: `2Gi`)
|
||||
- `resources.requests.cpu` (default: `1000m`)
|
||||
- `resources.limits.memory` (default: `8Gi`)
|
||||
- `resources.limits.cpu` (default: `4000m`)
|
||||
|
||||
**Location:** `k8s/statefulset.yaml` (lines ~98-103)
|
||||
|
||||
### 9. Happy Coder Configuration (Optional)
|
||||
|
||||
**Variables:**
|
||||
- `happy-server-url` - Custom Happy server URL
|
||||
- `happy-webapp-url` - Custom Happy webapp URL
|
||||
|
||||
**Location:** `k8s/configmap.yaml` (lines ~12-13, commented out)
|
||||
**Default:** Uses Happy's default servers
|
||||
**When to set:** Only if using a self-hosted Happy instance
|
||||
|
||||
## Deployment Steps
|
||||
|
||||
### Step 1: Clone the Repository
|
||||
### 1. Clone the Repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/cpfarhood/devcontainer.git
|
||||
cd devcontainer
|
||||
```
|
||||
|
||||
### Step 2: Configure Storage Class
|
||||
### 2. Create Secret (Optional)
|
||||
|
||||
Edit `k8s/statefulset.yaml` and find the `volumeClaimTemplates` section (around line 117):
|
||||
For private repos or VNC password:
|
||||
|
||||
```bash
|
||||
# Find your storage class
|
||||
kubectl get storageclass
|
||||
|
||||
# Edit the file
|
||||
vi k8s/statefulset.yaml
|
||||
kubectl create secret generic devcontainer-mydev-secrets-env \
|
||||
--from-literal=GITHUB_TOKEN='ghp_...' \
|
||||
--from-literal=VNC_PASSWORD='changeme' \
|
||||
--from-literal=ANTHROPIC_API_KEY='sk-ant-...'
|
||||
```
|
||||
|
||||
Change `storageClassName` to match your cluster:
|
||||
```yaml
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: userhome
|
||||
spec:
|
||||
accessModes: [ "ReadWriteMany" ]
|
||||
storageClassName: "ceph-filesystem" # ← Change this
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
```
|
||||
|
||||
### Step 3: Configure GitHub Repository
|
||||
|
||||
Edit `k8s/configmap.yaml`:
|
||||
### 3. Deploy with Helm
|
||||
|
||||
```bash
|
||||
vi k8s/configmap.yaml
|
||||
# Basic deployment
|
||||
helm install mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/youruser/yourrepo
|
||||
|
||||
# With custom storage class
|
||||
helm install mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/youruser/yourrepo \
|
||||
--set storage.className=nfs-client
|
||||
|
||||
# With cluster access for kubectl
|
||||
helm install mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/youruser/yourrepo \
|
||||
--set clusterAccess=readwritens
|
||||
```
|
||||
|
||||
Set your repository URL:
|
||||
```yaml
|
||||
data:
|
||||
github-repo: "https://github.com/yourusername/yourrepo"
|
||||
```
|
||||
|
||||
### Step 4: Configure Gateway (HTTPRoute)
|
||||
|
||||
Edit `k8s/httproute.yaml`:
|
||||
### 4. Access the Container
|
||||
|
||||
```bash
|
||||
# Find your Gateway
|
||||
kubectl get gateway -A
|
||||
|
||||
# Edit the file
|
||||
vi k8s/httproute.yaml
|
||||
```
|
||||
|
||||
Update with your Gateway details:
|
||||
```yaml
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: your-gateway-name # ← Change this
|
||||
namespace: your-gateway-namespace # ← Change this
|
||||
hostnames:
|
||||
- "devcontainer.yourdomain.com" # ← Change this
|
||||
```
|
||||
|
||||
### Step 5: Create Secrets
|
||||
|
||||
Create the secrets for GitHub token and VNC password:
|
||||
|
||||
```bash
|
||||
# Create the secret
|
||||
kubectl create secret generic antigravity-secrets \
|
||||
--from-literal=github-token='ghp_your_token_here' \
|
||||
--from-literal=vnc-password='your_vnc_password' \
|
||||
--dry-run=client -o yaml | \
|
||||
kubeseal --format=yaml > k8s/sealedsecrets.yaml
|
||||
|
||||
# Verify the sealed secret was created
|
||||
cat k8s/sealedsecrets.yaml
|
||||
```
|
||||
|
||||
**If you don't have Sealed Secrets controller:**
|
||||
|
||||
Option 1: Install Sealed Secrets
|
||||
```bash
|
||||
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml
|
||||
```
|
||||
|
||||
Option 2: Use plain secrets (not recommended for production)
|
||||
```bash
|
||||
kubectl create secret generic antigravity-secrets \
|
||||
--from-literal=github-token='ghp_your_token_here' \
|
||||
--from-literal=vnc-password='your_vnc_password'
|
||||
```
|
||||
|
||||
### Step 6: Review Configuration (Optional)
|
||||
|
||||
Review and adjust optional settings:
|
||||
|
||||
**Namespace:**
|
||||
```bash
|
||||
vi k8s/kustomization.yaml
|
||||
# Change line 5: namespace: default
|
||||
```
|
||||
|
||||
**Resource limits:**
|
||||
```bash
|
||||
vi k8s/statefulset.yaml
|
||||
# Adjust lines 98-103 for your needs
|
||||
```
|
||||
|
||||
### Step 7: Deploy to Kubernetes
|
||||
|
||||
```bash
|
||||
# Deploy everything
|
||||
kubectl apply -k k8s/
|
||||
|
||||
# Or if you changed the namespace
|
||||
kubectl apply -k k8s/ -n your-namespace
|
||||
```
|
||||
|
||||
### Step 8: Verify Deployment
|
||||
|
||||
```bash
|
||||
# Check StatefulSet
|
||||
kubectl get statefulset antigravity
|
||||
|
||||
# Check Pod
|
||||
kubectl get pods -l app=antigravity
|
||||
|
||||
# Check PVC
|
||||
kubectl get pvc -l app=antigravity
|
||||
|
||||
# Check HTTPRoute
|
||||
kubectl get httproute antigravity
|
||||
|
||||
# View logs
|
||||
kubectl logs antigravity-0
|
||||
```
|
||||
|
||||
### Step 9: Access the Container
|
||||
|
||||
**Option A: Via HTTPRoute (external access)**
|
||||
```bash
|
||||
# Open in browser
|
||||
open https://devcontainer.yourdomain.com
|
||||
```
|
||||
|
||||
**Option B: Via Port Forward (local access)**
|
||||
```bash
|
||||
# Port forward to localhost
|
||||
kubectl port-forward statefulset/antigravity 5800:5800
|
||||
|
||||
# Open in browser
|
||||
# Port forward
|
||||
kubectl port-forward deployment/devcontainer-mydev 5800:5800
|
||||
open http://localhost:5800
|
||||
```
|
||||
|
||||
## Configuration Summary
|
||||
## Deployment Options
|
||||
|
||||
Here's a quick checklist of all variables you need to set:
|
||||
### Using Values File
|
||||
|
||||
### Required Variables
|
||||
Create a custom `values.yaml`:
|
||||
|
||||
| Variable | File | Line | Example Value |
|
||||
|----------|------|------|---------------|
|
||||
| `storageClassName` | `k8s/statefulset.yaml` | ~117 | `ceph-filesystem` |
|
||||
| `github-repo` | `k8s/configmap.yaml` | ~9 | `https://github.com/user/repo` |
|
||||
| `parentRefs.name` | `k8s/httproute.yaml` | ~8 | `cilium-gateway` |
|
||||
| `parentRefs.namespace` | `k8s/httproute.yaml` | ~9 | `kube-system` |
|
||||
| `hostnames` | `k8s/httproute.yaml` | ~10 | `devcontainer.example.com` |
|
||||
```yaml
|
||||
name: mydev
|
||||
githubRepo: https://github.com/youruser/yourrepo
|
||||
ide: vscode
|
||||
ssh: false
|
||||
|
||||
### Optional Variables
|
||||
# Storage
|
||||
storage:
|
||||
size: 32Gi
|
||||
className: ceph-filesystem
|
||||
|
||||
| Variable | File | Line | Default | When to Change |
|
||||
|----------|------|------|---------|----------------|
|
||||
| `namespace` | `k8s/kustomization.yaml` | ~5 | `default` | If deploying to different namespace |
|
||||
| `github-token` | Sealed secret | N/A | None | For private repos |
|
||||
| `vnc-password` | Sealed secret | N/A | None | For VNC security |
|
||||
| `image` | `k8s/statefulset.yaml` | ~32 | `ghcr.io/cpfarhood/devcontainer:latest` | For specific version or custom build |
|
||||
| `resources.*` | `k8s/statefulset.yaml` | ~98-103 | 2Gi/8Gi RAM, 1/4 CPU | Based on workload needs |
|
||||
| `happy-server-url` | `k8s/configmap.yaml` | ~12 | Default Happy server | For self-hosted Happy |
|
||||
| `happy-webapp-url` | `k8s/configmap.yaml` | ~13 | Default Happy webapp | For self-hosted Happy |
|
||||
# Resources
|
||||
resources:
|
||||
requests:
|
||||
memory: "4Gi"
|
||||
cpu: "2000m"
|
||||
limits:
|
||||
memory: "16Gi"
|
||||
cpu: "8000m"
|
||||
|
||||
# Kubernetes access
|
||||
clusterAccess: readwritens
|
||||
|
||||
# MCP sidecars
|
||||
mcpSidecars:
|
||||
kubernetes:
|
||||
enabled: true
|
||||
flux:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
Deploy:
|
||||
|
||||
```bash
|
||||
helm install mydev ./chart -f values.yaml
|
||||
```
|
||||
|
||||
### SSH Access Setup
|
||||
|
||||
Enable SSH and add your public key:
|
||||
|
||||
```bash
|
||||
# Create secret with SSH key
|
||||
kubectl create secret generic devcontainer-mydev-secrets-env \
|
||||
--from-literal=SSH_AUTHORIZED_KEYS='ssh-ed25519 AAAA...'
|
||||
|
||||
# Deploy with SSH enabled
|
||||
helm install mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/youruser/yourrepo \
|
||||
--set ssh=true
|
||||
|
||||
# Connect via SSH
|
||||
kubectl port-forward deployment/devcontainer-mydev 2222:22
|
||||
ssh -p 2222 user@localhost
|
||||
```
|
||||
|
||||
### MCP Sidecar Configuration
|
||||
|
||||
Control MCP servers for AI-assisted operations:
|
||||
|
||||
```bash
|
||||
# Disable all MCP sidecars
|
||||
helm install mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/youruser/yourrepo \
|
||||
--set mcpSidecars.kubernetes.enabled=false \
|
||||
--set mcpSidecars.flux.enabled=false
|
||||
|
||||
# Enable only Kubernetes MCP
|
||||
helm install mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/youruser/yourrepo \
|
||||
--set mcpSidecars.kubernetes.enabled=true \
|
||||
--set mcpSidecars.flux.enabled=false
|
||||
```
|
||||
|
||||
### Cluster Access Levels
|
||||
|
||||
Configure Kubernetes RBAC permissions:
|
||||
|
||||
| Value | Scope | Permissions | Use Case |
|
||||
|-------|-------|-------------|----------|
|
||||
| `none` | No access | None | Default, isolated development |
|
||||
| `readonlyns` | Namespace | Read-only | View resources in namespace |
|
||||
| `readwritens` | Namespace | Full access | Deploy apps in namespace |
|
||||
| `readonly` | Cluster-wide | Read-only | View all cluster resources |
|
||||
| `readwrite` | Cluster-wide | Full access | Cluster administration |
|
||||
|
||||
```bash
|
||||
# Example: Full access within namespace
|
||||
helm install mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/youruser/yourrepo \
|
||||
--set clusterAccess=readwritens
|
||||
```
|
||||
|
||||
## Ingress Configuration
|
||||
|
||||
### Using Gateway API HTTPRoute
|
||||
|
||||
Create an HTTPRoute for external access:
|
||||
|
||||
```yaml
|
||||
apiVersion: gateway.networking.k8s.io/v1beta1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: devcontainer-mydev
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: your-gateway
|
||||
namespace: your-gateway-namespace
|
||||
hostnames:
|
||||
- devcontainer.example.com
|
||||
rules:
|
||||
- backendRefs:
|
||||
- name: devcontainer-mydev
|
||||
port: 5800
|
||||
```
|
||||
|
||||
### Using Traditional Ingress
|
||||
|
||||
Create an Ingress resource:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: devcontainer-mydev
|
||||
spec:
|
||||
rules:
|
||||
- host: devcontainer.example.com
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: devcontainer-mydev
|
||||
port:
|
||||
number: 5800
|
||||
```
|
||||
|
||||
## Advanced Configurations
|
||||
|
||||
### Custom Happy Coder Endpoints
|
||||
|
||||
For self-hosted Happy instances:
|
||||
|
||||
```bash
|
||||
helm install mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/youruser/yourrepo \
|
||||
--set happyServerUrl=https://your-happy-server.com \
|
||||
--set happyWebappUrl=https://your-happy-webapp.com
|
||||
```
|
||||
|
||||
### Custom Display Resolution
|
||||
|
||||
```bash
|
||||
helm install mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/youruser/yourrepo \
|
||||
--set display.width=2560 \
|
||||
--set display.height=1440
|
||||
```
|
||||
|
||||
### Different IDE Options
|
||||
|
||||
```bash
|
||||
# Use Google Antigravity
|
||||
helm install mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/youruser/yourrepo \
|
||||
--set ide=antigravity
|
||||
|
||||
# SSH-only mode (no GUI)
|
||||
helm install mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/youruser/yourrepo \
|
||||
--set ide=none \
|
||||
--set ssh=true
|
||||
```
|
||||
|
||||
## Helm Operations
|
||||
|
||||
### List Deployments
|
||||
|
||||
```bash
|
||||
helm list
|
||||
```
|
||||
|
||||
### Upgrade Deployment
|
||||
|
||||
```bash
|
||||
# Change values
|
||||
helm upgrade mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/youruser/newrepo
|
||||
|
||||
# Upgrade with new chart version
|
||||
git pull
|
||||
helm upgrade mydev ./chart
|
||||
```
|
||||
|
||||
### Uninstall
|
||||
|
||||
```bash
|
||||
helm uninstall mydev
|
||||
|
||||
# Note: PVC persists by default
|
||||
kubectl delete pvc userhome-mydev
|
||||
```
|
||||
|
||||
### Rollback
|
||||
|
||||
```bash
|
||||
# View history
|
||||
helm history mydev
|
||||
|
||||
# Rollback to previous version
|
||||
helm rollback mydev
|
||||
|
||||
# Rollback to specific revision
|
||||
helm rollback mydev 3
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Pod not starting
|
||||
### Pod Not Starting
|
||||
|
||||
**Check events:**
|
||||
```bash
|
||||
kubectl describe pod antigravity-0
|
||||
# Check pod status
|
||||
kubectl get pods -l app.kubernetes.io/instance=mydev
|
||||
|
||||
# Describe pod for events
|
||||
kubectl describe pod -l app.kubernetes.io/instance=mydev
|
||||
|
||||
# Check logs
|
||||
kubectl logs deployment/devcontainer-mydev
|
||||
```
|
||||
|
||||
**Common issues:**
|
||||
- Storage class doesn't support ReadWriteMany
|
||||
- PVC not binding (check storage class exists)
|
||||
- Image pull errors (check image name)
|
||||
### Repository Not Cloning
|
||||
|
||||
### Repository not cloning
|
||||
|
||||
**Check logs:**
|
||||
```bash
|
||||
kubectl logs antigravity-0 | grep -A 10 "Repository Initialization"
|
||||
# Check init logs
|
||||
kubectl logs deployment/devcontainer-mydev | grep "Repository Initialization"
|
||||
|
||||
# Verify secret exists
|
||||
kubectl get secret devcontainer-mydev-secrets-env
|
||||
|
||||
# Check environment
|
||||
kubectl exec deployment/devcontainer-mydev -- env | grep GITHUB
|
||||
```
|
||||
|
||||
**Common issues:**
|
||||
- Invalid GitHub URL
|
||||
- Private repo without token
|
||||
- Token doesn't have correct permissions
|
||||
### VNC Not Accessible
|
||||
|
||||
### HTTPRoute not working
|
||||
|
||||
**Check HTTPRoute:**
|
||||
```bash
|
||||
kubectl describe httproute antigravity
|
||||
# Check service
|
||||
kubectl get svc devcontainer-mydev
|
||||
kubectl describe svc devcontainer-mydev
|
||||
|
||||
# Test with port-forward
|
||||
kubectl port-forward deployment/devcontainer-mydev 5800:5800
|
||||
```
|
||||
|
||||
**Common issues:**
|
||||
- Gateway name/namespace incorrect
|
||||
- Domain not pointing to Gateway
|
||||
- TLS certificate not issued
|
||||
### MCP Sidecar Issues
|
||||
|
||||
### VNC not accessible
|
||||
|
||||
**Check service:**
|
||||
```bash
|
||||
kubectl get svc antigravity
|
||||
kubectl describe svc antigravity
|
||||
# Check all containers
|
||||
kubectl get pod -l app.kubernetes.io/instance=mydev -o jsonpath='{.items[0].spec.containers[*].name}'
|
||||
|
||||
# Check MCP container logs
|
||||
kubectl logs deployment/devcontainer-mydev -c kubernetes-mcp
|
||||
kubectl logs deployment/devcontainer-mydev -c flux-mcp
|
||||
|
||||
# Verify RBAC permissions
|
||||
kubectl auth can-i --list --as system:serviceaccount:default:devcontainer-mydev
|
||||
```
|
||||
|
||||
**Port forward test:**
|
||||
### Storage Issues
|
||||
|
||||
```bash
|
||||
kubectl port-forward antigravity-0 5800:5800
|
||||
# Try accessing http://localhost:5800
|
||||
# Check PVC
|
||||
kubectl get pvc userhome-mydev
|
||||
kubectl describe pvc userhome-mydev
|
||||
|
||||
# Check available storage classes
|
||||
kubectl get storageclass
|
||||
|
||||
# Verify ReadWriteMany support
|
||||
kubectl get storageclass <class-name> -o yaml | grep -i accessmodes
|
||||
```
|
||||
|
||||
## Quick Deploy Example
|
||||
## Best Practices
|
||||
|
||||
Complete deployment with all values filled in:
|
||||
### Production Deployment
|
||||
|
||||
1. **Use specific image tags** instead of `latest`:
|
||||
```bash
|
||||
helm install mydev ./chart --set image.tag=v1.0.0
|
||||
```
|
||||
|
||||
2. **Set resource limits** appropriately:
|
||||
```yaml
|
||||
resources:
|
||||
requests:
|
||||
memory: "4Gi"
|
||||
cpu: "2000m"
|
||||
limits:
|
||||
memory: "8Gi"
|
||||
cpu: "4000m"
|
||||
```
|
||||
|
||||
3. **Enable VNC password**:
|
||||
```bash
|
||||
kubectl create secret generic devcontainer-mydev-secrets-env \
|
||||
--from-literal=VNC_PASSWORD='strong-password-here'
|
||||
```
|
||||
|
||||
4. **Use dedicated namespace**:
|
||||
```bash
|
||||
kubectl create namespace dev-environments
|
||||
helm install mydev ./chart -n dev-environments
|
||||
```
|
||||
|
||||
5. **Configure appropriate cluster access**:
|
||||
- Use `readonlyns` or `readwritens` for namespace-scoped work
|
||||
- Avoid `readwrite` cluster-wide access unless necessary
|
||||
|
||||
### Multi-User Deployment
|
||||
|
||||
For teams, create separate deployments per user:
|
||||
|
||||
```bash
|
||||
# 1. Set your values
|
||||
STORAGE_CLASS="ceph-filesystem"
|
||||
GITHUB_REPO="https://github.com/myuser/myproject"
|
||||
GITHUB_TOKEN="ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
VNC_PASSWORD="my-secure-password-123"
|
||||
GATEWAY_NAME="cilium-gateway"
|
||||
GATEWAY_NAMESPACE="kube-system"
|
||||
DOMAIN="devcontainer.example.com"
|
||||
# User 1
|
||||
helm install alice-dev ./chart \
|
||||
--set name=alice-dev \
|
||||
--set githubRepo=https://github.com/alice/project
|
||||
|
||||
# 2. Update storage class
|
||||
sed -i "s/storageClassName: .*/storageClassName: \"$STORAGE_CLASS\"/" k8s/statefulset.yaml
|
||||
|
||||
# 3. Update GitHub repo
|
||||
sed -i "s|github-repo: .*|github-repo: \"$GITHUB_REPO\"|" k8s/configmap.yaml
|
||||
|
||||
# 4. Update Gateway
|
||||
sed -i "s/- name: gateway/- name: $GATEWAY_NAME/" k8s/httproute.yaml
|
||||
sed -i "s/namespace: gateway-system/namespace: $GATEWAY_NAMESPACE/" k8s/httproute.yaml
|
||||
sed -i "s/antigravity.example.com/$DOMAIN/" k8s/httproute.yaml
|
||||
|
||||
# 5. Create sealed secret
|
||||
kubectl create secret generic antigravity-secrets \
|
||||
--from-literal=github-token="$GITHUB_TOKEN" \
|
||||
--from-literal=vnc-password="$VNC_PASSWORD" \
|
||||
--dry-run=client -o yaml | \
|
||||
kubeseal --format=yaml > k8s/sealedsecrets.yaml
|
||||
|
||||
# 6. Deploy
|
||||
kubectl apply -k k8s/
|
||||
|
||||
# 7. Watch deployment
|
||||
kubectl get pods -l app=antigravity -w
|
||||
# User 2
|
||||
helm install bob-dev ./chart \
|
||||
--set name=bob-dev \
|
||||
--set githubRepo=https://github.com/bob/project
|
||||
```
|
||||
|
||||
## Updates and Maintenance
|
||||
### Backup and Recovery
|
||||
|
||||
### Updating the Image
|
||||
|
||||
The image is automatically built and pushed to ghcr.io on every commit to main.
|
||||
|
||||
**To use latest:**
|
||||
```bash
|
||||
kubectl set image statefulset/antigravity \
|
||||
antigravity=ghcr.io/cpfarhood/devcontainer:latest
|
||||
```
|
||||
|
||||
**To use specific version:**
|
||||
```bash
|
||||
kubectl set image statefulset/antigravity \
|
||||
antigravity=ghcr.io/cpfarhood/devcontainer:v1.0.0
|
||||
```
|
||||
|
||||
### Changing Repository
|
||||
|
||||
Edit the ConfigMap and restart:
|
||||
```bash
|
||||
kubectl edit configmap antigravity-config
|
||||
# Change github-repo value
|
||||
kubectl rollout restart statefulset/antigravity
|
||||
```
|
||||
|
||||
### Scaling
|
||||
The home directory persists on PVC. To backup:
|
||||
|
||||
```bash
|
||||
# Scale to multiple instances (each gets own home PVC)
|
||||
kubectl scale statefulset antigravity --replicas=3
|
||||
# Create backup pod
|
||||
kubectl run backup --image=busybox --restart=Never --rm -i --tty \
|
||||
-- tar czf - -C /home . | gzip > home-backup.tar.gz
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions:
|
||||
- GitHub Issues: https://github.com/cpfarhood/devcontainer/issues
|
||||
- Documentation: https://github.com/cpfarhood/devcontainer
|
||||
- Documentation: https://github.com/cpfarhood/devcontainer
|
||||
@@ -44,26 +44,40 @@ clean: stop
|
||||
@echo "Cleaning up..."
|
||||
rm -rf ./home ./workspace
|
||||
|
||||
# Kubernetes deployment
|
||||
k8s-deploy:
|
||||
@echo "Deploying to Kubernetes..."
|
||||
kubectl apply -k k8s/
|
||||
# Helm deployment
|
||||
RELEASE_NAME ?= mydev
|
||||
NAMESPACE ?= default
|
||||
|
||||
k8s-delete:
|
||||
@echo "Deleting from Kubernetes..."
|
||||
kubectl delete -k k8s/
|
||||
helm-deploy:
|
||||
@echo "Deploying with Helm (release: $(RELEASE_NAME))..."
|
||||
@if [ -z "$(GITHUB_REPO)" ]; then \
|
||||
echo "ERROR: GITHUB_REPO environment variable is required"; \
|
||||
echo "Usage: GITHUB_REPO=https://github.com/user/repo make helm-deploy"; \
|
||||
exit 1; \
|
||||
fi
|
||||
helm upgrade --install $(RELEASE_NAME) ./chart \
|
||||
--namespace $(NAMESPACE) \
|
||||
--set name=$(RELEASE_NAME) \
|
||||
--set githubRepo="$(GITHUB_REPO)" \
|
||||
--set image.repository=$(REGISTRY)/$(IMAGE_NAME) \
|
||||
--set image.tag=$(IMAGE_TAG)
|
||||
|
||||
k8s-logs:
|
||||
@echo "Showing logs..."
|
||||
kubectl logs -f antigravity-0
|
||||
helm-delete:
|
||||
@echo "Deleting Helm release $(RELEASE_NAME)..."
|
||||
helm uninstall $(RELEASE_NAME) --namespace $(NAMESPACE)
|
||||
@echo "Note: PVC persists. To delete: kubectl delete pvc userhome-$(RELEASE_NAME) -n $(NAMESPACE)"
|
||||
|
||||
k8s-shell:
|
||||
@echo "Opening shell..."
|
||||
kubectl exec -it antigravity-0 -- bash
|
||||
helm-logs:
|
||||
@echo "Showing logs for $(RELEASE_NAME)..."
|
||||
kubectl logs -f deployment/devcontainer-$(RELEASE_NAME) -n $(NAMESPACE)
|
||||
|
||||
k8s-port-forward:
|
||||
@echo "Port forwarding to localhost:5800..."
|
||||
kubectl port-forward antigravity-0 5800:5800
|
||||
helm-shell:
|
||||
@echo "Opening shell in $(RELEASE_NAME)..."
|
||||
kubectl exec -it deployment/devcontainer-$(RELEASE_NAME) -n $(NAMESPACE) -- bash
|
||||
|
||||
helm-port-forward:
|
||||
@echo "Port forwarding $(RELEASE_NAME) to localhost:5800..."
|
||||
kubectl port-forward deployment/devcontainer-$(RELEASE_NAME) 5800:5800 -n $(NAMESPACE)
|
||||
|
||||
# Show help
|
||||
help:
|
||||
@@ -78,24 +92,29 @@ help:
|
||||
@echo " stop - Stop running container"
|
||||
@echo " clean - Clean up containers and volumes"
|
||||
@echo ""
|
||||
@echo "Kubernetes Targets:"
|
||||
@echo " k8s-deploy - Deploy to Kubernetes"
|
||||
@echo " k8s-delete - Delete from Kubernetes"
|
||||
@echo " k8s-logs - Show container logs"
|
||||
@echo " k8s-shell - Open shell in container"
|
||||
@echo " k8s-port-forward - Port forward to localhost"
|
||||
@echo "Helm/Kubernetes Targets:"
|
||||
@echo " helm-deploy - Deploy with Helm chart (requires GITHUB_REPO)"
|
||||
@echo " helm-delete - Delete Helm release"
|
||||
@echo " helm-logs - Show container logs"
|
||||
@echo " helm-shell - Open shell in container"
|
||||
@echo " helm-port-forward - Port forward to localhost"
|
||||
@echo ""
|
||||
@echo "Variables:"
|
||||
@echo " REGISTRY - Docker registry (default: ghcr.io/cpfarhood)"
|
||||
@echo " IMAGE_NAME - Image name (default: antigravity)"
|
||||
@echo " IMAGE_TAG - Image tag (default: latest)"
|
||||
@echo " RELEASE_NAME - Helm release name (default: mydev)"
|
||||
@echo " NAMESPACE - Kubernetes namespace (default: default)"
|
||||
@echo " GITHUB_REPO - GitHub repository URL (required for helm-deploy)"
|
||||
@echo ""
|
||||
@echo "Environment Variables for 'make run':"
|
||||
@echo " GITHUB_REPO - GitHub repository URL"
|
||||
@echo " GITHUB_TOKEN - GitHub token (optional)"
|
||||
@echo " VNC_PASSWORD - VNC password (optional)"
|
||||
@echo ""
|
||||
@echo "Example:"
|
||||
@echo "Examples:"
|
||||
@echo " make build"
|
||||
@echo " make push REGISTRY=ghcr.io/myuser IMAGE_TAG=v1.0"
|
||||
@echo " GITHUB_REPO=https://github.com/user/repo make run"
|
||||
@echo " GITHUB_REPO=https://github.com/user/repo make helm-deploy"
|
||||
@echo " RELEASE_NAME=alice-dev GITHUB_REPO=https://github.com/alice/project make helm-deploy"
|
||||
|
||||
@@ -150,6 +150,54 @@ helm install mydev ./chart \
|
||||
|
||||
With any non-`none` value, a `ServiceAccount` named `devcontainer-{name}` is created and set as the pod's `serviceAccountName`, so `kubectl` and any in-cluster API calls use it automatically.
|
||||
|
||||
### MCP Sidecars
|
||||
|
||||
The devcontainer includes MCP (Model Context Protocol) servers as sidecar containers that enable AI assistants to interact with Kubernetes and Flux:
|
||||
|
||||
| Sidecar | Default | Purpose |
|
||||
|---------|---------|---------|
|
||||
| `mcpSidecars.kubernetes.enabled` | `true` | Kubernetes API access via MCP |
|
||||
| `mcpSidecars.flux.enabled` | `true` | Flux GitOps operations via MCP |
|
||||
|
||||
These sidecars inherit the pod's ServiceAccount RBAC permissions (controlled by `clusterAccess`).
|
||||
|
||||
**Disable MCP sidecars:**
|
||||
```bash
|
||||
# Disable both sidecars
|
||||
helm install mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/youruser/yourrepo \
|
||||
--set mcpSidecars.kubernetes.enabled=false \
|
||||
--set mcpSidecars.flux.enabled=false
|
||||
|
||||
# Or selectively disable
|
||||
helm install mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/youruser/yourrepo \
|
||||
--set mcpSidecars.flux.enabled=false # Disable only Flux MCP
|
||||
```
|
||||
|
||||
**Custom MCP configuration:**
|
||||
```yaml
|
||||
# values.yaml override
|
||||
mcpSidecars:
|
||||
kubernetes:
|
||||
enabled: true
|
||||
image:
|
||||
repository: quay.io/containers/kubernetes_mcp_server
|
||||
tag: latest
|
||||
port: 8080
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
flux:
|
||||
enabled: false # Disabled in this example
|
||||
```
|
||||
|
||||
### Display and resources
|
||||
|
||||
| Value | Default | Description |
|
||||
|
||||
+353
-275
@@ -1,305 +1,383 @@
|
||||
# Configuration Variables Reference
|
||||
# Helm Chart Values Reference
|
||||
|
||||
Quick reference for all configurable variables in this project.
|
||||
Complete reference for all configurable values in the Antigravity Dev Container Helm chart.
|
||||
|
||||
## Required Variables
|
||||
## Core Configuration
|
||||
|
||||
These MUST be configured before deployment:
|
||||
|
||||
### Storage Class Name
|
||||
- **Variable:** `storageClassName`
|
||||
- **File:** `k8s/statefulset.yaml`
|
||||
- **Line:** ~117
|
||||
### name
|
||||
- **Type:** String
|
||||
- **Description:** ReadWriteMany storage class available in your cluster
|
||||
- **Example:** `ceph-filesystem`, `nfs-client`, `efs-sc`
|
||||
- **How to find:** `kubectl get storageclass`
|
||||
|
||||
### GitHub Repository URL
|
||||
- **Variable:** `github-repo`
|
||||
- **File:** `k8s/configmap.yaml`
|
||||
- **Line:** ~9
|
||||
- **Type:** String (URL)
|
||||
- **Description:** Repository to clone on container startup
|
||||
- **Format:** `https://github.com/username/repository`
|
||||
- **Example:** `https://github.com/cpfarhood/my-project`
|
||||
|
||||
### Gateway Name
|
||||
- **Variable:** `parentRefs[0].name`
|
||||
- **File:** `k8s/httproute.yaml`
|
||||
- **Line:** ~8
|
||||
- **Type:** String
|
||||
- **Description:** Name of your Gateway resource
|
||||
- **How to find:** `kubectl get gateway -A`
|
||||
|
||||
### Gateway Namespace
|
||||
- **Variable:** `parentRefs[0].namespace`
|
||||
- **File:** `k8s/httproute.yaml`
|
||||
- **Line:** ~9
|
||||
- **Type:** String
|
||||
- **Description:** Namespace where Gateway is deployed
|
||||
- **How to find:** `kubectl get gateway -A`
|
||||
|
||||
### Domain Hostname
|
||||
- **Variable:** `hostnames[0]`
|
||||
- **File:** `k8s/httproute.yaml`
|
||||
- **Line:** ~11
|
||||
- **Type:** String (FQDN)
|
||||
- **Description:** Domain name for accessing the container
|
||||
- **Example:** `devcontainer.example.com`
|
||||
|
||||
## Optional Variables
|
||||
|
||||
### GitHub Token
|
||||
- **Variable:** `github-token`
|
||||
- **File:** Sealed Secret
|
||||
- **Type:** String (GitHub PAT)
|
||||
- **Description:** Personal Access Token for private repos
|
||||
- **Required:** Only for private repositories
|
||||
- **Format:** `ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
|
||||
- **Scopes:** `repo`
|
||||
|
||||
### VNC Password
|
||||
- **Variable:** `vnc-password`
|
||||
- **File:** Sealed Secret
|
||||
- **Type:** String
|
||||
- **Description:** Password for VNC web interface
|
||||
- **Required:** Recommended for security
|
||||
- **Format:** Any string (12+ characters recommended)
|
||||
|
||||
### Namespace
|
||||
- **Variable:** `namespace`
|
||||
- **File:** `k8s/kustomization.yaml`
|
||||
- **Line:** ~5
|
||||
- **Type:** String
|
||||
- **Description:** Kubernetes namespace for deployment
|
||||
- **Default:** `default`
|
||||
|
||||
### Container Image
|
||||
- **Variable:** `image`
|
||||
- **File:** `k8s/statefulset.yaml`
|
||||
- **Line:** ~32
|
||||
- **Type:** String (image reference)
|
||||
- **Description:** Docker image to deploy
|
||||
- **Default:** `ghcr.io/cpfarhood/devcontainer:latest`
|
||||
- **Format:** `registry/repository:tag`
|
||||
|
||||
### Memory Request
|
||||
- **Variable:** `resources.requests.memory`
|
||||
- **File:** `k8s/statefulset.yaml`
|
||||
- **Line:** ~99
|
||||
- **Type:** String (quantity)
|
||||
- **Description:** Minimum memory to reserve
|
||||
- **Default:** `2Gi`
|
||||
- **Format:** `<number>Gi` or `<number>Mi`
|
||||
|
||||
### Memory Limit
|
||||
- **Variable:** `resources.limits.memory`
|
||||
- **File:** `k8s/statefulset.yaml`
|
||||
- **Line:** ~102
|
||||
- **Type:** String (quantity)
|
||||
- **Description:** Maximum memory allowed
|
||||
- **Default:** `8Gi`
|
||||
- **Format:** `<number>Gi` or `<number>Mi`
|
||||
|
||||
### CPU Request
|
||||
- **Variable:** `resources.requests.cpu`
|
||||
- **File:** `k8s/statefulset.yaml`
|
||||
- **Line:** ~100
|
||||
- **Type:** String (quantity)
|
||||
- **Description:** Minimum CPU to reserve
|
||||
- **Default:** `1000m` (1 core)
|
||||
- **Format:** `<number>m` (millicores) or `<number>` (cores)
|
||||
|
||||
### CPU Limit
|
||||
- **Variable:** `resources.limits.cpu`
|
||||
- **File:** `k8s/statefulset.yaml`
|
||||
- **Line:** ~103
|
||||
- **Type:** String (quantity)
|
||||
- **Description:** Maximum CPU allowed
|
||||
- **Default:** `4000m` (4 cores)
|
||||
- **Format:** `<number>m` (millicores) or `<number>` (cores)
|
||||
|
||||
### Storage Size
|
||||
- **Variable:** `storage` (under volumeClaimTemplates)
|
||||
- **File:** `k8s/statefulset.yaml`
|
||||
- **Line:** ~120
|
||||
- **Type:** String (quantity)
|
||||
- **Description:** Size of home directory PVC
|
||||
- **Default:** `10Gi`
|
||||
- **Format:** `<number>Gi` or `<number>Ti`
|
||||
|
||||
### Happy Server URL
|
||||
- **Variable:** `happy-server-url`
|
||||
- **File:** `k8s/configmap.yaml`
|
||||
- **Line:** ~12 (commented)
|
||||
- **Type:** String (URL)
|
||||
- **Description:** Custom Happy Coder server
|
||||
- **Default:** `https://api.cluster-fluster.com`
|
||||
- **When to set:** Self-hosted Happy instance only
|
||||
|
||||
### Happy Webapp URL
|
||||
- **Variable:** `happy-webapp-url`
|
||||
- **File:** `k8s/configmap.yaml`
|
||||
- **Line:** ~13 (commented)
|
||||
- **Type:** String (URL)
|
||||
- **Description:** Custom Happy Coder webapp
|
||||
- **Default:** `https://app.happy.engineering`
|
||||
- **When to set:** Self-hosted Happy instance only
|
||||
|
||||
### Display Width
|
||||
- **Variable:** `DISPLAY_WIDTH`
|
||||
- **File:** `k8s/statefulset.yaml`
|
||||
- **Line:** ~56
|
||||
- **Type:** String (number)
|
||||
- **Description:** VNC display width in pixels
|
||||
- **Default:** `1920`
|
||||
|
||||
### Display Height
|
||||
- **Variable:** `DISPLAY_HEIGHT`
|
||||
- **File:** `k8s/statefulset.yaml`
|
||||
- **Line:** ~58
|
||||
- **Type:** String (number)
|
||||
- **Description:** VNC display height in pixels
|
||||
- **Default:** `1080`
|
||||
|
||||
### User ID
|
||||
- **Variable:** `USER_ID`
|
||||
- **File:** `k8s/statefulset.yaml`
|
||||
- **Line:** ~51
|
||||
- **Type:** String (number)
|
||||
- **Description:** UID for claude user
|
||||
- **Default:** `1000`
|
||||
|
||||
### Group ID
|
||||
- **Variable:** `GROUP_ID`
|
||||
- **File:** `k8s/statefulset.yaml`
|
||||
- **Line:** ~53
|
||||
- **Type:** String (number)
|
||||
- **Description:** GID for claude user
|
||||
- **Default:** `1000`
|
||||
|
||||
### StatefulSet Replicas
|
||||
- **Variable:** `replicas`
|
||||
- **File:** `k8s/statefulset.yaml`
|
||||
- **Line:** ~21
|
||||
- **Type:** Integer
|
||||
- **Description:** Number of container instances
|
||||
- **Default:** `1`
|
||||
- **Note:** Each replica gets own home PVC
|
||||
|
||||
## Environment Variables (Runtime)
|
||||
|
||||
These are set at runtime, not in configuration files:
|
||||
|
||||
### GITHUB_REPO
|
||||
- **Type:** String (URL)
|
||||
- **Description:** Repository URL (from ConfigMap)
|
||||
- **Default:** `""`
|
||||
- **Required:** Yes
|
||||
- **Source:** ConfigMap `antigravity.github-repo`
|
||||
- **Description:** Instance name used to generate resource names (`devcontainer-{name}`, `userhome-{name}`)
|
||||
- **Example:** `mydev`, `alice-dev`, `team-workspace`
|
||||
|
||||
### GITHUB_TOKEN
|
||||
### githubRepo
|
||||
- **Type:** String
|
||||
- **Description:** GitHub PAT (from Secret)
|
||||
- **Required:** No (only for private repos)
|
||||
- **Source:** Secret `antigravity.github-token`
|
||||
- **Default:** `""`
|
||||
- **Required:** Yes
|
||||
- **Description:** GitHub repository URL to clone into `/workspace`
|
||||
- **Example:** `https://github.com/username/repository`
|
||||
|
||||
### VNC_PASSWORD
|
||||
### ide
|
||||
- **Type:** String
|
||||
- **Description:** VNC password (from Secret)
|
||||
- **Required:** No
|
||||
- **Source:** Secret `antigravity.vnc-password`
|
||||
- **Default:** `vscode`
|
||||
- **Options:** `vscode`, `antigravity`, `none`
|
||||
- **Description:** IDE to launch inside the container
|
||||
- `vscode` — VSCode via VNC browser UI on port 5800
|
||||
- `antigravity` — Google Antigravity (VSCode fork) via VNC on port 5800
|
||||
- `none` — No IDE; useful when `ssh: true` is the sole access method
|
||||
|
||||
### HAPPY_SERVER_URL
|
||||
- **Type:** String (URL)
|
||||
- **Description:** Happy server URL (from ConfigMap)
|
||||
- **Required:** No
|
||||
- **Source:** ConfigMap `antigravity.happy-server-url`
|
||||
### ssh
|
||||
- **Type:** Boolean
|
||||
- **Default:** `false`
|
||||
- **Description:** Start an OpenSSH server on port 22 in addition to the IDE
|
||||
- **Note:** Requires `SSH_AUTHORIZED_KEYS` in env secret for key-based login
|
||||
|
||||
### HAPPY_WEBAPP_URL
|
||||
- **Type:** String (URL)
|
||||
- **Description:** Happy webapp URL (from ConfigMap)
|
||||
- **Required:** No
|
||||
- **Source:** ConfigMap `antigravity.happy-webapp-url`
|
||||
## Image Configuration
|
||||
|
||||
### HAPPY_HOME_DIR
|
||||
- **Type:** String (path)
|
||||
- **Description:** Happy data directory
|
||||
- **Required:** No
|
||||
- **Default:** `/home/claude/.happy`
|
||||
- **Source:** Hardcoded in StatefulSet
|
||||
### image.repository
|
||||
- **Type:** String
|
||||
- **Default:** `ghcr.io/cpfarhood/devcontainer`
|
||||
- **Description:** Container image repository
|
||||
|
||||
### HAPPY_EXPERIMENTAL
|
||||
- **Type:** String (boolean)
|
||||
- **Description:** Enable Happy experimental features
|
||||
- **Required:** No
|
||||
### image.tag
|
||||
- **Type:** String
|
||||
- **Default:** `latest`
|
||||
- **Description:** Container image tag
|
||||
- **Best Practice:** Use specific version tags for production
|
||||
|
||||
### image.pullPolicy
|
||||
- **Type:** String
|
||||
- **Default:** `Always`
|
||||
- **Options:** `Always`, `IfNotPresent`, `Never`
|
||||
- **Description:** Image pull policy
|
||||
|
||||
## Happy Coder Configuration
|
||||
|
||||
### happyServerUrl
|
||||
- **Type:** String
|
||||
- **Default:** `https://happy.farh.net`
|
||||
- **Description:** Happy Coder server endpoint
|
||||
- **When to Change:** Self-hosted Happy instance
|
||||
|
||||
### happyWebappUrl
|
||||
- **Type:** String
|
||||
- **Default:** `https://happy-coder.farh.net`
|
||||
- **Description:** Happy Coder webapp URL
|
||||
- **When to Change:** Self-hosted Happy instance
|
||||
|
||||
### happyHomeDir
|
||||
- **Type:** String
|
||||
- **Default:** `/config/userdata/.happy`
|
||||
- **Description:** Happy runtime state directory (persists on PVC)
|
||||
|
||||
### happyExperimental
|
||||
- **Type:** String
|
||||
- **Default:** `"true"`
|
||||
- **Description:** Enable experimental Happy features
|
||||
|
||||
## Display Configuration
|
||||
|
||||
### display.width
|
||||
- **Type:** String
|
||||
- **Default:** `"1920"`
|
||||
- **Description:** VNC display width in pixels
|
||||
|
||||
### display.height
|
||||
- **Type:** String
|
||||
- **Default:** `"1080"`
|
||||
- **Description:** VNC display height in pixels
|
||||
|
||||
### secureConnection
|
||||
- **Type:** String
|
||||
- **Default:** `"0"`
|
||||
- **Options:** `"0"`, `"1"`
|
||||
- **Description:** Set to `"0"` when TLS is terminated at the gateway layer
|
||||
|
||||
## User Configuration
|
||||
|
||||
### userId
|
||||
- **Type:** String
|
||||
- **Default:** `"1000"`
|
||||
- **Description:** UID for the app user
|
||||
|
||||
### groupId
|
||||
- **Type:** String
|
||||
- **Default:** `"1000"`
|
||||
- **Description:** GID for the app user
|
||||
|
||||
## Storage Configuration
|
||||
|
||||
### storage.size
|
||||
- **Type:** String
|
||||
- **Default:** `32Gi`
|
||||
- **Description:** Size of the persistent home directory
|
||||
- **Format:** Kubernetes quantity (e.g., `10Gi`, `100Gi`, `1Ti`)
|
||||
|
||||
### storage.className
|
||||
- **Type:** String
|
||||
- **Default:** `ceph-filesystem`
|
||||
- **Description:** StorageClass name (must support ReadWriteMany)
|
||||
- **Examples:** `ceph-filesystem`, `nfs-client`, `efs-sc`, `azurefile`
|
||||
|
||||
### shm.sizeLimit
|
||||
- **Type:** String
|
||||
- **Default:** `2Gi`
|
||||
- **Description:** `/dev/shm` size (memory-backed emptyDir for Electron apps)
|
||||
|
||||
## Resource Limits
|
||||
|
||||
### resources.requests.memory
|
||||
- **Type:** String
|
||||
- **Default:** `2Gi`
|
||||
- **Description:** Minimum memory to reserve
|
||||
- **Format:** Kubernetes quantity
|
||||
|
||||
### resources.requests.cpu
|
||||
- **Type:** String
|
||||
- **Default:** `1000m`
|
||||
- **Description:** Minimum CPU to reserve
|
||||
- **Format:** Millicores (`1000m` = 1 CPU core)
|
||||
|
||||
### resources.limits.memory
|
||||
- **Type:** String
|
||||
- **Default:** `8Gi`
|
||||
- **Description:** Maximum memory allowed
|
||||
- **Format:** Kubernetes quantity
|
||||
|
||||
### resources.limits.cpu
|
||||
- **Type:** String
|
||||
- **Default:** `4000m`
|
||||
- **Description:** Maximum CPU allowed
|
||||
- **Format:** Millicores (`4000m` = 4 CPU cores)
|
||||
|
||||
## Kubernetes Access
|
||||
|
||||
### clusterAccess
|
||||
- **Type:** String
|
||||
- **Default:** `none`
|
||||
- **Options:**
|
||||
- `none` — No cluster access
|
||||
- `readonlyns` — Read-only access to release namespace
|
||||
- `readwritens` — Full access to release namespace
|
||||
- `readonly` — Read-only access cluster-wide
|
||||
- `readwrite` — Full access cluster-wide
|
||||
- **Description:** RBAC permissions for the pod's ServiceAccount
|
||||
|
||||
## Secrets
|
||||
|
||||
### envSecretName
|
||||
- **Type:** String
|
||||
- **Default:** `""` (auto-generates as `devcontainer-{name}-secrets-env`)
|
||||
- **Description:** Name of existing Secret containing environment variables
|
||||
- **Keys Recognized:**
|
||||
- `GITHUB_TOKEN` — PAT for private repo access
|
||||
- `VNC_PASSWORD` — Password for VNC web UI
|
||||
- `ANTHROPIC_API_KEY` — API key for Claude
|
||||
- `SSH_AUTHORIZED_KEYS` — Public keys for SSH access
|
||||
|
||||
## MCP Sidecars
|
||||
|
||||
### mcpSidecars.kubernetes.enabled
|
||||
- **Type:** Boolean
|
||||
- **Default:** `true`
|
||||
- **Source:** Hardcoded in StatefulSet
|
||||
- **Description:** Enable Kubernetes MCP server sidecar
|
||||
|
||||
## Variable Groups by Use Case
|
||||
### mcpSidecars.kubernetes.image.repository
|
||||
- **Type:** String
|
||||
- **Default:** `quay.io/containers/kubernetes_mcp_server`
|
||||
- **Description:** Kubernetes MCP server image
|
||||
|
||||
### Minimal Deployment
|
||||
Only these variables are required for basic deployment:
|
||||
1. `storageClassName`
|
||||
2. `github-repo`
|
||||
3. `parentRefs.name`
|
||||
4. `parentRefs.namespace`
|
||||
5. `hostnames`
|
||||
### mcpSidecars.kubernetes.image.tag
|
||||
- **Type:** String
|
||||
- **Default:** `latest`
|
||||
- **Description:** Kubernetes MCP server image tag
|
||||
|
||||
### Private Repository Deployment
|
||||
Add these for private repos:
|
||||
1. All minimal deployment variables
|
||||
2. `github-token` (sealed secret)
|
||||
### mcpSidecars.kubernetes.port
|
||||
- **Type:** Integer
|
||||
- **Default:** `8080`
|
||||
- **Description:** Port for Kubernetes MCP server
|
||||
|
||||
### Production Deployment
|
||||
Recommended for production:
|
||||
1. All private repository variables
|
||||
2. `vnc-password` (sealed secret)
|
||||
3. `resources.requests.*` (adjusted for workload)
|
||||
4. `resources.limits.*` (adjusted for workload)
|
||||
5. `namespace` (dedicated namespace)
|
||||
### mcpSidecars.kubernetes.resources
|
||||
- **Type:** Object
|
||||
- **Default:**
|
||||
```yaml
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
```
|
||||
- **Description:** Resource limits for Kubernetes MCP sidecar
|
||||
|
||||
### Multi-User Deployment
|
||||
For multiple users:
|
||||
1. All production deployment variables
|
||||
2. `replicas` (set to number of users)
|
||||
3. Larger `storage` size for home PVCs
|
||||
### mcpSidecars.flux.enabled
|
||||
- **Type:** Boolean
|
||||
- **Default:** `true`
|
||||
- **Description:** Enable Flux MCP server sidecar
|
||||
|
||||
## Quick Copy Templates
|
||||
### mcpSidecars.flux.image.repository
|
||||
- **Type:** String
|
||||
- **Default:** `ghcr.io/controlplaneio-fluxcd/flux-operator-mcp`
|
||||
- **Description:** Flux MCP server image
|
||||
|
||||
### mcpSidecars.flux.image.tag
|
||||
- **Type:** String
|
||||
- **Default:** `v0.41.1`
|
||||
- **Description:** Flux MCP server image tag
|
||||
|
||||
### mcpSidecars.flux.port
|
||||
- **Type:** Integer
|
||||
- **Default:** `8081`
|
||||
- **Description:** Port for Flux MCP server
|
||||
|
||||
### mcpSidecars.flux.resources
|
||||
- **Type:** Object
|
||||
- **Default:**
|
||||
```yaml
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
```
|
||||
- **Description:** Resource limits for Flux MCP sidecar
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Minimal Configuration
|
||||
|
||||
### Minimal Required Variables
|
||||
```yaml
|
||||
# k8s/statefulset.yaml
|
||||
storageClassName: "CHANGE_ME" # Line ~117
|
||||
|
||||
# k8s/configmap.yaml
|
||||
github-repo: "CHANGE_ME" # Line ~9
|
||||
|
||||
# k8s/httproute.yaml
|
||||
parentRefs:
|
||||
- name: CHANGE_ME # Line ~8
|
||||
namespace: CHANGE_ME # Line ~9
|
||||
hostnames:
|
||||
- "CHANGE_ME" # Line ~11
|
||||
name: mydev
|
||||
githubRepo: https://github.com/user/repo
|
||||
```
|
||||
|
||||
### With Secrets
|
||||
```bash
|
||||
kubectl create secret generic antigravity-secrets \
|
||||
--from-literal=github-token='CHANGE_ME' \
|
||||
--from-literal=vnc-password='CHANGE_ME' \
|
||||
--dry-run=client -o yaml | \
|
||||
kubeseal --format=yaml > k8s/sealedsecrets.yaml
|
||||
```
|
||||
### Production Configuration
|
||||
|
||||
### With Resource Adjustments
|
||||
```yaml
|
||||
# k8s/statefulset.yaml (lines ~98-103)
|
||||
name: prod-workspace
|
||||
githubRepo: https://github.com/company/application
|
||||
ide: vscode
|
||||
ssh: true
|
||||
|
||||
image:
|
||||
tag: v1.0.0
|
||||
|
||||
storage:
|
||||
size: 100Gi
|
||||
className: ceph-filesystem
|
||||
|
||||
resources:
|
||||
requests:
|
||||
memory: "CHANGE_ME" # e.g., 4Gi
|
||||
cpu: "CHANGE_ME" # e.g., 2000m
|
||||
memory: "4Gi"
|
||||
cpu: "2000m"
|
||||
limits:
|
||||
memory: "CHANGE_ME" # e.g., 16Gi
|
||||
cpu: "CHANGE_ME" # e.g., 8000m
|
||||
memory: "16Gi"
|
||||
cpu: "8000m"
|
||||
|
||||
clusterAccess: readwritens
|
||||
|
||||
mcpSidecars:
|
||||
kubernetes:
|
||||
enabled: true
|
||||
flux:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
### Development Team Configuration
|
||||
|
||||
```yaml
|
||||
name: team-dev
|
||||
githubRepo: https://github.com/team/project
|
||||
ide: antigravity
|
||||
|
||||
display:
|
||||
width: "2560"
|
||||
height: "1440"
|
||||
|
||||
storage:
|
||||
size: 50Gi
|
||||
className: nfs-client
|
||||
|
||||
clusterAccess: readonly
|
||||
|
||||
happyServerUrl: https://happy.internal.company.com
|
||||
happyWebappUrl: https://happy-app.internal.company.com
|
||||
```
|
||||
|
||||
## Helm CLI Examples
|
||||
|
||||
### Using --set Flags
|
||||
|
||||
```bash
|
||||
# Basic deployment
|
||||
helm install mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/user/repo
|
||||
|
||||
# With multiple values
|
||||
helm install mydev ./chart \
|
||||
--set name=mydev \
|
||||
--set githubRepo=https://github.com/user/repo \
|
||||
--set ide=antigravity \
|
||||
--set storage.size=50Gi \
|
||||
--set clusterAccess=readwritens \
|
||||
--set mcpSidecars.flux.enabled=false
|
||||
```
|
||||
|
||||
### Using Values File
|
||||
|
||||
Create `custom-values.yaml`:
|
||||
```yaml
|
||||
name: mydev
|
||||
githubRepo: https://github.com/user/repo
|
||||
storage:
|
||||
size: 50Gi
|
||||
clusterAccess: readwritens
|
||||
```
|
||||
|
||||
Deploy:
|
||||
```bash
|
||||
helm install mydev ./chart -f custom-values.yaml
|
||||
```
|
||||
|
||||
### Combining Methods
|
||||
|
||||
```bash
|
||||
helm install mydev ./chart \
|
||||
-f base-values.yaml \
|
||||
-f prod-values.yaml \
|
||||
--set githubRepo=https://github.com/user/repo \
|
||||
--set image.tag=v2.0.0
|
||||
```
|
||||
|
||||
## Value Precedence
|
||||
|
||||
Values are applied in order of precedence (highest to lowest):
|
||||
1. `--set` flags on command line
|
||||
2. `-f` values files (later files override earlier)
|
||||
3. `chart/values.yaml` defaults
|
||||
|
||||
## Environment Variables
|
||||
|
||||
These environment variables are set in the container based on chart values:
|
||||
|
||||
| Environment Variable | Source Value | Description |
|
||||
|---------------------|--------------|-------------|
|
||||
| `GITHUB_REPO` | `githubRepo` | Repository to clone |
|
||||
| `GITHUB_TOKEN` | Secret: `github-token` | PAT for private repos |
|
||||
| `VNC_PASSWORD` | Secret: `vnc-password` | VNC access password |
|
||||
| `ANTHROPIC_API_KEY` | Secret: `anthropic-api-key` | Claude API key |
|
||||
| `SSH_AUTHORIZED_KEYS` | Secret: `ssh-authorized-keys` | SSH public keys |
|
||||
| `HAPPY_SERVER_URL` | `happyServerUrl` | Happy server endpoint |
|
||||
| `HAPPY_WEBAPP_URL` | `happyWebappUrl` | Happy webapp URL |
|
||||
| `HAPPY_HOME_DIR` | `happyHomeDir` | Happy data directory |
|
||||
| `HAPPY_EXPERIMENTAL` | `happyExperimental` | Experimental features |
|
||||
| `DISPLAY_WIDTH` | `display.width` | VNC width |
|
||||
| `DISPLAY_HEIGHT` | `display.height` | VNC height |
|
||||
| `SECURE_CONNECTION` | `secureConnection` | TLS termination |
|
||||
| `USER_ID` | `userId` | App user UID |
|
||||
| `GROUP_ID` | `groupId` | App user GID |
|
||||
| `IDE` | `ide` | IDE to launch |
|
||||
| `SSH` | `ssh` | SSH server enabled |
|
||||
Reference in New Issue
Block a user