Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cf429115d7 | |||
| 27af9dc9c4 | |||
| 0944dcec1c | |||
| 60a2689658 | |||
| 53bc4b68a6 | |||
| d526a445fd | |||
| f56b3efb66 | |||
| a778d32b3b | |||
| b48fce97d5 | |||
| 47af7acc5e | |||
| da45415cfe | |||
| 897555b1dc | |||
| df1f4d9b50 | |||
| 2f5a8d65d5 | |||
| 0d8fe1ec64 | |||
| 00638d372c | |||
| 31ec139a8a | |||
| 71c6ca70cc |
@@ -2,6 +2,8 @@
|
||||
"enabledMcpjsonServers": [
|
||||
"kubernetes",
|
||||
"flux",
|
||||
"playwright"
|
||||
"playwright",
|
||||
"github",
|
||||
"pgtuner"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- 'v*'
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
@@ -18,6 +16,9 @@ env:
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
# Skip builds triggered by release-unified.yaml commits (github-actions[bot])
|
||||
# to prevent racing with the release workflow's own Docker build
|
||||
if: github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' || github.actor != 'github-actions[bot]'
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
@@ -46,9 +47,6 @@ jobs:
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
type=sha,prefix=sha-
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@v4
|
||||
|
||||
- name: Extract version from tag
|
||||
id: version
|
||||
run: |
|
||||
TAG=${GITHUB_REF#refs/tags/}
|
||||
VERSION=${TAG#v}
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
echo "version=${VERSION}" >> $GITHUB_OUTPUT
|
||||
echo "🚀 Creating release for ${TAG}"
|
||||
|
||||
- name: Package and Push Helm Chart
|
||||
run: |
|
||||
helm registry login ghcr.io \
|
||||
--username ${{ github.actor }} \
|
||||
--password ${{ secrets.GITHUB_TOKEN }}
|
||||
helm package chart/
|
||||
helm push devcontainer-${{ steps.version.outputs.version }}.tgz oci://ghcr.io/cpfarhood/charts
|
||||
|
||||
- name: Generate Release Notes
|
||||
id: notes
|
||||
run: |
|
||||
# Get commits since last tag
|
||||
PREV_TAG=$(git describe --tags --abbrev=0 ${{ steps.version.outputs.tag }}^ 2>/dev/null || echo "")
|
||||
if [ -z "$PREV_TAG" ]; then
|
||||
COMMITS=$(git log --pretty=format:"- %s (%h)" ${{ steps.version.outputs.tag }})
|
||||
else
|
||||
COMMITS=$(git log --pretty=format:"- %s (%h)" ${PREV_TAG}..${{ steps.version.outputs.tag }})
|
||||
fi
|
||||
|
||||
cat << EOF > release-notes.md
|
||||
## 🚀 Release ${{ steps.version.outputs.version }}
|
||||
|
||||
### Changes
|
||||
${COMMITS}
|
||||
|
||||
### Docker Image
|
||||
\`\`\`bash
|
||||
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.tag }}
|
||||
\`\`\`
|
||||
|
||||
### Helm Chart
|
||||
\`\`\`bash
|
||||
helm install devcontainer oci://ghcr.io/cpfarhood/charts/devcontainer --version ${{ steps.version.outputs.version }}
|
||||
\`\`\`
|
||||
EOF
|
||||
|
||||
echo "notes<<EOF" >> $GITHUB_OUTPUT
|
||||
cat release-notes.md >> $GITHUB_OUTPUT
|
||||
echo "EOF" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create GitHub Release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ steps.version.outputs.tag }}
|
||||
release_name: Release ${{ steps.version.outputs.tag }}
|
||||
body: ${{ steps.notes.outputs.notes }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
@@ -22,6 +22,14 @@
|
||||
"pgtuner": {
|
||||
"type": "sse",
|
||||
"url": "http://localhost:8085/sse"
|
||||
},
|
||||
"fetch": {
|
||||
"type": "sse",
|
||||
"url": "http://localhost:8082/sse"
|
||||
},
|
||||
"sequentialthinking": {
|
||||
"type": "sse",
|
||||
"url": "http://localhost:8083/sse"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ The stack is primarily **Bash scripts + YAML** — there is no Node.js package,
|
||||
```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
|
||||
docker build -t ghcr.io/cpfarhood/devcontainer:latest . # Direct build
|
||||
```
|
||||
|
||||
### Running Locally
|
||||
@@ -77,7 +77,7 @@ Container start
|
||||
| `chart/templates/pvc.yaml` | PersistentVolumeClaim for user home |
|
||||
| `chart/templates/service.yaml` | ClusterIP Service (VNC + optional SSH) |
|
||||
| `chart/values.yaml` | Default Helm values |
|
||||
| `.mcp.json` | MCP server connection config (Kubernetes, Flux, GitHub, Home Assistant, Playwright) |
|
||||
| `.mcp.json` | MCP server connection config (GitHub Copilot, Kubernetes, Flux, Fetch, Sequential Thinking, Playwright, pgtuner) |
|
||||
| `Makefile` | Build/deploy automation |
|
||||
|
||||
### MCP Sidecars
|
||||
@@ -88,15 +88,18 @@ MCP (Model Context Protocol) servers run as sidecar containers in the pod, enabl
|
||||
|---------|-------|---------|------|----------|---------|
|
||||
| `kubernetes-mcp` | `quay.io/containers/kubernetes_mcp_server` | v0.0.57 | 8080 | `http://localhost:8080/sse` | Enabled |
|
||||
| `flux-mcp` | `ghcr.io/controlplaneio-fluxcd/flux-operator-mcp` | v0.41.1 | 8081 | `http://localhost:8081/sse` | Enabled |
|
||||
| `github-mcp` | `ghcr.io/modelcontextprotocol/servers/github` | latest | 8088 | `http://localhost:8088/sse` | Disabled |
|
||||
| `fetch-mcp` | `mcp/fetch` | latest | 8082 | `http://localhost:8082/sse` | Enabled |
|
||||
| `sequentialthinking-mcp` | `mcp/sequentialthinking` | latest | 8083 | `http://localhost:8083/sse` | Enabled |
|
||||
| `homeassistant-mcp` | `ghcr.io/homeassistant-ai/ha-mcp` | stable | 8087 | `http://localhost:8087/sse` | Disabled |
|
||||
| `pgtuner-mcp` | `dog830228/pgtuner_mcp` | latest | 8085 | `http://localhost:8085/sse` | Disabled |
|
||||
| `playwright-mcp` | `microsoft/playwright-mcp` | latest | 8086 | `http://localhost:8086/sse` | Enabled |
|
||||
| `playwright-mcp` | `mcr.microsoft.com/playwright/mcp` | latest | 8086 | `http://localhost:8086/sse` | Enabled |
|
||||
|
||||
**Note:**
|
||||
- GitHub MCP is accessed via the Copilot API (`https://api.githubcopilot.com/mcp/`), not as a sidecar
|
||||
- Kubernetes and Flux sidecars require `clusterAccess` != `none` to be deployed (they need RBAC permissions)
|
||||
- Kubernetes and Flux sidecars inherit the pod's ServiceAccount RBAC permissions
|
||||
- GitHub sidecar uses `GITHUB_TOKEN` from the env secret (same token used for repo cloning)
|
||||
- Fetch sidecar provides web content fetching capabilities and HTML to markdown conversion
|
||||
- Sequential thinking sidecar enables structured thinking and problem-solving processes
|
||||
- Home Assistant sidecar requires `HOMEASSISTANT_URL` and `HOMEASSISTANT_TOKEN` in the env secret
|
||||
- PostgreSQL tuner sidecar requires `DATABASE_URI` in the env secret (PostgreSQL connection string)
|
||||
- Playwright sidecar provides browser automation and web testing capabilities
|
||||
@@ -109,34 +112,38 @@ To control MCP sidecars, set the `enabled` flag in your values override:
|
||||
# Disable all MCP sidecars
|
||||
mcp:
|
||||
sidecars:
|
||||
kubernetes:
|
||||
enabled: false
|
||||
flux:
|
||||
enabled: false
|
||||
github:
|
||||
enabled: false
|
||||
homeassistant:
|
||||
enabled: false
|
||||
pgtuner:
|
||||
enabled: false
|
||||
playwright:
|
||||
enabled: false
|
||||
kubernetes:
|
||||
enabled: false
|
||||
flux:
|
||||
enabled: false
|
||||
fetch:
|
||||
enabled: false
|
||||
sequentialthinking:
|
||||
enabled: false
|
||||
homeassistant:
|
||||
enabled: false
|
||||
pgtuner:
|
||||
enabled: false
|
||||
playwright:
|
||||
enabled: false
|
||||
|
||||
# Or selectively enable/disable
|
||||
mcp:
|
||||
sidecars:
|
||||
kubernetes:
|
||||
enabled: true # Keep Kubernetes MCP enabled
|
||||
flux:
|
||||
enabled: false # Disable Flux MCP
|
||||
github:
|
||||
enabled: true # Keep GitHub MCP enabled (uses GITHUB_TOKEN)
|
||||
homeassistant:
|
||||
enabled: true # Enable Home Assistant MCP (requires secrets)
|
||||
pgtuner:
|
||||
enabled: true # Enable PostgreSQL tuner MCP (requires DATABASE_URI)
|
||||
playwright:
|
||||
enabled: true # Enable Playwright MCP for browser automation
|
||||
kubernetes:
|
||||
enabled: true # Keep Kubernetes MCP enabled
|
||||
flux:
|
||||
enabled: false # Disable Flux MCP
|
||||
fetch:
|
||||
enabled: true # Enable Fetch MCP for web content fetching
|
||||
sequentialthinking:
|
||||
enabled: true # Enable Sequential Thinking MCP for problem-solving
|
||||
homeassistant:
|
||||
enabled: true # Enable Home Assistant MCP (requires secrets)
|
||||
pgtuner:
|
||||
enabled: true # Enable PostgreSQL tuner MCP (requires DATABASE_URI)
|
||||
playwright:
|
||||
enabled: true # Enable Playwright MCP for browser automation
|
||||
```
|
||||
|
||||
When deploying via Helm:
|
||||
@@ -179,8 +186,7 @@ helm install my-devcontainer ./chart -f custom-values.yaml
|
||||
|
||||
### 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.
|
||||
- **`build-and-push.yaml`** — Builds and pushes to GHCR on every push to `main`, version tags (`v*`), and PRs. For version tags, also creates GitHub Release with Helm chart after Docker build completes. Tags: `latest` (main), semver, branch name, commit SHA.
|
||||
- **`dependabot.yml`** — Weekly updates for GitHub Actions and Docker base image.
|
||||
|
||||
Image registry: `ghcr.io/cpfarhood/devcontainer`
|
||||
|
||||
+17
-1
@@ -89,10 +89,26 @@ RUN mkdir -p /etc/apt/keyrings && \
|
||||
gpg --dearmor --yes -o /etc/apt/keyrings/antigravity-repo-key.gpg && \
|
||||
echo "deb [signed-by=/etc/apt/keyrings/antigravity-repo-key.gpg] https://us-central1-apt.pkg.dev/projects/antigravity-auto-updater-dev/ antigravity-debian main" \
|
||||
> /etc/apt/sources.list.d/antigravity.list && \
|
||||
# Clear package cache to force fresh repository data
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
apt-get update && \
|
||||
apt-get install -y antigravity && \
|
||||
# Show available versions for debugging
|
||||
apt-cache policy antigravity && \
|
||||
# Install latest version
|
||||
apt-get install -y --no-install-recommends antigravity && \
|
||||
# Display installed version
|
||||
dpkg -l | grep antigravity && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Pre-configure Antigravity to skip onboarding/setup on first run
|
||||
RUN mkdir -p /etc/skel/.config/antigravity/User/globalStorage && \
|
||||
echo '{"antigravityUnifiedStateSync.seenNuxOneTimeMigration": true, "antigravityUnifiedStateSync.browserOnboarding.completed": true, "antigravityUnifiedStateSync.hasOnboardingCompleted": true, "browserOnboarding.hasSeenWelcome": true, "antigravityUnifiedStateSync.browserPreferences.hasAddedLocalhostToAllowlist": true, "antigravityUnifiedStateSync.oauthToken.hasLegacyMigrated": true, "antigravityUnifiedStateSync.auth.tokenSyncEnabled": true, "antigravityUnifiedStateSync.auth.cloudSyncEnabled": true, "theme": "vs-dark"}' \
|
||||
> /etc/skel/.config/antigravity/User/globalStorage/storage.json && \
|
||||
echo '{"workbench.startupEditor": "none", "workbench.welcomePage.walkthroughs.openOnInstall": false, "workbench.tips.enabled": false, "extensions.ignoreRecommendations": true, "telemetry.telemetryLevel": "off", "update.mode": "none", "extensions.autoUpdate": false, "extensions.autoCheckUpdates": false, "workbench.enableExperiments": true, "workbench.settings.enableNaturalLanguageSearch": true, "antigravity.onboarding.completed": true, "antigravity.browserOnboarding.completed": true, "antigravity.setup.completed": true, "antigravity.ai.enabled": true, "antigravity.ai.autoComplete.enabled": true, "antigravity.ai.chat.enabled": true, "antigravity.ai.codeActions.enabled": true, "antigravity.ai.explainCode.enabled": true, "antigravity.ai.generateCode.enabled": true, "antigravity.ai.optimizeCode.enabled": true, "antigravity.ai.autoSuggest.enabled": true, "antigravity.telemetry.crashReporter": "on", "antigravity.ai.acceptTerms": true, "antigravity.auth.syncState": true, "antigravity.auth.enableTokenSync": true, "antigravity.ai.enableCloudSync": true, "antigravity.settings.sync": true}' \
|
||||
> /etc/skel/.config/antigravity/User/settings.json && \
|
||||
# Validate Antigravity installation
|
||||
/usr/share/antigravity/antigravity --version || echo "WARNING: Antigravity version check failed"
|
||||
|
||||
# Install OpenSSH server (for SSH IDE mode)
|
||||
RUN apt-get update && \
|
||||
apt-get install -y openssh-server && \
|
||||
|
||||
@@ -48,9 +48,9 @@ The secret is picked up automatically via `envFrom`. Keys recognised:
|
||||
| `VNC_PASSWORD` | Password for the VNC web UI |
|
||||
| `ANTHROPIC_API_KEY` | API key — alternative to browser-based Claude login |
|
||||
| `SSH_AUTHORIZED_KEYS` | Public key(s) for SSH access (required when `ssh: true`) |
|
||||
| `HOMEASSISTANT_URL` | Home Assistant URL (required when `mcpSidecars.homeassistant.enabled: true`) |
|
||||
| `HOMEASSISTANT_TOKEN` | Home Assistant long-lived access token (required when `mcpSidecars.homeassistant.enabled: true`) |
|
||||
| `DATABASE_URI` | PostgreSQL connection string (required when `mcpSidecars.pgtuner.enabled: true`) |
|
||||
| `HOMEASSISTANT_URL` | Home Assistant URL (required when `mcp.sidecars.homeassistant.enabled: true`) |
|
||||
| `HOMEASSISTANT_TOKEN` | Home Assistant long-lived access token (required when `mcp.sidecars.homeassistant.enabled: true`) |
|
||||
| `DATABASE_URI` | PostgreSQL connection string (required when `mcp.sidecars.pgtuner.enabled: true`) |
|
||||
| `PGTUNER_EXCLUDE_USERIDS` | Comma-separated PostgreSQL user OIDs to exclude from monitoring (optional) |
|
||||
|
||||
```bash
|
||||
@@ -119,14 +119,14 @@ The Helm chart uses a logical organization with these main sections:
|
||||
|-------|---------|-------------|
|
||||
| `name` | `""` | Instance name — used in all resource names (`devcontainer-{name}`) |
|
||||
| `githubRepo` | `""` | Repository to clone into `/workspace` on startup |
|
||||
| `ide` | `vscode` | IDE to launch — `vscode`, `antigravity`, or `none` (see below) |
|
||||
| `ssh` | `false` | Also start an OpenSSH server on port 22 (additive, any `ide`) |
|
||||
| `ide.type` | `vscode` | IDE to launch — `vscode`, `antigravity`, or `none` (see below) |
|
||||
| `ssh.enabled` | `false` | Also start an OpenSSH server on port 22 (additive, any IDE) |
|
||||
| `image.repository` | `ghcr.io/cpfarhood/devcontainer` | Container image |
|
||||
| `image.tag` | `latest` | Image tag |
|
||||
|
||||
### IDE choice
|
||||
|
||||
`ide` controls what GUI is launched in the VNC session:
|
||||
`ide.type` controls what GUI is launched in the VNC session:
|
||||
|
||||
| Value | Port | Description |
|
||||
|-------|------|-------------|
|
||||
@@ -136,14 +136,14 @@ The Helm chart uses a logical organization with these main sections:
|
||||
|
||||
### SSH access
|
||||
|
||||
`ssh: true` starts OpenSSH on port 22 **in addition to** the IDE. It works with any `ide` value:
|
||||
`ssh.enabled: true` starts OpenSSH on port 22 **in addition to** the IDE. It works with any `ide.type` value:
|
||||
|
||||
```bash
|
||||
# SSH-only (no VNC)
|
||||
helm install mydev ./chart --set name=mydev --set ide=none --set ssh=true
|
||||
helm install mydev ./chart --set name=mydev --set ide.type=none --set ssh.enabled=true
|
||||
|
||||
# VSCode in VNC + SSH access at the same time
|
||||
helm install mydev ./chart --set name=mydev --set ssh=true
|
||||
helm install mydev ./chart --set name=mydev --set ssh.enabled=true
|
||||
```
|
||||
|
||||
Add your public key to the env secret:
|
||||
@@ -165,10 +165,10 @@ ssh -p 2222 user@localhost
|
||||
|
||||
| Value | Default | Description |
|
||||
|-------|---------|-------------|
|
||||
| `happyServerUrl` | `https://happy.farh.net` | Happy Coder server endpoint |
|
||||
| `happyWebappUrl` | `https://happy-coder.farh.net` | Happy Coder webapp URL |
|
||||
| `happyHomeDir` | `/home/user/.happy` | Happy runtime state directory (persists on the home PVC) |
|
||||
| `happyExperimental` | `true` | Enable experimental Happy features |
|
||||
| `happy.serverUrl` | `https://happy.farh.net` | Happy Coder server endpoint |
|
||||
| `happy.webappUrl` | `https://happy-coder.farh.net` | Happy Coder webapp URL |
|
||||
| `happy.homeDir` | `/config/userdata/.happy` | Happy runtime state directory (persists on the home PVC) |
|
||||
| `happy.experimental` | `true` | Enable experimental Happy features |
|
||||
|
||||
### Kubernetes cluster access
|
||||
|
||||
@@ -200,16 +200,16 @@ The devcontainer includes MCP (Model Context Protocol) servers as sidecar contai
|
||||
|---------|---------|---------|
|
||||
| `mcp.sidecars.kubernetes.enabled` | `true` | Kubernetes API access via MCP |
|
||||
| `mcp.sidecars.flux.enabled` | `true` | Flux GitOps operations via MCP |
|
||||
| `mcp.sidecars.github.enabled` | `false` | GitHub API access via MCP (DISABLED: archived image) |
|
||||
| `mcp.sidecars.homeassistant.enabled` | `false` | Home Assistant smart home control via MCP |
|
||||
| `mcp.sidecars.pgtuner.enabled` | `false` | PostgreSQL performance tuning and analysis via MCP |
|
||||
| `mcp.sidecars.playwright.enabled` | `true` | Browser automation and web testing via MCP |
|
||||
|
||||
**Notes:**
|
||||
- GitHub MCP is accessed via the Copilot API (`https://api.githubcopilot.com/mcp/`), not as a sidecar
|
||||
- Kubernetes and Flux sidecars require `clusterAccess` != `none` to be deployed (automatically disabled when no cluster access)
|
||||
- Kubernetes and Flux sidecars inherit the pod's ServiceAccount RBAC permissions (controlled by `clusterAccess`)
|
||||
- Home Assistant sidecar requires `homeassistant-url` and `homeassistant-token` in the env secret
|
||||
- PostgreSQL tuner sidecar requires `database-uri` in the env secret (PostgreSQL connection string)
|
||||
- Home Assistant sidecar requires `HOMEASSISTANT_URL` and `HOMEASSISTANT_TOKEN` in the env secret
|
||||
- PostgreSQL tuner sidecar requires `DATABASE_URI` in the env secret (PostgreSQL connection string)
|
||||
- Playwright sidecar provides browser automation and web testing capabilities
|
||||
|
||||
**Disable MCP sidecars:**
|
||||
@@ -263,62 +263,46 @@ helm install mydev ./chart \
|
||||
# values.yaml override
|
||||
mcp:
|
||||
sidecars:
|
||||
kubernetes:
|
||||
enabled: true
|
||||
image:
|
||||
repository: quay.io/containers/kubernetes_mcp_server
|
||||
tag: v0.0.57
|
||||
port: 8080
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
flux:
|
||||
enabled: false # Disabled in this example
|
||||
github:
|
||||
enabled: false # Disabled by default (archived image)
|
||||
homeassistant:
|
||||
enabled: true
|
||||
image:
|
||||
repository: ghcr.io/homeassistant-ai/ha-mcp
|
||||
tag: stable
|
||||
port: 8087
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
pgtuner:
|
||||
enabled: true
|
||||
image:
|
||||
repository: dog830228/pgtuner_mcp
|
||||
tag: latest
|
||||
port: 8085
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
playwright:
|
||||
enabled: true
|
||||
image:
|
||||
repository: microsoft/playwright-mcp
|
||||
tag: latest
|
||||
port: 8086
|
||||
resources:
|
||||
requests:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "1000m"
|
||||
kubernetes:
|
||||
enabled: true
|
||||
image:
|
||||
repository: quay.io/containers/kubernetes_mcp_server
|
||||
tag: v0.0.57
|
||||
port: 8080
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
flux:
|
||||
enabled: false # Disabled in this example
|
||||
homeassistant:
|
||||
enabled: true
|
||||
image:
|
||||
repository: ghcr.io/homeassistant-ai/ha-mcp
|
||||
tag: stable
|
||||
port: 8087
|
||||
pgtuner:
|
||||
enabled: true
|
||||
image:
|
||||
repository: dog830228/pgtuner_mcp
|
||||
tag: latest
|
||||
port: 8085
|
||||
playwright:
|
||||
enabled: true
|
||||
image:
|
||||
repository: mcr.microsoft.com/playwright/mcp
|
||||
tag: latest
|
||||
port: 8086
|
||||
resources:
|
||||
requests:
|
||||
memory: "128Mi"
|
||||
cpu: "100m"
|
||||
limits:
|
||||
memory: "512Mi"
|
||||
cpu: "1000m"
|
||||
```
|
||||
|
||||
### Display and resources
|
||||
@@ -327,9 +311,9 @@ mcp:
|
||||
|-------|---------|-------------|
|
||||
| `display.width` | `1920` | VNC width (px) |
|
||||
| `display.height` | `1080` | VNC height (px) |
|
||||
| `secureConnection` | `0` | Set to `1` if TLS is not terminated upstream |
|
||||
| `userId` | `1000` | UID for the app user |
|
||||
| `groupId` | `1000` | GID for the app user |
|
||||
| `display.secureConnection` | `0` | Set to `1` if TLS is not terminated upstream |
|
||||
| `user.id` | `1000` | UID for the app user |
|
||||
| `user.groupId` | `1000` | GID for the app user |
|
||||
| `storage.size` | `32Gi` | Home PVC size |
|
||||
| `storage.className` | `ceph-filesystem` | StorageClass (must be ReadWriteMany) |
|
||||
| `shm.sizeLimit` | `2Gi` | `/dev/shm` size (memory-backed; used by Electron apps) |
|
||||
@@ -362,10 +346,10 @@ Container start
|
||||
|
||||
| Mount | Source | Persistence |
|
||||
|-------|--------|-------------|
|
||||
| `/home` | ReadWriteMany PVC (`userhome-{name}`) | Survives pod restarts — stores Claude credentials, dotfiles, git config |
|
||||
| `/config` | ReadWriteMany PVC (`userhome-{name}`) | Survives pod restarts — stores Claude credentials, dotfiles, git config |
|
||||
| `/workspace` | `emptyDir` | Ephemeral — repo is re-cloned on each pod start |
|
||||
|
||||
Happy Coder's runtime state (`HAPPY_HOME_DIR`) is kept in `/home/user/.happy` on the persistent home PVC, so auth credentials and settings survive pod restarts when manually started.
|
||||
Happy Coder's runtime state (`HAPPY_HOME_DIR`) is kept in `/config/userdata/.happy` on the persistent home PVC, so auth credentials and settings survive pod restarts when manually started.
|
||||
|
||||
---
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
apiVersion: v2
|
||||
name: devcontainer
|
||||
description: Antigravity Dev Container with Happy Coder AI assistant
|
||||
description: Dev Container with AI coding agents and MCP sidecars
|
||||
type: application
|
||||
version: 0.3.2
|
||||
version: 0.4.7
|
||||
appVersion: "latest"
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
{{/*
|
||||
Resource name prefix: devcontainer-{name}
|
||||
*/}}
|
||||
{{- define "antigravity.fullname" -}}
|
||||
{{- define "devcontainer.fullname" -}}
|
||||
{{- printf "devcontainer-%s" .Values.name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PVC name: userhome-{name}
|
||||
*/}}
|
||||
{{- define "antigravity.pvcName" -}}
|
||||
{{- define "devcontainer.pvcName" -}}
|
||||
{{- printf "userhome-%s" .Values.name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Secret name for env vars, default to devcontainer-{name}-secrets-env
|
||||
*/}}
|
||||
{{- define "antigravity.envSecretName" -}}
|
||||
{{- define "devcontainer.envSecretName" -}}
|
||||
{{- .Values.envSecretName | default (printf "devcontainer-%s-secrets-env" .Values.name) }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "antigravity.labels" -}}
|
||||
{{- define "devcontainer.labels" -}}
|
||||
app: devcontainer
|
||||
instance: {{ .Values.name }}
|
||||
{{- end }}
|
||||
@@ -30,7 +30,7 @@ instance: {{ .Values.name }}
|
||||
{{/*
|
||||
Smart resource sizing based on enabled features
|
||||
*/}}
|
||||
{{- define "antigravity.smartResources" -}}
|
||||
{{- define "devcontainer.smartResources" -}}
|
||||
{{- $baseMemory := "2Gi" }}
|
||||
{{- $baseCpu := "1000m" }}
|
||||
{{- $limitMemory := "8Gi" }}
|
||||
@@ -59,7 +59,7 @@ limits:
|
||||
{{/*
|
||||
Auto-detect environment type and set smart defaults
|
||||
*/}}
|
||||
{{- define "antigravity.smartDefaults" -}}
|
||||
{{- define "devcontainer.smartDefaults" -}}
|
||||
{{- $isDev := or (contains "dev" .Values.name) (contains "test" .Values.name) (contains "local" .Values.name) }}
|
||||
{{- $isProd := or (contains "prod" .Values.name) (contains "production" .Values.name) }}
|
||||
{{- $isTeam := or (contains "team" .Values.name) (contains "shared" .Values.name) }}
|
||||
@@ -79,7 +79,7 @@ team: true
|
||||
{{/*
|
||||
Smart MCP sidecar selection based on cluster access
|
||||
*/}}
|
||||
{{- define "antigravity.mcpDefaults" -}}
|
||||
{{- define "devcontainer.mcpDefaults" -}}
|
||||
{{- if eq .Values.clusterAccess "none" }}
|
||||
{{/* No cluster access - disable k8s/flux sidecars */}}
|
||||
kubernetes:
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "antigravity.fullname" . }}
|
||||
name: {{ include "devcontainer.fullname" . }}
|
||||
labels:
|
||||
{{- include "antigravity.labels" . | nindent 4 }}
|
||||
{{- include "devcontainer.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "antigravity.labels" . | nindent 6 }}
|
||||
{{- include "devcontainer.labels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "antigravity.labels" . | nindent 8 }}
|
||||
{{- include "devcontainer.labels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- if ne (.Values.clusterAccess | default "none") "none" }}
|
||||
serviceAccountName: {{ include "antigravity.fullname" . }}
|
||||
serviceAccountName: {{ include "devcontainer.fullname" . }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
fsGroup: 1000
|
||||
@@ -81,7 +81,7 @@ spec:
|
||||
value: {{ .Values.githubRepo | quote }}
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: {{ include "antigravity.envSecretName" . }}
|
||||
name: {{ include "devcontainer.envSecretName" . }}
|
||||
optional: true
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
@@ -166,6 +166,48 @@ spec:
|
||||
resources:
|
||||
{{- toYaml .Values.mcp.sidecars.flux.resources | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.mcp.sidecars.fetch.enabled }}
|
||||
- name: fetch-mcp
|
||||
image: "{{ .Values.mcp.sidecars.fetch.image.repository }}:{{ .Values.mcp.sidecars.fetch.image.tag }}"
|
||||
imagePullPolicy: Always
|
||||
command: ["fastmcp", "run", "--transport", "sse", "--host", "0.0.0.0", "--port", "{{ .Values.mcp.sidecars.fetch.port }}"]
|
||||
ports:
|
||||
- name: fetch
|
||||
containerPort: {{ .Values.mcp.sidecars.fetch.port }}
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: {{ .Values.mcp.sidecars.fetch.port }}
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: {{ .Values.mcp.sidecars.fetch.port }}
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
resources:
|
||||
{{- toYaml .Values.mcp.sidecars.fetch.resources | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.mcp.sidecars.sequentialthinking.enabled }}
|
||||
- name: sequentialthinking-mcp
|
||||
image: "{{ .Values.mcp.sidecars.sequentialthinking.image.repository }}:{{ .Values.mcp.sidecars.sequentialthinking.image.tag }}"
|
||||
imagePullPolicy: Always
|
||||
command: ["fastmcp", "run", "--transport", "sse", "--host", "0.0.0.0", "--port", "{{ .Values.mcp.sidecars.sequentialthinking.port }}"]
|
||||
ports:
|
||||
- name: sequentialthinking
|
||||
containerPort: {{ .Values.mcp.sidecars.sequentialthinking.port }}
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: {{ .Values.mcp.sidecars.sequentialthinking.port }}
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: {{ .Values.mcp.sidecars.sequentialthinking.port }}
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
resources:
|
||||
{{- toYaml .Values.mcp.sidecars.sequentialthinking.resources | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.mcp.sidecars.homeassistant.enabled }}
|
||||
- name: homeassistant-mcp
|
||||
image: "{{ .Values.mcp.sidecars.homeassistant.image.repository }}:{{ .Values.mcp.sidecars.homeassistant.image.tag }}"
|
||||
@@ -178,13 +220,13 @@ spec:
|
||||
- name: HOMEASSISTANT_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "antigravity.envSecretName" . }}
|
||||
name: {{ include "devcontainer.envSecretName" . }}
|
||||
key: HOMEASSISTANT_URL
|
||||
optional: true
|
||||
- name: HOMEASSISTANT_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "antigravity.envSecretName" . }}
|
||||
name: {{ include "devcontainer.envSecretName" . }}
|
||||
key: HOMEASSISTANT_TOKEN
|
||||
optional: true
|
||||
livenessProbe:
|
||||
@@ -200,43 +242,11 @@ spec:
|
||||
resources:
|
||||
{{- toYaml .Values.mcp.sidecars.homeassistant.resources | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.mcp.sidecars.github.enabled }}
|
||||
- name: github-mcp
|
||||
image: "{{ .Values.mcp.sidecars.github.image.repository }}:{{ .Values.mcp.sidecars.github.image.tag }}"
|
||||
imagePullPolicy: Always
|
||||
args:
|
||||
- --sse
|
||||
- --port={{ .Values.mcp.sidecars.github.port }}
|
||||
ports:
|
||||
- name: github
|
||||
containerPort: {{ .Values.mcp.sidecars.github.port }}
|
||||
env:
|
||||
- name: GITHUB_PERSONAL_ACCESS_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "antigravity.envSecretName" . }}
|
||||
key: GITHUB_TOKEN
|
||||
optional: true
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: {{ .Values.mcp.sidecars.github.port }}
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: {{ .Values.mcp.sidecars.github.port }}
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
resources:
|
||||
{{- toYaml .Values.mcp.sidecars.github.resources | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.mcp.sidecars.pgtuner.enabled }}
|
||||
- name: pgtuner-mcp
|
||||
image: "{{ .Values.mcp.sidecars.pgtuner.image.repository }}:{{ .Values.mcp.sidecars.pgtuner.image.tag }}"
|
||||
imagePullPolicy: Always
|
||||
command: ["python", "-m", "pgtuner_mcp", "--transport", "sse", "--port", "{{ .Values.mcp.sidecars.pgtuner.port }}"]
|
||||
command: ["python", "-m", "pgtuner_mcp", "--mode", "sse", "--host", "0.0.0.0", "--port", "{{ .Values.mcp.sidecars.pgtuner.port }}"]
|
||||
ports:
|
||||
- name: pgtuner
|
||||
containerPort: {{ .Values.mcp.sidecars.pgtuner.port }}
|
||||
@@ -244,13 +254,13 @@ spec:
|
||||
- name: DATABASE_URI
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "antigravity.envSecretName" . }}
|
||||
name: {{ include "devcontainer.envSecretName" . }}
|
||||
key: DATABASE_URI
|
||||
optional: true
|
||||
- name: PGTUNER_EXCLUDE_USERIDS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "antigravity.envSecretName" . }}
|
||||
name: {{ include "devcontainer.envSecretName" . }}
|
||||
key: PGTUNER_EXCLUDE_USERIDS
|
||||
optional: true
|
||||
livenessProbe:
|
||||
@@ -270,9 +280,15 @@ spec:
|
||||
- name: playwright-mcp
|
||||
image: "{{ .Values.mcp.sidecars.playwright.image.repository }}:{{ .Values.mcp.sidecars.playwright.image.tag }}"
|
||||
imagePullPolicy: Always
|
||||
command: ["node"]
|
||||
args:
|
||||
- --transport
|
||||
- sse
|
||||
- cli.js
|
||||
- --headless
|
||||
- --browser
|
||||
- chromium
|
||||
- --no-sandbox
|
||||
- --host
|
||||
- 0.0.0.0
|
||||
- --port
|
||||
- {{ .Values.mcp.sidecars.playwright.port | quote }}
|
||||
ports:
|
||||
@@ -303,4 +319,4 @@ spec:
|
||||
sizeLimit: {{ .Values.shm.sizeLimit }}
|
||||
- name: userhome
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "antigravity.pvcName" . }}
|
||||
claimName: {{ include "devcontainer.pvcName" . }}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ include "antigravity.pvcName" . }}
|
||||
name: {{ include "devcontainer.pvcName" . }}
|
||||
labels:
|
||||
{{- include "antigravity.labels" . | nindent 4 }}
|
||||
{{- include "devcontainer.labels" . | nindent 4 }}
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{{- $access := .Values.clusterAccess | default "none" }}
|
||||
{{- $name := include "antigravity.fullname" . }}
|
||||
{{- $name := include "devcontainer.fullname" . }}
|
||||
{{- $ns := .Release.Namespace }}
|
||||
{{- $labels := include "antigravity.labels" . }}
|
||||
{{- $labels := include "devcontainer.labels" . }}
|
||||
|
||||
{{- if ne $access "none" }}
|
||||
---
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "antigravity.fullname" . }}
|
||||
name: {{ include "devcontainer.fullname" . }}
|
||||
labels:
|
||||
{{- include "antigravity.labels" . | nindent 4 }}
|
||||
{{- include "devcontainer.labels" . | nindent 4 }}
|
||||
spec:
|
||||
ports:
|
||||
{{- if ne (.Values.ide.type | default "vscode") "none" }}
|
||||
@@ -19,4 +19,4 @@ spec:
|
||||
targetPort: ssh
|
||||
{{- end }}
|
||||
selector:
|
||||
{{- include "antigravity.labels" . | nindent 4 }}
|
||||
{{- include "devcontainer.labels" . | nindent 4 }}
|
||||
|
||||
@@ -177,14 +177,17 @@
|
||||
"homeassistant": {
|
||||
"$ref": "#/$defs/mcpSidecar"
|
||||
},
|
||||
"github": {
|
||||
"$ref": "#/$defs/mcpSidecar"
|
||||
},
|
||||
"pgtuner": {
|
||||
"$ref": "#/$defs/mcpSidecar"
|
||||
},
|
||||
"playwright": {
|
||||
"$ref": "#/$defs/mcpSidecar"
|
||||
},
|
||||
"fetch": {
|
||||
"$ref": "#/$defs/mcpSidecar"
|
||||
},
|
||||
"sequentialthinking": {
|
||||
"$ref": "#/$defs/mcpSidecar"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@@ -195,6 +198,11 @@
|
||||
"envSecretName": {
|
||||
"type": "string",
|
||||
"description": "Custom environment secret name"
|
||||
},
|
||||
"resourceProfile": {
|
||||
"type": "string",
|
||||
"enum": ["auto", "small", "medium", "large", "xlarge"],
|
||||
"description": "Resource profile preset"
|
||||
}
|
||||
},
|
||||
"required": ["name"],
|
||||
@@ -256,4 +264,4 @@
|
||||
"required": ["enabled", "image", "port", "resources"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+27
-12
@@ -108,13 +108,13 @@ mcp:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
|
||||
# Home Assistant smart home control
|
||||
homeassistant:
|
||||
enabled: false # Requires HOMEASSISTANT_URL and HOMEASSISTANT_TOKEN
|
||||
# Web content fetching capabilities
|
||||
fetch:
|
||||
enabled: true
|
||||
image:
|
||||
repository: ghcr.io/homeassistant-ai/ha-mcp
|
||||
tag: stable
|
||||
port: 8087
|
||||
repository: mcp/fetch
|
||||
tag: latest
|
||||
port: 8082
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
@@ -123,13 +123,28 @@ mcp:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
|
||||
# GitHub API access (DISABLED: archived image)
|
||||
github:
|
||||
enabled: false
|
||||
# Sequential thinking and problem-solving
|
||||
sequentialthinking:
|
||||
enabled: true
|
||||
image:
|
||||
repository: ghcr.io/modelcontextprotocol/servers/github
|
||||
repository: mcp/sequentialthinking
|
||||
tag: latest
|
||||
port: 8088
|
||||
port: 8083
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "50m"
|
||||
limits:
|
||||
memory: "256Mi"
|
||||
cpu: "500m"
|
||||
|
||||
# Home Assistant smart home control
|
||||
homeassistant:
|
||||
enabled: false # Requires HOMEASSISTANT_URL and HOMEASSISTANT_TOKEN
|
||||
image:
|
||||
repository: ghcr.io/homeassistant-ai/ha-mcp
|
||||
tag: stable
|
||||
port: 8087
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
@@ -157,7 +172,7 @@ mcp:
|
||||
playwright:
|
||||
enabled: true
|
||||
image:
|
||||
repository: microsoft/playwright-mcp
|
||||
repository: mcr.microsoft.com/playwright/mcp
|
||||
tag: latest
|
||||
port: 8086
|
||||
resources:
|
||||
|
||||
Reference in New Issue
Block a user