f79be89e4e
Add detailed documentation to enable autonomous deployment by other AI agents. New files: - DEPLOYMENT.md: Complete step-by-step deployment guide - Prerequisites checklist - Required vs optional variables clearly marked - All configuration variables documented with examples - Troubleshooting section - Quick deploy example with all values - Configuration summary table - VARIABLES.md: Complete variables reference - All variables listed with file, line, type, description - Required variables clearly marked - Optional variables with defaults - Variables grouped by use case - Quick copy templates - Environment variables reference Updated README.md: - Add links to new documentation files - Clear pointer to DEPLOYMENT.md for deployment These docs enable another Claude Code instance to: 1. Identify all required configuration variables 2. Know where to find/set each variable 3. Understand what values are valid 4. Deploy successfully without human intervention 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>
437 lines
11 KiB
Markdown
437 lines
11 KiB
Markdown
# Deployment Guide
|
|
|
|
This guide provides step-by-step instructions for deploying the Antigravity Dev Container to Kubernetes.
|
|
|
|
## Prerequisites
|
|
|
|
- Kubernetes cluster with Gateway API support
|
|
- `kubectl` configured to access your cluster
|
|
- 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
|
|
|
|
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
|
|
|
|
```bash
|
|
git clone https://github.com/cpfarhood/devcontainer.git
|
|
cd devcontainer
|
|
```
|
|
|
|
### Step 2: Configure Storage Class
|
|
|
|
Edit `k8s/statefulset.yaml` and find the `volumeClaimTemplates` section (around line 117):
|
|
|
|
```bash
|
|
# Find your storage class
|
|
kubectl get storageclass
|
|
|
|
# Edit the file
|
|
vi k8s/statefulset.yaml
|
|
```
|
|
|
|
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`:
|
|
|
|
```bash
|
|
vi k8s/configmap.yaml
|
|
```
|
|
|
|
Set your repository URL:
|
|
```yaml
|
|
data:
|
|
github-repo: "https://github.com/yourusername/yourrepo"
|
|
```
|
|
|
|
### Step 4: Configure Gateway (HTTPRoute)
|
|
|
|
Edit `k8s/httproute.yaml`:
|
|
|
|
```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
|
|
open http://localhost:5800
|
|
```
|
|
|
|
## Configuration Summary
|
|
|
|
Here's a quick checklist of all variables you need to set:
|
|
|
|
### Required Variables
|
|
|
|
| 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` |
|
|
|
|
### Optional Variables
|
|
|
|
| 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 |
|
|
|
|
## Troubleshooting
|
|
|
|
### Pod not starting
|
|
|
|
**Check events:**
|
|
```bash
|
|
kubectl describe pod antigravity-0
|
|
```
|
|
|
|
**Common issues:**
|
|
- Storage class doesn't support ReadWriteMany
|
|
- PVC not binding (check storage class exists)
|
|
- Image pull errors (check image name)
|
|
|
|
### Repository not cloning
|
|
|
|
**Check logs:**
|
|
```bash
|
|
kubectl logs antigravity-0 | grep -A 10 "Repository Initialization"
|
|
```
|
|
|
|
**Common issues:**
|
|
- Invalid GitHub URL
|
|
- Private repo without token
|
|
- Token doesn't have correct permissions
|
|
|
|
### HTTPRoute not working
|
|
|
|
**Check HTTPRoute:**
|
|
```bash
|
|
kubectl describe httproute antigravity
|
|
```
|
|
|
|
**Common issues:**
|
|
- Gateway name/namespace incorrect
|
|
- Domain not pointing to Gateway
|
|
- TLS certificate not issued
|
|
|
|
### VNC not accessible
|
|
|
|
**Check service:**
|
|
```bash
|
|
kubectl get svc antigravity
|
|
kubectl describe svc antigravity
|
|
```
|
|
|
|
**Port forward test:**
|
|
```bash
|
|
kubectl port-forward antigravity-0 5800:5800
|
|
# Try accessing http://localhost:5800
|
|
```
|
|
|
|
## Quick Deploy Example
|
|
|
|
Complete deployment with all values filled in:
|
|
|
|
```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"
|
|
|
|
# 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
|
|
```
|
|
|
|
## Updates and Maintenance
|
|
|
|
### 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
|
|
|
|
```bash
|
|
# Scale to multiple instances (each gets own home PVC)
|
|
kubectl scale statefulset antigravity --replicas=3
|
|
```
|
|
|
|
## Support
|
|
|
|
For issues or questions:
|
|
- GitHub Issues: https://github.com/cpfarhood/devcontainer/issues
|
|
- Documentation: https://github.com/cpfarhood/devcontainer
|