From 3794ec60d764fab8d542a01461c3fe282072037e Mon Sep 17 00:00:00 2001 From: Chris Farhood Date: Thu, 19 Feb 2026 17:39:59 -0500 Subject: [PATCH] Fix startup scripts and k8s config for initial deployment - Fix chown/sudo to use numeric UID/GID instead of hardcoded 'claude' username (baseimage-gui creates users dynamically, name not available at script runtime) - Fix image name: ghcr.io/cpfarhood/devcontainer (matches github.repository) - Fix ConfigMap name: antigravity-config -> antigravity (matches statefulset refs) - Set github-repo in ConfigMap to headlamp-polaris-plugin - Set HTTPRoute to external gateway at antigravity.dev.farh.net - Add CLAUDE.md for Claude Code guidance Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Co-Authored-By: Happy --- CLAUDE.md | 107 +++++++++++++++++++++++++++++++++++++++++++ k8s/configmap.yaml | 4 +- k8s/httproute.yaml | 6 +-- k8s/statefulset.yaml | 2 +- scripts/init-repo.sh | 24 +++++----- scripts/startapp.sh | 3 +- 6 files changed, 128 insertions(+), 18 deletions(-) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..989efbf --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,107 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Antigravity is a Docker-based cloud development environment that provides: +- Web-based GUI IDE (VSCode/Antigravity) via VNC on port 5800 +- Happy Coder AI assistant integration +- Automatic GitHub repository cloning on startup +- Kubernetes-native deployment with persistent home storage + +The stack is primarily **Bash scripts + YAML** — there is no Node.js package, compiled language, or test framework. + +## Common Commands + +### Building + +```bash +make build # Build Docker image +make build REGISTRY=ghcr.io/myuser IMAGE_TAG=v1.0 # Custom registry/tag +docker build -t ghcr.io/cpfarhood/antigravity:latest . # Direct build +``` + +### Running Locally + +```bash +GITHUB_REPO="https://github.com/user/repo" make run # Run with Docker +make stop # Stop container +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 +``` + +### Other Useful Targets + +```bash +make help # List all Makefile targets with descriptions +make push # Push image to registry (build first) +``` + +## Architecture + +### Startup Flow + +``` +Container start + → scripts/startapp.sh + → scripts/init-repo.sh (clone GITHUB_REPO, start Happy Coder) + → launch VSCode as user `claude` in /workspace +``` + +### Key Files + +| File | Purpose | +|------|---------| +| `Dockerfile` | Image definition — installs Chrome, Node.js, VSCode, Happy Coder; creates non-root user `claude` (UID 1000) | +| `scripts/init-repo.sh` | Clones GitHub repo, authenticates with token, starts Happy Coder background service | +| `scripts/startapp.sh` | Calls init-repo.sh then opens VSCode in the workspace | +| `k8s/statefulset.yaml` | StatefulSet + headless Service; mounts `/home` (PVC) and `/workspace` (emptyDir) | +| `k8s/configmap.yaml` | `GITHUB_REPO`, `HAPPY_SERVER_URL`, `HAPPY_WEBAPP_URL` | +| `k8s/httproute.yaml` | Gateway API HTTPRoute for external browser access | +| `k8s/secrets-example.yaml` | Template for SealedSecrets (GitHub token, VNC password) | +| `Makefile` | Build/deploy automation | + +### Storage Model + +- `/home` — ReadWriteMany PVC (persists across pod restarts, holds user config/dotfiles) +- `/workspace` — emptyDir by default (ephemeral; can be changed to PVC) + +### Environment Variables + +**Required:** +- `GITHUB_REPO` — URL of repository to clone into `/workspace` + +**Optional:** +- `GITHUB_TOKEN` — PAT for private repo access +- `VNC_PASSWORD` — VNC web interface password +- `DISPLAY_WIDTH` / `DISPLAY_HEIGHT` — VNC resolution +- `USER_ID` / `GROUP_ID` — Override UID/GID (default 1000) +- `HAPPY_SERVER_URL` / `HAPPY_WEBAPP_URL` — Custom Happy Coder endpoints +- `HAPPY_HOME_DIR` / `HAPPY_EXPERIMENTAL` + +### CI/CD + +- **`build-and-push.yaml`** — Builds and pushes to GHCR on every push to `main`, version tags (`v*`), and PRs. Tags: `latest` (main), semver, branch name, commit SHA. +- **`release.yaml`** — Creates a GitHub Release with docker pull instructions when a version tag is pushed. +- **`dependabot.yml`** — Weekly updates for GitHub Actions and Docker base image. + +Image registry: `ghcr.io/cpfarhood/devcontainer` + +## Kubernetes Notes + +- Uses Kustomize (`kubectl apply -k k8s/`) +- Storage class is `ceph-filesystem` by default — change in `statefulset.yaml` for other clusters +- Resource limits: 1–4 CPU, 2–8Gi memory +- Health checks (liveness/readiness probes) on port 5800 +- Secrets managed via SealedSecrets (see `k8s/secrets-example.yaml`) diff --git a/k8s/configmap.yaml b/k8s/configmap.yaml index d24b119..ae929cd 100644 --- a/k8s/configmap.yaml +++ b/k8s/configmap.yaml @@ -2,11 +2,11 @@ apiVersion: v1 kind: ConfigMap metadata: - name: antigravity-config + name: antigravity data: # GitHub repository to clone on startup # Example: "https://github.com/username/repository" - github-repo: "" + github-repo: "https://github.com/privilegedescalation/headlamp-polaris-plugin" # Happy Coder configuration (optional) # happy-server-url: "https://api.cluster-fluster.com" diff --git a/k8s/httproute.yaml b/k8s/httproute.yaml index e824e15..50e88bf 100644 --- a/k8s/httproute.yaml +++ b/k8s/httproute.yaml @@ -5,10 +5,10 @@ metadata: name: antigravity spec: parentRefs: - - name: gateway # Replace with your Gateway name - namespace: gateway-system # Replace with your Gateway namespace + - name: external + namespace: gateway-system hostnames: - - "antigravity.example.com" # Replace with your domain + - "antigravity.dev.farh.net" rules: - matches: - path: diff --git a/k8s/statefulset.yaml b/k8s/statefulset.yaml index 1499b71..00b5dbe 100644 --- a/k8s/statefulset.yaml +++ b/k8s/statefulset.yaml @@ -34,7 +34,7 @@ spec: fsGroupChangePolicy: "OnRootMismatch" containers: - name: antigravity - image: ghcr.io/cpfarhood/antigravity:latest + image: ghcr.io/cpfarhood/devcontainer:latest imagePullPolicy: IfNotPresent ports: - containerPort: 5800 diff --git a/scripts/init-repo.sh b/scripts/init-repo.sh index 75aba70..d095ad8 100644 --- a/scripts/init-repo.sh +++ b/scripts/init-repo.sh @@ -25,8 +25,8 @@ else # Configure git to use token if provided if [ -n "$GITHUB_TOKEN" ]; then git config credential.helper store - echo "https://oauth2:${GITHUB_TOKEN}@github.com" > /home/claude/.git-credentials - chmod 600 /home/claude/.git-credentials + echo "https://oauth2:${GITHUB_TOKEN}@github.com" > /home/.git-credentials + chmod 600 /home/.git-credentials fi git pull || echo "Pull failed, continuing anyway..." @@ -42,29 +42,31 @@ else # Configure credentials for future use git config --global credential.helper store - echo "https://oauth2:${GITHUB_TOKEN}@github.com" > /home/claude/.git-credentials - chmod 600 /home/claude/.git-credentials + echo "https://oauth2:${GITHUB_TOKEN}@github.com" > /home/.git-credentials + chmod 600 /home/.git-credentials else git clone "$GITHUB_REPO" "$WORKSPACE_DIR" fi fi fi -# Set ownership -chown -R claude:claude "$WORKSPACE_DIR" -chown -R claude:claude /home/claude +# Set ownership using numeric IDs (username may not exist yet in baseimage-gui) +RUN_UID="${USER_ID:-1000}" +RUN_GID="${GROUP_ID:-1000}" +chown -R "$RUN_UID:$RUN_GID" "$WORKSPACE_DIR" +chown -R "$RUN_UID:$RUN_GID" /home -# Start Happy Coder in background as claude user +# Start Happy Coder in background as the app user echo "Starting Happy Coder..." cd "$WORKSPACE_DIR" # Create Happy Coder log file HAPPY_LOG="/tmp/happy-coder.log" touch "$HAPPY_LOG" -chown claude:claude "$HAPPY_LOG" +chown "$RUN_UID:$RUN_GID" "$HAPPY_LOG" -# Start Happy Coder as claude user -sudo -u claude bash -c "cd '$WORKSPACE_DIR' && happy-coder > '$HAPPY_LOG' 2>&1 &" +# Start Happy Coder as the app user (use numeric UID for compatibility with baseimage-gui) +sudo -u "#$RUN_UID" bash -c "cd '$WORKSPACE_DIR' && happy-coder > '$HAPPY_LOG' 2>&1 &" # Save PID for monitoring echo $! > /tmp/happy-coder.pid diff --git a/scripts/startapp.sh b/scripts/startapp.sh index bf62c2b..ffb9dbe 100644 --- a/scripts/startapp.sh +++ b/scripts/startapp.sh @@ -18,4 +18,5 @@ echo "Opening Antigravity in: $WORKSPACE_DIR" # Start Antigravity (VSCode) in the workspace directory as claude user # The baseimage-gui will handle the GUI display -exec sudo -u claude code --new-window --wait "$WORKSPACE_DIR" +RUN_UID="${USER_ID:-1000}" +exec sudo -u "#$RUN_UID" code --new-window --wait "$WORKSPACE_DIR"