Compare commits

...

31 Commits

Author SHA1 Message Date
github-actions[bot] e6c3b7f7bf chore(release): 2.1.0 [skip ci] 2026-02-27 02:11:16 +00:00
DevContainer User 41e270ec32 docs: update CLAUDE.md with gh, kubeseal, and Helm MCP sidecar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 02:08:24 +00:00
DevContainer User 05b06d1d90 feat: add gh CLI, kubeseal CLI, and Helm MCP sidecar
Install GitHub CLI (gh) via official APT repo and kubeseal via GitHub
Releases binary in the Dockerfile. Add mcp-helm sidecar on port 8088
for AI-assisted Helm chart browsing, with corresponding values, schema,
deployment template, and .mcp.json configuration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 01:26:05 +00:00
DevContainer User 8736d5b500 fix: clean up GitHub Actions workflows
- Enable GHA build cache across all workflows (replace no-cache: true)
- Add [skip ci] guard to build-and-push to prevent duplicate latest
  builds during releases
- Remove dead serverless branch trigger and build-routing-proxy job
- Remove unused id-token: write permission
- Add branch guard and contents: read permission to quick-fix workflow
- Fix release notes heredoc indentation so markdown renders correctly
- Fix git describe to use HEAD~1 for accurate changelog after version bump

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 01:17:33 +00:00
github-actions[bot] 713e5eebe6 chore(release): 2.0.5 [skip ci] 2026-02-27 00:59:31 +00:00
Chris Farhood 276477e245 fix: copy claude binary to /usr/local/bin instead of symlinking
Symlink left the original in ~/.local/bin which triggered a PATH
warning at runtime. Copy the binary and remove the original.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 19:11:33 -05:00
Chris Farhood 2136976b8e fix: symlink claude binary to /usr/local/bin after install
The installer puts claude in ~/.local/bin which isn't in PATH during
Docker build.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:54:45 -05:00
Chris Farhood e269e19f23 fix: pipe install script to bash, not sh
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:51:25 -05:00
Chris Farhood 3109de7e2e fix: switch Claude Code to native binary — npm wrapper breaks remote control
The npm-installed Claude Code runs via Node.js, which causes remote
control to fail with '/usr/bin/node: bad option: --sdk-url'. The native
binary handles subprocess spawning correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:48:57 -05:00
Chris Farhood 2b9350c86d fix: pin Claude Code to @latest tag and print version at build time
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:28:27 -05:00
Chris Farhood 5d62842aec fix: force fresh npm registry lookup for Claude Code install
npm was serving a cached older version even with Docker no-cache.
Clear npm cache and use --prefer-online to force a fresh registry fetch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:23:06 -05:00
Chris Farhood 58719cf262 fix: disable all Docker layer caching in CI
GHA cache was serving stale npm install layers despite cache-bust ARG.
Remove all caching — every build is now fully clean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:14:15 -05:00
github-actions[bot] c066aa49be chore(release): 2.0.4 [skip ci] 2026-02-25 23:00:36 +00:00
Chris Farhood 204a673b3d chore: remove 2.0.0-dev image tag from CI
No longer needed — main builds tag as latest only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:52:35 -05:00
Chris Farhood 04ed52bc8d fix: default image tag to latest — 2.0.0-dev was stale
The 2.0.0-dev tag was only built from the now-merged
feature/serverless-2.0.0 branch. Pushes to main only tagged latest,
so the 2.0.0-dev image in the registry was frozen and missing all
recent fixes. Default to latest and also tag main builds as 2.0.0-dev
for backwards compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:50:19 -05:00
Chris Farhood c670dd124f fix: ensure Claude Code updates on rebuild and allow GITHUB_REPO from secret
Two fixes:
- Move Claude Code npm install below TOOLS_CACHEBUST ARG so it actually
  gets refreshed when the cache-bust value changes
- Make GITHUB_REPO env conditional so an empty Helm value no longer
  overrides the value provided via the Kubernetes secret (envFrom)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:36:57 -05:00
Chris Farhood 219af987ae fix: revert Claude Code back to npm install — binary download breaks container
The direct GCS binary download approach has been unreliable across
multiple attempts. Revert to the proven npm install method. Node.js
is already required for Happy Coder so there is no extra dependency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 15:03:47 -05:00
DevContainer User c70352dc41 fix: use direct binary download for Claude Code instead of npm
npm install fails in CI due to native dependency compilation issues.
Download the pre-built binary directly from the official GCS distribution
bucket with SHA256 checksum verification. This approach worked previously
(run #135) and avoids npm entirely — Node.js is only needed for Happy Coder.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 19:20:46 +00:00
DevContainer User f689b27b78 fix: revert Claude Code to npm install — native installer unreliable
The native binary installer (both direct GCS download and claude.ai/install.sh)
has been unreliable during Docker builds. Revert to the proven npm approach.
Node.js is already required for Happy Coder, so there's no extra dependency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 19:11:36 +00:00
DevContainer User a978b505d0 fix: use official Claude Code installer instead of raw GCS bucket URL
The previous native installer approach used a direct GCS bucket download
that was fragile and failing during builds. Switch to the official
install script (claude.ai/install.sh) which handles version discovery,
platform detection, and checksum verification properly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 18:42:17 +00:00
github-actions[bot] 69497b1ec6 chore(release): 2.0.3 [skip ci] 2026-02-25 16:46:05 +00:00
DevContainer User 698c5810a0 fix: update VSCode install to use Microsoft's current repo setup
The legacy GPG key import and .list format was failing with exit code 100
in CI. Switch to the DEB822 .sources format and install -D key method
per Microsoft's current documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 16:39:24 +00:00
github-actions[bot] 2582c1d824 chore(release): 2.0.2 [skip ci] 2026-02-25 16:29:21 +00:00
DevContainer User 6dd560f2ad fix: bust Docker cache for tools that fetch latest versions
The native Claude Code installer (and other tools) fetch "latest" at
build time, but Docker layer caching serves stale layers because the
RUN command text never changes. Add TOOLS_CACHEBUST build arg with
github.run_id so every CI run re-downloads fresh tool binaries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 16:16:14 +00:00
github-actions[bot] 19d47da079 chore(release): 2.0.1-dev [skip ci] 2026-02-25 15:30:05 +00:00
DevContainer User 12d3444cc5 feat: switch Claude Code to native installer
Replace npm-based Claude Code installation with the native binary
installer. Downloads directly from Anthropic's distribution bucket to
/usr/local/bin/claude — no Node.js dependency for Claude Code anymore.
Node.js is retained for Happy Coder only.

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>
2026-02-25 15:29:14 +00:00
Chris Farhood eeb995e1fc Merge pull request #53 from cpfarhood/feat/helm-github-pages
feat: switch Helm repo to GitHub Pages
2026-02-25 08:55:27 -05:00
Chris Farhood d26b69c587 Merge pull request #52 from cpfarhood/feature/serverless-2.0.0
feat: DevContainer 2.0.0-dev with serverless architecture and unified Helm chart
2026-02-25 08:55:16 -05:00
DevContainer User da40d57e07 fix: overhaul release pipeline — 5 issues resolved
1. version input now optional — auto-increment from release_type works
2. replaced deprecated actions/create-release@v1 with gh release create
3. race condition fixed — release commit uses [skip ci], removed fragile
   github.actor guard from build-and-push.yaml
4. simplified gh-pages publishing — uses clean temp dir + shallow clone
   instead of convoluted git worktree fallback
5. version parsing strips pre-release suffixes (e.g., 2.0.0-dev → 2.0.0)

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>
2026-02-25 13:53:58 +00:00
DevContainer User e99ec65cd9 docs: update all references from OCI registry to GitHub Pages Helm repo
Update CLAUDE.md, README.md, and workflows README to reference the new
GitHub Pages Helm repository at https://cpfarhood.github.io/devcontainer
instead of the old OCI registry at oci://ghcr.io/cpfarhood/charts.

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>
2026-02-25 13:38:03 +00:00
DevContainer User 38e481484e feat: switch Helm chart publishing from OCI registry to GitHub Pages
Replaces OCI push (oci://ghcr.io/cpfarhood/charts) with GitHub Pages
Helm repository at https://cpfarhood.github.io/devcontainer. The release
workflow now packages the chart, maintains an index.yaml on the gh-pages
branch, and auto-creates the branch on first run.

Usage: helm repo add devcontainer https://cpfarhood.github.io/devcontainer

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>
2026-02-25 13:34:56 +00:00
12 changed files with 202 additions and 137 deletions
+3 -4
View File
@@ -15,9 +15,8 @@ Use this for all version releases:
- ✅ Updates chart version
- ✅ Creates git tag
- ✅ Builds Docker image with all proper tags
- ✅ Publishes Helm chart to GHCR
- ✅ Publishes Helm chart to GitHub Pages (`https://cpfarhood.github.io/devcontainer`)
- ✅ Creates GitHub Release with changelog
- ✅ No more `[skip ci]` blocking builds!
### 2️⃣ For Quick Fixes → **Quick Fix Build**
Use this for emergency fixes without version changes:
@@ -30,8 +29,8 @@ Use this for emergency fixes without version changes:
### 3️⃣ Automatic CI → **Build and Push**
Runs automatically on:
- Pushes to `main` (builds and pushes; skipped for release commits via `[skip ci]`)
- Pull requests (builds but doesn't push)
- Tags starting with `v*` (builds and pushes)
- Manual trigger available
## Workflow Files
@@ -90,5 +89,5 @@ gh run watch
### After (Simple! 🎉)
- **3 total workflows** (down from 6+)
- **1 button** for complete releases
- **No more `[skip ci]`** blocking builds
- Release builds its own Docker image — `[skip ci]` on the version commit prevents duplicate CI builds
- **Clear separation** of concerns
+3 -52
View File
@@ -4,7 +4,6 @@ on:
push:
branches:
- main
- 'feature/serverless-*' # Build development images for serverless features
pull_request:
branches:
- main
@@ -17,13 +16,12 @@ 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]'
if: >-
github.event_name != 'push'
|| !contains(github.event.head_commit.message, '[skip ci]')
permissions:
contents: read
packages: write
id-token: write
steps:
- name: Checkout repository
@@ -50,8 +48,6 @@ jobs:
type=ref,event=pr
type=sha,prefix=sha-
type=raw,value=latest,enable={{is_default_branch}}
# Development tags for serverless features
type=raw,value=2.0.0-dev,enable=${{ github.ref == 'refs/heads/feature/serverless-2.0.0' }}
- name: Build and push Docker image
uses: docker/build-push-action@v6
@@ -63,48 +59,3 @@ jobs:
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64
# Build routing proxy image for serverless features
build-routing-proxy:
runs-on: ubuntu-latest
# Only build routing proxy for serverless feature branches
if: github.ref == 'refs/heads/feature/serverless-2.0.0' && github.event_name != 'pull_request'
permissions:
contents: read
packages: write
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for routing proxy
id: meta-proxy
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/cpfarhood/devcontainer-routing-proxy
tags: |
type=raw,value=latest
type=raw,value=2.0.0-dev
type=sha,prefix=sha-
- name: Build and push routing proxy image
uses: docker/build-push-action@v6
with:
context: ./serverless/routing-proxy
push: true
tags: ${{ steps.meta-proxy.outputs.tags }}
labels: ${{ steps.meta-proxy.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64
+2
View File
@@ -16,7 +16,9 @@ env:
jobs:
build:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
permissions:
contents: read
packages: write
steps:
+88 -54
View File
@@ -4,11 +4,11 @@ on:
workflow_dispatch:
inputs:
version:
description: 'Version to release (e.g., 0.1.25)'
required: true
description: 'Explicit version (e.g., 1.2.3). Leave blank to auto-increment.'
required: false
type: string
release_type:
description: 'Release type'
description: 'Release type (used when version is blank)'
required: true
default: 'patch'
type: choice
@@ -49,37 +49,34 @@ jobs:
- name: Determine Version
id: version
run: |
if [ "${{ github.event.inputs.version }}" != "" ]; then
VERSION="${{ github.event.inputs.version }}"
INPUT_VERSION="${{ github.event.inputs.version }}"
if [ -n "$INPUT_VERSION" ]; then
VERSION="$INPUT_VERSION"
else
# Auto-determine next version based on release type
# Auto-increment based on release_type
CURRENT=$(grep '^version:' chart/Chart.yaml | awk '{print $2}')
MAJOR=$(echo $CURRENT | cut -d. -f1)
MINOR=$(echo $CURRENT | cut -d. -f2)
PATCH=$(echo $CURRENT | cut -d. -f3)
# Strip any pre-release suffix (e.g., 2.0.0-dev -> 2.0.0)
CURRENT=$(echo "$CURRENT" | sed 's/-.*//')
MAJOR=$(echo "$CURRENT" | cut -d. -f1)
MINOR=$(echo "$CURRENT" | cut -d. -f2)
PATCH=$(echo "$CURRENT" | cut -d. -f3)
case "${{ github.event.inputs.release_type }}" in
major)
VERSION="$((MAJOR + 1)).0.0"
;;
minor)
VERSION="${MAJOR}.$((MINOR + 1)).0"
;;
patch)
VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))"
;;
major) VERSION="$((MAJOR + 1)).0.0" ;;
minor) VERSION="${MAJOR}.$((MINOR + 1)).0" ;;
patch) VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))" ;;
esac
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "tag=v${VERSION}" >> $GITHUB_OUTPUT
echo "🚀 Releasing version ${VERSION}"
echo "Releasing version ${VERSION}"
- name: Update Chart Version
run: |
sed -i "s/^version: .*/version: ${{ steps.version.outputs.version }}/" chart/Chart.yaml
git add chart/Chart.yaml
git diff --quiet --staged || git commit -m "chore: release version ${{ steps.version.outputs.version }}"
git diff --quiet --staged || git commit -m "chore(release): ${{ steps.version.outputs.version }} [skip ci]"
- name: Create and Push Tag
run: |
@@ -107,53 +104,90 @@ jobs:
cache-to: type=gha,mode=max
platforms: linux/amd64
- name: Package Helm Chart
- name: Publish Helm Chart to GitHub Pages
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
CHART_TGZ="devcontainer-${{ steps.version.outputs.version }}.tgz"
- name: Generate Release Notes
id: notes
# Set up gh-pages in a temporary directory
PAGES_DIR=$(mktemp -d)
if git ls-remote --heads origin gh-pages | grep -q gh-pages; then
# gh-pages exists — shallow clone just that branch
git clone --single-branch --branch gh-pages \
"https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" \
"$PAGES_DIR"
else
# First time — initialize gh-pages
git init "$PAGES_DIR"
git -C "$PAGES_DIR" checkout --orphan gh-pages
git -C "$PAGES_DIR" remote add origin \
"https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git"
cat > "$PAGES_DIR/index.html" <<'HTMLEOF'
<!DOCTYPE html>
<html>
<head><title>Dev Container Helm Chart Repository</title></head>
<body>
<h1>Dev Container Helm Chart Repository</h1>
<p>Add this repository to Helm:</p>
<pre>helm repo add devcontainer https://cpfarhood.github.io/devcontainer</pre>
<p>Install the chart:</p>
<pre>helm install mydev devcontainer/devcontainer --set name=mydev</pre>
</body>
</html>
HTMLEOF
fi
git -C "$PAGES_DIR" config user.name "github-actions[bot]"
git -C "$PAGES_DIR" config user.email "github-actions[bot]@users.noreply.github.com"
# Copy chart package and rebuild index
cp "$CHART_TGZ" "$PAGES_DIR/"
if [ -f "$PAGES_DIR/index.yaml" ]; then
helm repo index "$PAGES_DIR" --url https://cpfarhood.github.io/devcontainer --merge "$PAGES_DIR/index.yaml"
else
helm repo index "$PAGES_DIR" --url https://cpfarhood.github.io/devcontainer
fi
# Commit and push
git -C "$PAGES_DIR" add .
git -C "$PAGES_DIR" commit -m "Publish chart ${{ steps.version.outputs.version }}"
git -C "$PAGES_DIR" push origin gh-pages
- name: Create GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Get commits since last tag
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
# Build release notes
PREV_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
if [ -z "$PREV_TAG" ]; then
COMMITS=$(git log --pretty=format:"- %s (%h)" HEAD)
else
COMMITS=$(git log --pretty=format:"- %s (%h)" ${PREV_TAG}..HEAD)
COMMITS=$(git log --pretty=format:"- %s (%h)" "${PREV_TAG}..HEAD")
fi
cat << EOF > release-notes.md
## 🚀 Release ${{ steps.version.outputs.version }}
cat > release-notes.md <<'NOTESEOF'
## Release RELEASE_VERSION
### Changes
${COMMITS}
RELEASE_COMMITS
### Docker Image
\`\`\`bash
docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.tag }}
\`\`\`
```bash
docker pull RELEASE_IMAGE
```
### Helm Chart
\`\`\`bash
helm install devcontainer oci://ghcr.io/cpfarhood/charts/devcontainer --version ${{ steps.version.outputs.version }}
\`\`\`
EOF
```bash
helm repo add devcontainer https://cpfarhood.github.io/devcontainer
helm repo update
helm install mydev devcontainer/devcontainer --version RELEASE_VERSION --set name=mydev
```
NOTESEOF
sed -i 's/^ //' release-notes.md
sed -i "s|RELEASE_VERSION|${{ steps.version.outputs.version }}|g" release-notes.md
sed -i "s|RELEASE_IMAGE|${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.tag }}|g" release-notes.md
sed -i "s|RELEASE_COMMITS|${COMMITS}|g" release-notes.md
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
gh release create "${{ steps.version.outputs.tag }}" \
--title "Release ${{ steps.version.outputs.tag }}" \
--notes-file release-notes.md
+3 -4
View File
@@ -19,10 +19,9 @@
"type": "sse",
"url": "http://localhost:8086/sse"
},
"pgtuner": {
"helm": {
"type": "sse",
"url": "http://localhost:8085/sse"
"url": "http://localhost:8088/sse"
}
}
}
}
+12 -4
View File
@@ -69,7 +69,7 @@ Container start
| File | Purpose |
|------|---------|
| `Dockerfile` | Image definition — installs Chrome, Node.js, VSCode, Helm, Claude Code, Happy Coder, OpenCode, Crush; creates non-root user (UID 1000) |
| `Dockerfile` | Image definition — installs Chrome, Node.js, VSCode, Helm, gh CLI, kubeseal, Claude Code, Happy Coder, OpenCode, Crush; creates non-root user (UID 1000) |
| `scripts/init-repo.sh` | Configures git credentials, clones GitHub repo |
| `scripts/startapp.sh` | Calls init-repo.sh then opens VSCode in the workspace |
| `chart/` | Helm chart for Kubernetes deployment |
@@ -78,7 +78,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 (GitHub Copilot, Kubernetes, Flux, Fetch, Sequential Thinking, Playwright, pgtuner) |
| `.mcp.json` | MCP server connection config (GitHub Copilot, Kubernetes, Flux, Helm, Fetch, Sequential Thinking, Playwright, pgtuner) |
| `Makefile` | Build/deploy automation |
### MCP Sidecars
@@ -89,6 +89,7 @@ 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 |
| `helm-mcp` | `ghcr.io/zekker6/mcp-helm` | v1.3.1 | 8088 | `http://localhost:8088/sse` | Enabled |
| `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 |
@@ -99,6 +100,7 @@ MCP (Model Context Protocol) servers run as sidecar containers in the pod, enabl
- 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
- Helm sidecar enables browsing Helm repositories and chart metadata
- 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
@@ -117,6 +119,8 @@ mcp:
enabled: false
flux:
enabled: false
helm:
enabled: false
fetch:
enabled: false
sequentialthinking:
@@ -135,6 +139,8 @@ mcp:
enabled: true # Keep Kubernetes MCP enabled
flux:
enabled: false # Disable Flux MCP
helm:
enabled: true # Enable Helm MCP for chart browsing
fetch:
enabled: true # Enable Fetch MCP for web content fetching
sequentialthinking:
@@ -190,14 +196,16 @@ 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. For version tags, also creates GitHub Release with Helm chart after Docker build completes. Tags: `latest` (main), semver, branch name, commit SHA.
- **`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-unified.yaml`** — Manual release workflow: bumps chart version, builds Docker image, publishes Helm chart to GitHub Pages (`https://cpfarhood.github.io/devcontainer`), and creates GitHub Release.
- **`dependabot.yml`** — Weekly updates for GitHub Actions and Docker base image.
Image registry: `ghcr.io/cpfarhood/devcontainer`
Helm repo: `https://cpfarhood.github.io/devcontainer`
## Kubernetes Notes
- Deployed via Helm chart (`chart/`), published as OCI artifact to GHCR, reconciled by Flux
- Deployed via Helm chart (`chart/`), published to GitHub Pages Helm repo, reconciled by Flux
- Storage class is `ceph-filesystem` by default — change via `storage.className` in values
- Resource limits: 14 CPU, 28Gi memory
- Health checks (liveness/readiness probes) on port 5800
+29 -6
View File
@@ -56,13 +56,19 @@ exec /usr/bin/google-chrome-stable \\\n\
"$@"\n' > /usr/local/bin/google-chrome && \
chmod +x /usr/local/bin/google-chrome
# Install Node.js (LTS version for Happy Coder)
# Install Node.js LTS (required by 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 and Claude Code globally
RUN npm install -g happy-coder @anthropic-ai/claude-code
# Install Happy Coder globally via npm (stable, rarely changes)
RUN npm install -g happy-coder
# Install Claude Code native binary (npm wrapper breaks remote control)
RUN curl -fsSL https://claude.ai/install.sh | bash && \
cp /root/.local/bin/claude /usr/local/bin/claude && \
rm -rf /root/.local/bin/claude && \
claude --version
# Install OpenCode AI coding agent
RUN OPENCODE_VERSION=$(curl -sL https://api.github.com/repos/opencode-ai/opencode/releases/latest | jq -r '.tag_name') && \
@@ -84,9 +90,26 @@ RUN curl -fsSL "https://get.helm.sh/helm-v${HELM_VERSION}-linux-amd64.tar.gz" |
tar -xz --strip-components=1 -C /usr/local/bin linux-amd64/helm && \
chmod +x /usr/local/bin/helm
# Install VSCode
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 && \
# Install GitHub CLI (gh) via official APT repo
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && \
chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && \
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" > /etc/apt/sources.list.d/github-cli.list && \
apt-get update && \
apt-get install -y gh && \
rm -rf /var/lib/apt/lists/*
# Install kubeseal CLI for Bitnami Sealed Secrets
RUN KUBESEAL_VERSION=$(curl -sL https://api.github.com/repos/bitnami-labs/sealed-secrets/releases/latest | jq -r '.tag_name' | sed 's/^v//') && \
curl -fsSL "https://github.com/bitnami-labs/sealed-secrets/releases/download/v${KUBESEAL_VERSION}/kubeseal-${KUBESEAL_VERSION}-linux-amd64.tar.gz" | \
tar -xz -C /usr/local/bin kubeseal && \
chmod +x /usr/local/bin/kubeseal
# Install VSCode (using Microsoft's current recommended setup)
RUN wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /tmp/microsoft.gpg && \
install -D -o root -g root -m 644 /tmp/microsoft.gpg /usr/share/keyrings/microsoft.gpg && \
rm -f /tmp/microsoft.gpg && \
printf 'Types: deb\nURIs: https://packages.microsoft.com/repos/code\nSuites: stable\nComponents: main\nArchitectures: amd64\nSigned-By: /usr/share/keyrings/microsoft.gpg\n' \
> /etc/apt/sources.list.d/vscode.sources && \
apt-get update && \
apt-get install -y code && \
rm -rf /var/lib/apt/lists/*
+17 -10
View File
@@ -14,23 +14,30 @@ A containerized cloud development environment with web-based GUI access, featuri
## Quick Start
### Option A: Quickstart (Recommended)
For 80% of users, use the simplified quickstart values:
### Option A: Install from Helm Repo (Recommended)
```bash
# Copy and customize the quickstart template
# Add the Helm repository
helm repo add devcontainer https://cpfarhood.github.io/devcontainer
helm repo update
# Deploy with one command
helm install mydev devcontainer/devcontainer \
--set name=mydev \
--set githubRepo=https://github.com/youruser/yourrepo
```
### Option B: Install from Source
```bash
# Clone and customize the quickstart template
cp chart/values-quickstart.yaml my-values.yaml
# Edit my-values.yaml to set your name and repository
# Edit my-values.yaml to set your name and repository:
# name: mydev
# githubRepo: https://github.com/youruser/yourrepo
# Deploy with minimal configuration
helm install mydev ./chart -f my-values.yaml
```
### Option B: One-Command Deploy
### Option C: One-Command from Source
```bash
helm install mydev ./chart \
+1 -1
View File
@@ -2,7 +2,7 @@ apiVersion: v2
name: devcontainer
description: Dev Container with AI coding agents and MCP sidecars - supports persistent and dynamic deployment modes
type: application
version: 2.0.0-dev
version: 2.1.0
appVersion: "latest"
keywords:
- development
+25
View File
@@ -88,8 +88,10 @@ spec:
value: {{ .Values.happy.serverUrl | quote }}
- name: HAPPY_WEBAPP_URL
value: {{ .Values.happy.webappUrl | quote }}
{{- if .Values.githubRepo }}
- name: GITHUB_REPO
value: {{ .Values.githubRepo | quote }}
{{- end }}
envFrom:
- secretRef:
name: {{ include "devcontainer.envSecretName" . }}
@@ -177,6 +179,29 @@ spec:
resources:
{{- toYaml .Values.mcp.sidecars.flux.resources | nindent 12 }}
{{- end }}
{{- if .Values.mcp.sidecars.helm.enabled }}
- name: helm-mcp
image: "{{ .Values.mcp.sidecars.helm.image.repository }}:{{ .Values.mcp.sidecars.helm.image.tag }}"
args:
- -mode=sse
- -port={{ .Values.mcp.sidecars.helm.port }}
ports:
- containerPort: {{ .Values.mcp.sidecars.helm.port }}
name: helm-mcp
protocol: TCP
livenessProbe:
tcpSocket:
port: {{ .Values.mcp.sidecars.helm.port }}
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
tcpSocket:
port: {{ .Values.mcp.sidecars.helm.port }}
initialDelaySeconds: 5
periodSeconds: 5
resources:
{{- toYaml .Values.mcp.sidecars.helm.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 }}"
+3
View File
@@ -270,6 +270,9 @@
"pgtuner": {
"$ref": "#/$defs/mcpSidecar"
},
"helm": {
"$ref": "#/$defs/mcpSidecar"
},
"playwright": {
"$ref": "#/$defs/mcpSidecar"
}
+16 -2
View File
@@ -13,7 +13,7 @@ deploymentMode: persistent # persistent | dynamic
# Container image configuration
image:
repository: ghcr.io/cpfarhood/devcontainer
tag: 2.0.0-dev
tag: latest
pullPolicy: Always
# GitHub repository to clone into /workspace (ignored in dynamic mode - uses URL routing)
@@ -124,6 +124,20 @@ mcp:
cpu: "500m"
# Helm chart browsing and management
helm:
enabled: true
image:
repository: ghcr.io/zekker6/mcp-helm
tag: v1.3.1
port: 8088
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "256Mi"
cpu: "500m"
# Home Assistant smart home control
homeassistant:
@@ -217,7 +231,7 @@ dynamic:
replicas: 2 # High availability
image:
repository: ghcr.io/cpfarhood/devcontainer-routing-proxy
tag: 2.0.0-dev
tag: latest
pullPolicy: Always
resources: