Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 288c1a4103 | |||
| 2caa8a790f | |||
| 7a6a515b53 | |||
| 4f126a938b | |||
| 4af38a5d2e | |||
| 90350a2090 | |||
| 5b8e6a290b | |||
| e860499757 | |||
| e90a2fe553 | |||
| 897f1409b5 | |||
| 32d4fe4944 |
@@ -3,7 +3,8 @@
|
|||||||

|

|
||||||
|
|
||||||
A containerized cloud development environment with web-based GUI access, featuring:
|
A containerized cloud development environment with web-based GUI access, featuring:
|
||||||
- **VSCode** via browser-based VNC (port 5800)
|
- **VSCode or Google Antigravity** via browser-based VNC (port 5800)
|
||||||
|
- **SSH access** option (OpenSSH on port 22, additive with any IDE)
|
||||||
- **Happy Coder** AI assistant backed by Claude
|
- **Happy Coder** AI assistant backed by Claude
|
||||||
- **Automatic GitHub repo cloning** on startup
|
- **Automatic GitHub repo cloning** on startup
|
||||||
- **Persistent home directory** via ReadWriteMany PVC
|
- **Persistent home directory** via ReadWriteMany PVC
|
||||||
@@ -160,6 +161,7 @@ With any non-`none` value, a `ServiceAccount` named `devcontainer-{name}` is cre
|
|||||||
| `groupId` | `1000` | GID for the app user |
|
| `groupId` | `1000` | GID for the app user |
|
||||||
| `storage.size` | `32Gi` | Home PVC size |
|
| `storage.size` | `32Gi` | Home PVC size |
|
||||||
| `storage.className` | `ceph-filesystem` | StorageClass (must be ReadWriteMany) |
|
| `storage.className` | `ceph-filesystem` | StorageClass (must be ReadWriteMany) |
|
||||||
|
| `shm.sizeLimit` | `2Gi` | `/dev/shm` size (memory-backed; used by Electron apps) |
|
||||||
| `resources.requests.memory` | `2Gi` | |
|
| `resources.requests.memory` | `2Gi` | |
|
||||||
| `resources.requests.cpu` | `1000m` | |
|
| `resources.requests.cpu` | `1000m` | |
|
||||||
| `resources.limits.memory` | `8Gi` | |
|
| `resources.limits.memory` | `8Gi` | |
|
||||||
@@ -182,9 +184,9 @@ Container start
|
|||||||
→ rm daemon.state.json.lock — clear stale Happy lock
|
→ rm daemon.state.json.lock — clear stale Happy lock
|
||||||
→ happy daemon start — starts Happy Coder background daemon
|
→ happy daemon start — starts Happy Coder background daemon
|
||||||
→ IDE=vscode: code --new-window --wait /workspace/{repo}
|
→ IDE=vscode: code --new-window --wait /workspace/{repo}
|
||||||
IDE=antigravity: antigravity --new-window --wait /workspace/{repo}
|
IDE=antigravity: antigravity --no-sandbox --user-data-dir ~/.config/antigravity ... /workspace/{repo}
|
||||||
IDE=none: sleep infinity
|
IDE=none: sleep infinity
|
||||||
(SSH=true: sshd also running as root on port 22)
|
(SSH=true: sshd also running as root on port 22; host keys persisted on PVC)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Storage
|
### Storage
|
||||||
@@ -230,7 +232,15 @@ Then restart the pod to pick up the new env var.
|
|||||||
```bash
|
```bash
|
||||||
kubectl port-forward deployment/devcontainer-mydev 5800:5800
|
kubectl port-forward deployment/devcontainer-mydev 5800:5800
|
||||||
kubectl logs deployment/devcontainer-mydev
|
kubectl logs deployment/devcontainer-mydev
|
||||||
kubectl describe pod -l instance=mydev
|
kubectl describe pod -l app.kubernetes.io/instance=mydev
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pod not picking up new image after upgrade
|
||||||
|
|
||||||
|
The chart uses `image.tag: latest`. Kubernetes won't restart the pod on a Helm upgrade unless the Deployment spec changes. Force a restart manually:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl rollout restart deployment/devcontainer-mydev
|
||||||
```
|
```
|
||||||
|
|
||||||
### Repository not cloning
|
### Repository not cloning
|
||||||
|
|||||||
+1
-1
@@ -2,5 +2,5 @@ apiVersion: v2
|
|||||||
name: devcontainer
|
name: devcontainer
|
||||||
description: Antigravity Dev Container with Happy Coder AI assistant
|
description: Antigravity Dev Container with Happy Coder AI assistant
|
||||||
type: application
|
type: application
|
||||||
version: 0.1.6
|
version: 0.1.12
|
||||||
appVersion: "latest"
|
appVersion: "latest"
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ spec:
|
|||||||
mountPath: /home
|
mountPath: /home
|
||||||
- name: workspace
|
- name: workspace
|
||||||
mountPath: /workspace
|
mountPath: /workspace
|
||||||
|
- name: shm
|
||||||
|
mountPath: /dev/shm
|
||||||
{{- if ne (.Values.ide | default "vscode") "none" }}
|
{{- if ne (.Values.ide | default "vscode") "none" }}
|
||||||
livenessProbe:
|
livenessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
@@ -99,6 +101,10 @@ spec:
|
|||||||
volumes:
|
volumes:
|
||||||
- name: workspace
|
- name: workspace
|
||||||
emptyDir: {}
|
emptyDir: {}
|
||||||
|
- name: shm
|
||||||
|
emptyDir:
|
||||||
|
medium: Memory
|
||||||
|
sizeLimit: {{ .Values.shm.sizeLimit }}
|
||||||
- name: userhome
|
- name: userhome
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: {{ include "antigravity.pvcName" . }}
|
claimName: {{ include "antigravity.pvcName" . }}
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ storage:
|
|||||||
size: 32Gi
|
size: 32Gi
|
||||||
className: ceph-filesystem
|
className: ceph-filesystem
|
||||||
|
|
||||||
|
# Shared memory size — mounted at /dev/shm as a memory-backed emptyDir.
|
||||||
|
# Electron apps (Antigravity, Chrome) use /dev/shm for GPU/IPC buffers.
|
||||||
|
shm:
|
||||||
|
sizeLimit: 2Gi
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: "2Gi"
|
memory: "2Gi"
|
||||||
|
|||||||
@@ -5,12 +5,30 @@
|
|||||||
|
|
||||||
echo "=== SSH enabled: starting sshd ==="
|
echo "=== SSH enabled: starting sshd ==="
|
||||||
|
|
||||||
# Generate host keys if missing (first boot or ephemeral /etc/ssh)
|
HOME_DIR="/home/user"
|
||||||
ssh-keygen -A 2>/dev/null || true
|
HOST_KEY_STORE="$HOME_DIR/.ssh/host_keys"
|
||||||
|
|
||||||
|
# Persist host keys on the home PVC so clients don't see a "host key
|
||||||
|
# changed" warning after pod restarts.
|
||||||
|
if [ -d "$HOST_KEY_STORE" ] && [ -n "$(ls "$HOST_KEY_STORE"/ssh_host_* 2>/dev/null)" ]; then
|
||||||
|
# Restore previously generated host keys
|
||||||
|
echo "Restoring SSH host keys from PVC..."
|
||||||
|
cp "$HOST_KEY_STORE"/ssh_host_* /etc/ssh/
|
||||||
|
chmod 600 /etc/ssh/ssh_host_*_key
|
||||||
|
chmod 644 /etc/ssh/ssh_host_*_key.pub
|
||||||
|
else
|
||||||
|
# First boot: generate and save host keys to PVC
|
||||||
|
echo "Generating SSH host keys (first boot)..."
|
||||||
|
ssh-keygen -A 2>/dev/null || true
|
||||||
|
mkdir -p "$HOST_KEY_STORE"
|
||||||
|
cp /etc/ssh/ssh_host_* "$HOST_KEY_STORE/"
|
||||||
|
chmod 700 "$HOST_KEY_STORE"
|
||||||
|
chown -R 1000:1000 "$HOST_KEY_STORE"
|
||||||
|
echo "SSH host keys saved to PVC."
|
||||||
|
fi
|
||||||
|
|
||||||
# Populate authorized_keys from env var (injected via Kubernetes secret)
|
# Populate authorized_keys from env var (injected via Kubernetes secret)
|
||||||
if [ -n "$SSH_AUTHORIZED_KEYS" ]; then
|
if [ -n "$SSH_AUTHORIZED_KEYS" ]; then
|
||||||
HOME_DIR="/home/user"
|
|
||||||
mkdir -p "$HOME_DIR/.ssh"
|
mkdir -p "$HOME_DIR/.ssh"
|
||||||
chmod 700 "$HOME_DIR/.ssh"
|
chmod 700 "$HOME_DIR/.ssh"
|
||||||
printf '%s\n' "$SSH_AUTHORIZED_KEYS" > "$HOME_DIR/.ssh/authorized_keys"
|
printf '%s\n' "$SSH_AUTHORIZED_KEYS" > "$HOME_DIR/.ssh/authorized_keys"
|
||||||
|
|||||||
+7
-1
@@ -21,7 +21,13 @@ echo "Workspace: $WORKSPACE_DIR"
|
|||||||
case "$IDE" in
|
case "$IDE" in
|
||||||
antigravity)
|
antigravity)
|
||||||
echo "Opening Google Antigravity in: $WORKSPACE_DIR"
|
echo "Opening Google Antigravity in: $WORKSPACE_DIR"
|
||||||
exec antigravity --new-window --wait "$WORKSPACE_DIR"
|
# --no-sandbox is required for Electron apps in Docker (no kernel sandbox available).
|
||||||
|
# Explicit --user-data-dir and --extensions-dir pin config to the home PVC so
|
||||||
|
# settings and the setup wizard state survive pod restarts.
|
||||||
|
exec antigravity --no-sandbox \
|
||||||
|
--user-data-dir "$HOME/.config/antigravity" \
|
||||||
|
--extensions-dir "$HOME/.antigravity/extensions" \
|
||||||
|
--new-window --wait "$WORKSPACE_DIR"
|
||||||
;;
|
;;
|
||||||
none)
|
none)
|
||||||
echo "IDE=none: no IDE launched, keeping container alive."
|
echo "IDE=none: no IDE launched, keeping container alive."
|
||||||
|
|||||||
Reference in New Issue
Block a user