Initial commit: Antigravity dev container with Happy Coder
Add containerized GUI development environment featuring: - Antigravity IDE (VSCode) accessible via web browser - Happy Coder AI assistant integration - Automatic GitHub repository cloning on startup - Persistent user home directory (ReadWriteMany PVC) - Secure non-root execution as user claude (UID 1000) Components: - Dockerfile based on jlesage/baseimage-gui - Startup scripts for repo initialization and app launch - Kubernetes manifests (StatefulSet, ConfigMap, Secrets) - Makefile for build and deployment automation - Comprehensive documentation Features: - Web-based VNC interface (port 5800) - GitHub token authentication for private repos - Happy Coder runs as background service in workspace - CephFS storage for persistent home directory - Configurable display resolution and security 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:
@@ -0,0 +1,24 @@
|
||||
.git
|
||||
.gitignore
|
||||
.dockerignore
|
||||
*.md
|
||||
README.md
|
||||
LICENSE
|
||||
Makefile
|
||||
docker-compose.yml
|
||||
|
||||
# Kubernetes files
|
||||
k8s/
|
||||
|
||||
# Local development
|
||||
home/
|
||||
workspace/
|
||||
*.log
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
# Secrets
|
||||
*.env
|
||||
.env.local
|
||||
secrets.yaml
|
||||
k8s/sealedsecrets.yaml
|
||||
|
||||
# Local volumes
|
||||
home/
|
||||
workspace/
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
|
||||
# Build artifacts
|
||||
*.tar
|
||||
*.tar.gz
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
FROM jlesage/baseimage-gui:ubuntu-22.04-v4
|
||||
|
||||
# Set environment variables
|
||||
ENV APP_NAME="Antigravity Dev Container" \
|
||||
KEEP_APP_RUNNING=1 \
|
||||
DISPLAY_WIDTH=1920 \
|
||||
DISPLAY_HEIGHT=1080 \
|
||||
SECURE_CONNECTION=1 \
|
||||
USER_ID=1000 \
|
||||
GROUP_ID=1000 \
|
||||
CLAUDE_USER=claude
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
wget \
|
||||
gnupg \
|
||||
ca-certificates \
|
||||
git \
|
||||
build-essential \
|
||||
python3 \
|
||||
python3-pip \
|
||||
jq \
|
||||
unzip \
|
||||
sudo \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Chrome
|
||||
RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/google-chrome-keyring.gpg && \
|
||||
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/google-chrome-keyring.gpg] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y google-chrome-stable && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Node.js (LTS version for Happy Coder)
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \
|
||||
apt-get install -y nodejs && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Happy Coder globally
|
||||
RUN npm install -g @happy-sdk/happy-coder
|
||||
|
||||
# Install Antigravity (Google's Project IDX / Cloud Code alternative)
|
||||
# Note: Antigravity might be packaged differently - adjust as needed
|
||||
# For now, we'll use VSCode with Project IDX extensions as a placeholder
|
||||
RUN wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor -o /usr/share/keyrings/packages.microsoft.gpg && \
|
||||
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main" > /etc/apt/sources.list.d/vscode.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y code && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create claude user with specific UID/GID
|
||||
RUN groupadd -g 1000 claude && \
|
||||
useradd -u 1000 -g 1000 -m -s /bin/bash claude && \
|
||||
echo "claude ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
|
||||
|
||||
# Create workspace directory
|
||||
RUN mkdir -p /workspace && \
|
||||
chown -R claude:claude /workspace
|
||||
|
||||
# Copy startup script
|
||||
COPY --chmod=755 scripts/startapp.sh /startapp.sh
|
||||
COPY --chmod=755 scripts/init-repo.sh /usr/local/bin/init-repo
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /workspace
|
||||
|
||||
# Configure container to run as claude user
|
||||
ENV HOME=/home/claude \
|
||||
USER=claude
|
||||
|
||||
# Expose VNC port (baseimage-gui default)
|
||||
EXPOSE 5800
|
||||
|
||||
# Set app name for baseimage-gui
|
||||
RUN set-cont-env APP_NAME "Antigravity"
|
||||
@@ -0,0 +1,102 @@
|
||||
.PHONY: build push run stop clean help
|
||||
|
||||
# Variables
|
||||
REGISTRY ?= ghcr.io/cpfarhood
|
||||
IMAGE_NAME ?= antigravity
|
||||
IMAGE_TAG ?= latest
|
||||
FULL_IMAGE = $(REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)
|
||||
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
# Build the Docker image
|
||||
build:
|
||||
@echo "Building $(FULL_IMAGE)..."
|
||||
docker build -t $(FULL_IMAGE) .
|
||||
|
||||
# Push the image to registry
|
||||
push: build
|
||||
@echo "Pushing $(FULL_IMAGE)..."
|
||||
docker push $(FULL_IMAGE)
|
||||
|
||||
# Run locally with Docker
|
||||
run:
|
||||
@echo "Running $(FULL_IMAGE) locally..."
|
||||
docker run -d \
|
||||
-p 5800:5800 \
|
||||
-e GITHUB_REPO="${GITHUB_REPO}" \
|
||||
-e GITHUB_TOKEN="${GITHUB_TOKEN}" \
|
||||
-e HAPPY_CODER_API_KEY="${HAPPY_CODER_API_KEY}" \
|
||||
-e VNC_PASSWORD="${VNC_PASSWORD}" \
|
||||
-v $(PWD)/home:/home \
|
||||
-v $(PWD)/workspace:/workspace \
|
||||
--name antigravity \
|
||||
$(FULL_IMAGE)
|
||||
@echo "Access at http://localhost:5800"
|
||||
|
||||
# Stop the running container
|
||||
stop:
|
||||
@echo "Stopping antigravity container..."
|
||||
docker stop antigravity || true
|
||||
docker rm antigravity || true
|
||||
|
||||
# Clean up local volumes
|
||||
clean: stop
|
||||
@echo "Cleaning up..."
|
||||
rm -rf ./home ./workspace
|
||||
|
||||
# Kubernetes deployment
|
||||
k8s-deploy:
|
||||
@echo "Deploying to Kubernetes..."
|
||||
kubectl apply -k k8s/
|
||||
|
||||
k8s-delete:
|
||||
@echo "Deleting from Kubernetes..."
|
||||
kubectl delete -k k8s/
|
||||
|
||||
k8s-logs:
|
||||
@echo "Showing logs..."
|
||||
kubectl logs -f antigravity-0
|
||||
|
||||
k8s-shell:
|
||||
@echo "Opening shell..."
|
||||
kubectl exec -it antigravity-0 -- bash
|
||||
|
||||
k8s-port-forward:
|
||||
@echo "Port forwarding to localhost:5800..."
|
||||
kubectl port-forward antigravity-0 5800:5800
|
||||
|
||||
# Show help
|
||||
help:
|
||||
@echo "Antigravity Dev Container Makefile"
|
||||
@echo ""
|
||||
@echo "Usage: make [target]"
|
||||
@echo ""
|
||||
@echo "Docker Targets:"
|
||||
@echo " build - Build the Docker image"
|
||||
@echo " push - Push image to registry"
|
||||
@echo " run - Run container locally (requires env vars)"
|
||||
@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 ""
|
||||
@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 ""
|
||||
@echo "Environment Variables for 'make run':"
|
||||
@echo " GITHUB_REPO - GitHub repository URL"
|
||||
@echo " GITHUB_TOKEN - GitHub token (optional)"
|
||||
@echo " HAPPY_CODER_API_KEY - Happy Coder API key"
|
||||
@echo " VNC_PASSWORD - VNC password (optional)"
|
||||
@echo ""
|
||||
@echo "Example:"
|
||||
@echo " make build"
|
||||
@echo " make push REGISTRY=ghcr.io/myuser IMAGE_TAG=v1.0"
|
||||
@echo " GITHUB_REPO=https://github.com/user/repo make run"
|
||||
@@ -0,0 +1,342 @@
|
||||
# Antigravity Dev Container
|
||||
|
||||
A containerized development environment with GUI access, featuring:
|
||||
- **Antigravity** (VSCode/Cloud IDE) via web browser
|
||||
- **Happy Coder** - AI-powered development assistant
|
||||
- **Automatic GitHub repo cloning**
|
||||
- **Persistent user home directory**
|
||||
- **Secure non-root execution**
|
||||
|
||||
## Features
|
||||
|
||||
### GUI Access
|
||||
- Web-based VNC interface (port 5800)
|
||||
- Full desktop environment in your browser
|
||||
- Secure connections with optional password protection
|
||||
|
||||
### Development Tools
|
||||
- Antigravity IDE (VSCode-based)
|
||||
- Happy Coder AI assistant
|
||||
- Git integration
|
||||
- Node.js and npm
|
||||
- Python 3
|
||||
- Chrome browser
|
||||
|
||||
### Security
|
||||
- Runs as non-root user `claude` (UID 1000, GID 1000)
|
||||
- Secure VNC connections
|
||||
- Token-based GitHub authentication
|
||||
- Isolated workspace
|
||||
|
||||
### Persistence
|
||||
- ReadWriteMany PVC for `/home` (user data persists)
|
||||
- Workspace mounted at `/workspace`
|
||||
- Repository cloned on first startup
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Build the Image
|
||||
|
||||
```bash
|
||||
docker build -t ghcr.io/cpfarhood/antigravity:latest .
|
||||
docker push ghcr.io/cpfarhood/antigravity:latest
|
||||
```
|
||||
|
||||
### 2. Configure Secrets
|
||||
|
||||
Edit `k8s/secrets-example.yaml` and create a sealed secret:
|
||||
|
||||
```bash
|
||||
kubectl create secret generic antigravity-secrets \
|
||||
--from-literal=github-token='ghp_your_token' \
|
||||
--from-literal=happy-coder-api-key='your_key' \
|
||||
--from-literal=vnc-password='your_password' \
|
||||
--dry-run=client -o yaml | \
|
||||
kubeseal --format=yaml > k8s/sealedsecrets.yaml
|
||||
```
|
||||
|
||||
### 3. Configure Repository
|
||||
|
||||
Edit `k8s/configmap.yaml`:
|
||||
|
||||
```yaml
|
||||
data:
|
||||
github-repo: "https://github.com/yourusername/yourrepo"
|
||||
```
|
||||
|
||||
### 4. Deploy to Kubernetes
|
||||
|
||||
```bash
|
||||
kubectl apply -k k8s/
|
||||
```
|
||||
|
||||
### 5. Access the Interface
|
||||
|
||||
```bash
|
||||
# Port forward for local access
|
||||
kubectl port-forward statefulset/antigravity 5800:5800
|
||||
|
||||
# Open in browser
|
||||
open http://localhost:5800
|
||||
```
|
||||
|
||||
Or configure Ingress for external access.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Required
|
||||
- `GITHUB_REPO` - GitHub repository URL to clone
|
||||
|
||||
### Optional
|
||||
- `GITHUB_TOKEN` - GitHub Personal Access Token (for private repos)
|
||||
- `HAPPY_CODER_API_KEY` - API key for Happy Coder
|
||||
- `VNC_PASSWORD` - Password for VNC access
|
||||
- `USER_ID` - UID for claude user (default: 1000)
|
||||
- `GROUP_ID` - GID for claude user (default: 1000)
|
||||
- `DISPLAY_WIDTH` - VNC display width (default: 1920)
|
||||
- `DISPLAY_HEIGHT` - VNC display height (default: 1080)
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ Web Browser (Port 5800) │
|
||||
└──────────────┬──────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ VNC Web Interface │
|
||||
│ (jlesage/baseimage-gui) │
|
||||
└──────────────┬──────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ Antigravity IDE │
|
||||
│ (VSCode + Extensions) │
|
||||
│ Running as user: claude (1000) │
|
||||
└──────────────┬──────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ Happy Coder (Background Process) │
|
||||
│ AI Development Assistant │
|
||||
└─────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────┐
|
||||
│ Workspace: /workspace/{repo} │
|
||||
│ Home: /home/claude (RWX PVC) │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Startup Flow
|
||||
|
||||
1. **Container starts** - baseimage-gui initializes
|
||||
2. **init-repo.sh runs**:
|
||||
- Checks for `GITHUB_REPO` environment variable
|
||||
- Clones repository to `/workspace/{repo-name}` if not exists
|
||||
- Configures git credentials with `GITHUB_TOKEN`
|
||||
- Starts Happy Coder in background
|
||||
3. **startapp.sh runs**:
|
||||
- Opens Antigravity IDE in the cloned repository
|
||||
- Happy Coder is already running and accessible
|
||||
|
||||
## Happy Coder Integration
|
||||
|
||||
Happy Coder runs as a background service and is accessible within the IDE:
|
||||
|
||||
```bash
|
||||
# Check Happy Coder status
|
||||
ps aux | grep happy-coder
|
||||
|
||||
# View logs
|
||||
cat /tmp/happy-coder.log
|
||||
|
||||
# Restart Happy Coder
|
||||
sudo -u claude bash -c "cd /workspace/your-repo && happy-coder &"
|
||||
```
|
||||
|
||||
## Local Development
|
||||
|
||||
### Run with Docker Compose
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
services:
|
||||
antigravity:
|
||||
build: .
|
||||
ports:
|
||||
- "5800:5800"
|
||||
environment:
|
||||
- GITHUB_REPO=https://github.com/yourusername/yourrepo
|
||||
- GITHUB_TOKEN=ghp_your_token
|
||||
- HAPPY_CODER_API_KEY=your_key
|
||||
- VNC_PASSWORD=yourpassword
|
||||
volumes:
|
||||
- ./home:/home
|
||||
- ./workspace:/workspace
|
||||
```
|
||||
|
||||
```bash
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
### Run with Docker
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
-p 5800:5800 \
|
||||
-e GITHUB_REPO="https://github.com/yourusername/yourrepo" \
|
||||
-e GITHUB_TOKEN="ghp_your_token" \
|
||||
-e HAPPY_CODER_API_KEY="your_key" \
|
||||
-e VNC_PASSWORD="yourpassword" \
|
||||
-v $(pwd)/home:/home \
|
||||
-v $(pwd)/workspace:/workspace \
|
||||
ghcr.io/cpfarhood/antigravity:latest
|
||||
```
|
||||
|
||||
## Kubernetes Deployment
|
||||
|
||||
### With Flux
|
||||
|
||||
See the animaniacs cluster configuration for GitOps deployment patterns.
|
||||
|
||||
### Standalone
|
||||
|
||||
```bash
|
||||
# Apply manifests
|
||||
kubectl apply -k k8s/
|
||||
|
||||
# Check status
|
||||
kubectl get statefulset antigravity
|
||||
kubectl get pods -l app=antigravity
|
||||
|
||||
# Access logs
|
||||
kubectl logs antigravity-0
|
||||
|
||||
# Access shell
|
||||
kubectl exec -it antigravity-0 -- bash
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Repository not cloning
|
||||
|
||||
```bash
|
||||
# Check logs
|
||||
kubectl logs antigravity-0 | grep "Repository Initialization"
|
||||
|
||||
# Verify GITHUB_REPO is set
|
||||
kubectl exec antigravity-0 -- env | grep GITHUB
|
||||
|
||||
# Check git credentials
|
||||
kubectl exec antigravity-0 -- cat /home/claude/.git-credentials
|
||||
```
|
||||
|
||||
### Happy Coder not starting
|
||||
|
||||
```bash
|
||||
# Check Happy Coder logs
|
||||
kubectl exec antigravity-0 -- cat /tmp/happy-coder.log
|
||||
|
||||
# Verify API key
|
||||
kubectl exec antigravity-0 -- env | grep HAPPY_CODER
|
||||
|
||||
# Restart Happy Coder
|
||||
kubectl exec antigravity-0 -- sudo -u claude bash -c "cd /workspace/repo && happy-coder &"
|
||||
```
|
||||
|
||||
### VNC not accessible
|
||||
|
||||
```bash
|
||||
# Check port forwarding
|
||||
kubectl port-forward antigravity-0 5800:5800
|
||||
|
||||
# Verify service
|
||||
kubectl get svc antigravity
|
||||
|
||||
# Check pod status
|
||||
kubectl describe pod antigravity-0
|
||||
```
|
||||
|
||||
### Permission issues
|
||||
|
||||
```bash
|
||||
# Check ownership
|
||||
kubectl exec antigravity-0 -- ls -la /home/claude
|
||||
kubectl exec antigravity-0 -- ls -la /workspace
|
||||
|
||||
# Fix ownership
|
||||
kubectl exec antigravity-0 -- chown -R claude:claude /home/claude
|
||||
kubectl exec antigravity-0 -- chown -R claude:claude /workspace
|
||||
```
|
||||
|
||||
## Security Considerations
|
||||
|
||||
1. **Secrets Management**: Use SealedSecrets or external secret managers
|
||||
2. **Network Policies**: Restrict ingress/egress as needed
|
||||
3. **RBAC**: Limit who can access the namespace
|
||||
4. **VNC Password**: Always set a strong VNC password
|
||||
5. **GitHub Token**: Use fine-grained tokens with minimal permissions
|
||||
6. **Container Security**: Runs as non-root user (claude:1000)
|
||||
|
||||
## Storage
|
||||
|
||||
### Home Directory (`/home`)
|
||||
- Mounted from ReadWriteMany PVC (`userhome`)
|
||||
- Persists user settings, credentials, history
|
||||
- Survives pod restarts
|
||||
|
||||
### Workspace (`/workspace`)
|
||||
- ephemeral emptyDir (can be changed to PVC)
|
||||
- Contains cloned repository
|
||||
- Rebuild on pod restart
|
||||
|
||||
To persist workspace:
|
||||
1. Create a PVC for workspace
|
||||
2. Update `statefulset.yaml` to use PVC instead of emptyDir
|
||||
|
||||
## Customization
|
||||
|
||||
### Add More Tools
|
||||
|
||||
Edit `Dockerfile`:
|
||||
|
||||
```dockerfile
|
||||
RUN apt-get update && apt-get install -y \
|
||||
your-package-here \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
```
|
||||
|
||||
### Change Display Resolution
|
||||
|
||||
Set environment variables:
|
||||
|
||||
```yaml
|
||||
env:
|
||||
- name: DISPLAY_WIDTH
|
||||
value: "2560"
|
||||
- name: DISPLAY_HEIGHT
|
||||
value: "1440"
|
||||
```
|
||||
|
||||
### Auto-clone Multiple Repos
|
||||
|
||||
Modify `init-repo.sh` to support `GITHUB_REPOS` (comma-separated):
|
||||
|
||||
```bash
|
||||
IFS=',' read -ra REPOS <<< "$GITHUB_REPOS"
|
||||
for repo in "${REPOS[@]}"; do
|
||||
# Clone each repo
|
||||
done
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## Credits
|
||||
|
||||
- Built on [jlesage/baseimage-gui](https://github.com/jlesage/docker-baseimage-gui)
|
||||
- Uses [Happy Coder](https://happy.engineering)
|
||||
- Inspired by Google's Project IDX
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: antigravity-config
|
||||
data:
|
||||
# GitHub repository to clone on startup
|
||||
# Example: "https://github.com/username/repository"
|
||||
github-repo: ""
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: antigravity
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
|
||||
nginx.ingress.kubernetes.io/websocket-services: "antigravity"
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- antigravity.example.com # Replace with your domain
|
||||
secretName: antigravity-tls
|
||||
rules:
|
||||
- host: antigravity.example.com # Replace with your domain
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: antigravity
|
||||
port:
|
||||
number: 5800
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
namespace: default
|
||||
|
||||
resources:
|
||||
- configmap.yaml
|
||||
- statefulset.yaml
|
||||
- ingress.yaml
|
||||
|
||||
# Uncomment to create secrets from files
|
||||
# secretGenerator:
|
||||
# - name: antigravity-secrets
|
||||
# literals:
|
||||
# - github-token=ghp_your_token
|
||||
# - happy-coder-api-key=your_key
|
||||
# - vnc-password=your_password
|
||||
|
||||
commonLabels:
|
||||
app: antigravity
|
||||
environment: production
|
||||
|
||||
commonAnnotations:
|
||||
managed-by: kustomize
|
||||
description: "Antigravity Dev Container with Happy Coder"
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
# Example secrets - DO NOT commit actual secrets!
|
||||
# Use SealedSecrets or another secret management solution
|
||||
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: antigravity-secrets
|
||||
type: Opaque
|
||||
stringData:
|
||||
# GitHub Personal Access Token (for private repos)
|
||||
github-token: "ghp_your_token_here"
|
||||
|
||||
# Happy Coder API Key
|
||||
happy-coder-api-key: "your_happy_coder_api_key"
|
||||
|
||||
# VNC Password (optional, for secure VNC access)
|
||||
vnc-password: "your_vnc_password"
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: antigravity
|
||||
labels:
|
||||
app: antigravity
|
||||
spec:
|
||||
ports:
|
||||
- port: 5800
|
||||
name: vnc-web
|
||||
protocol: TCP
|
||||
clusterIP: None
|
||||
selector:
|
||||
app: antigravity
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: antigravity
|
||||
spec:
|
||||
serviceName: "antigravity"
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: antigravity
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: antigravity
|
||||
spec:
|
||||
securityContext:
|
||||
fsGroup: 1000
|
||||
fsGroupChangePolicy: "OnRootMismatch"
|
||||
containers:
|
||||
- name: antigravity
|
||||
image: ghcr.io/cpfarhood/antigravity:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- containerPort: 5800
|
||||
name: vnc-web
|
||||
protocol: TCP
|
||||
volumeMounts:
|
||||
- name: userhome
|
||||
mountPath: /home
|
||||
- name: workspace
|
||||
mountPath: /workspace
|
||||
env:
|
||||
# User/Group IDs for the claude user
|
||||
- name: USER_ID
|
||||
value: "1000"
|
||||
- name: GROUP_ID
|
||||
value: "1000"
|
||||
# VNC display settings
|
||||
- name: DISPLAY_WIDTH
|
||||
value: "1920"
|
||||
- name: DISPLAY_HEIGHT
|
||||
value: "1080"
|
||||
- name: SECURE_CONNECTION
|
||||
value: "1"
|
||||
- name: VNC_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: antigravity
|
||||
key: vnc-password
|
||||
optional: true
|
||||
# GitHub configuration
|
||||
- name: GITHUB_REPO
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: antigravity
|
||||
key: github-repo
|
||||
optional: true
|
||||
- name: GITHUB_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: antigravity
|
||||
key: github-token
|
||||
optional: true
|
||||
# Happy Coder configuration
|
||||
- name: HAPPY_CODER_API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: antigravity
|
||||
key: happy-coder-api-key
|
||||
optional: true
|
||||
resources:
|
||||
requests:
|
||||
memory: "2Gi"
|
||||
cpu: "1000m"
|
||||
limits:
|
||||
memory: "8Gi"
|
||||
cpu: "4000m"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 5800
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: 5800
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
volumes:
|
||||
- name: workspace
|
||||
emptyDir: {}
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: userhome
|
||||
spec:
|
||||
accessModes: [ "ReadWriteMany" ]
|
||||
storageClassName: "ceph-filesystem"
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
@@ -0,0 +1,78 @@
|
||||
#!/bin/bash
|
||||
# Initialize repository and start Happy Coder
|
||||
set -e
|
||||
|
||||
echo "=== Repository Initialization ==="
|
||||
|
||||
# Check if GITHUB_REPO is set
|
||||
if [ -z "$GITHUB_REPO" ]; then
|
||||
echo "GITHUB_REPO not set, skipping repository clone"
|
||||
WORKSPACE_DIR="/workspace/default"
|
||||
mkdir -p "$WORKSPACE_DIR"
|
||||
else
|
||||
# Parse repo name from URL
|
||||
REPO_NAME=$(basename "$GITHUB_REPO" .git)
|
||||
WORKSPACE_DIR="/workspace/$REPO_NAME"
|
||||
|
||||
echo "Repository: $GITHUB_REPO"
|
||||
echo "Target directory: $WORKSPACE_DIR"
|
||||
|
||||
# Check if repo already exists
|
||||
if [ -d "$WORKSPACE_DIR/.git" ]; then
|
||||
echo "Repository already exists, pulling latest changes..."
|
||||
cd "$WORKSPACE_DIR"
|
||||
|
||||
# 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
|
||||
fi
|
||||
|
||||
git pull || echo "Pull failed, continuing anyway..."
|
||||
else
|
||||
echo "Cloning repository..."
|
||||
mkdir -p "$(dirname "$WORKSPACE_DIR")"
|
||||
|
||||
# Clone with token if provided
|
||||
if [ -n "$GITHUB_TOKEN" ]; then
|
||||
# Replace https://github.com/ with https://oauth2:token@github.com/
|
||||
CLONE_URL=$(echo "$GITHUB_REPO" | sed "s|https://github.com/|https://oauth2:${GITHUB_TOKEN}@github.com/|")
|
||||
git clone "$CLONE_URL" "$WORKSPACE_DIR"
|
||||
|
||||
# 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
|
||||
else
|
||||
git clone "$GITHUB_REPO" "$WORKSPACE_DIR"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Set ownership
|
||||
chown -R claude:claude "$WORKSPACE_DIR"
|
||||
chown -R claude:claude /home/claude
|
||||
|
||||
# Start Happy Coder in background as claude 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"
|
||||
|
||||
# Start Happy Coder as claude user
|
||||
sudo -u claude bash -c "cd '$WORKSPACE_DIR' && happy-coder > '$HAPPY_LOG' 2>&1 &"
|
||||
|
||||
# Save PID for monitoring
|
||||
echo $! > /tmp/happy-coder.pid
|
||||
|
||||
echo "Happy Coder started (PID: $(cat /tmp/happy-coder.pid))"
|
||||
echo "Logs available at: $HAPPY_LOG"
|
||||
|
||||
# Export workspace directory for startapp.sh
|
||||
echo "$WORKSPACE_DIR" > /tmp/workspace-dir
|
||||
|
||||
echo "=== Initialization Complete ==="
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
# Start application script for baseimage-gui
|
||||
set -e
|
||||
|
||||
echo "=== Starting Antigravity Dev Container ==="
|
||||
|
||||
# Initialize repository and Happy Coder
|
||||
/usr/local/bin/init-repo
|
||||
|
||||
# Get workspace directory
|
||||
if [ -f /tmp/workspace-dir ]; then
|
||||
WORKSPACE_DIR=$(cat /tmp/workspace-dir)
|
||||
else
|
||||
WORKSPACE_DIR="/workspace/default"
|
||||
fi
|
||||
|
||||
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"
|
||||
Reference in New Issue
Block a user