IDEKUBE runs a fleet of browser-accessible developer environments — JupyterLab, Coder/VS Code, full Linux desktop (XFCE + noVNC), and AI-agent shells (Claude Code, opencode, Hermes) — on your own Kubernetes cluster. A self-hosted alternative to GitHub Codespaces, Gitpod, and Coder Cloud, built for small engineering teams and research labs that need per-user dev environments, shared GPUs/NPUs, and on-prem control. Runs on NVIDIA GPUs and Huawei Ascend NPUs; field-tested at SPEIT (Shanghai Jiao Tong University Paris Elite Institute of Technology).
This is the meta-repository that owns the centralized build system. Image repos under images/ remain independently versioned submodules but are driven from this repo's docker-bake.hcl.
- Small engineering teams (5–50 devs) who want Codespaces-style ephemeral dev containers without paying per-seat and without sending source to a SaaS.
- Research labs and university courses that need to give each student or researcher their own JupyterLab, IDE, and Linux desktop on shared GPUs or NPUs.
- AI / agent teams running Claude Code, opencode, or custom agents as a fleet — each agent gets an isolated container with a full developer toolchain.
- Robotics & simulation groups who need ROS 2 Jazzy, Gazebo, MoveIt, and Kathara network labs in a reproducible browser-accessible image.
- Self-hosted GitHub Codespaces / Gitpod / Coder Cloud alternative on your own Kubernetes cluster
- Shared GPU JupyterLab fleet for an ML research lab
- Per-student browser desktops for a university course (SPEIT runs the fleet at scale)
- AI-agent sandboxes: one Claude Code or opencode container per task or per user
- ROS 2 + Gazebo browser desktops for distributed robotics teams
- Network-emulation labs (Kathara) with no per-laptop setup
- Ascend NPU notebooks for teams on Huawei hardware
Note on the "gherkin badge": the test suite is pytest + Playwright, not a Gherkin/BDD framework (Cucumber, behave, pytest-bdd, etc.), so a Gherkin-feature-count or Cucumber-report badge is not applicable.
| Path | Description |
|---|---|
docker-bake.hcl |
All bake targets, groups, dependency DAG, build args |
docker-bake.staging.hcl |
Staging override (sets STAGING_POSTFIX="-staging") |
docker-bake.production.hcl |
Production override (GHA cache) |
Makefile |
Thin wrappers around docker buildx bake + tests |
tests/ |
pytest + Playwright suite, parametrized per branch |
.github/workflows/publish.yml |
Staging CI for PRs, main, and manual dispatch |
.github/workflows/publish-production.yml |
Production publish on releases or manual dispatch |
scripts/tag-stable.sh |
Post-publish stable-tag aliasing helper |
qemu-builder/ |
QEMU/Ansible nested-VM build pipeline |
| Submodule | Repository | Description |
|---|---|---|
artifacts/ |
idekube-container-artifacts | Shared install scripts and common rootfs overlay |
frontend/ |
idekube-container-frontend | Vue.js landing page (built inside Docker via named context) |
healthcheck/ |
idekube-container-healthcheck | Go health check server (compiled inside Docker via named context) |
| Submodule | GHCR repo | Variants | Base |
|---|---|---|---|
images/featured-base/ |
idekube-container-featured-base |
base |
ubuntu:24.04 / ascendai/cann |
images/featured/ |
idekube-container-featured |
speit, speit-ai, dind, kathara, ros2 |
featured/base |
images/coder-base/ |
idekube-container-coder-base |
base |
ubuntu:24.04 |
images/coder/ |
idekube-container-coder |
conda |
coder/base |
images/jupyter-base/ |
idekube-container-jupyter-base |
base |
ubuntu:24.04 / ascendai/cann |
images/jupyter/ |
idekube-container-jupyter |
speit-ai |
jupyter/base |
images/agent-base/ |
idekube-container-agent-base |
base |
ubuntu:24.04 |
images/agent/ |
idekube-container-agent |
openclaw, hermes |
agent/base |
featured/— Full Linux desktop in a browser: Coder IDE + noVNC (TurboVNC + VirtualGL) + SSH. Variants:base,speit,speit-ai,dind,kathara,ros2coder/— Coder / VS Code IDE only + SSH. Variants:base,condajupyter/— JupyterLab notebook server only + SSH. Variants:base,speit-aiagent/— AI-agent runtime (Claude Code + opencode + document processing) + ttyd web terminal + SSH. Variants:base,openclaw,hermes
All services are reverse-proxied by Nginx on port 80:
| Endpoint | Service |
|---|---|
/ |
Landing page (auto-detects available services) |
/coder |
Coder service |
/jupyter |
Jupyter service |
/vnc |
noVNC service |
/agent |
openclaw agent gateway |
/terminal |
ttyd web terminal |
/ssh |
Websocat-proxied SSH |
/health |
Health check endpoint (no auth, JSON, for k8s probes) |
docker buildx bake reads docker-bake.hcl from the meta-repo root and:
- Walks the dependency DAG via
target:named contexts (no separate Python orchestrator). - Sets
--build-context artifacts=./artifacts,--build-context healthcheck-src=./healthcheck,--build-context frontend-src=./frontendon every target so each Dockerfile only references its own image-repo tree. - For matrix-expanded dual-lineup images, generates
<name>-universaland<name>-ascendvariants with the rightBASE_IMAGEandplatforms. - Tags base repos as
<VERSION>[-ascend][-staging]and application repos as<variant>-<VERSION>[-ascend][-staging].
Bake schedules independent targets in parallel and resolves dependencies automatically.
featured/base ──> featured/speit
──> featured/speit-ai
──> featured/dind ──> featured/kathara
──> featured/ros2
coder/base ──> coder/conda
jupyter/base ──> jupyter/speit-ai
agent/base ──> agent/openclaw
──> agent/hermes
git clone --recurse-submodules https://github.com/idekube-project/idekube-container.git
cd idekube-container
make prepare# Single target, host arch, loaded into local docker
make bake TARGET=featured-base-universal
make bake TARGET=agent-openclaw
# Inspect the bake plan as JSON
make discover GROUP=universal# Builds for both linux/amd64 and linux/arm64
make bake-staging GROUP=universal
# Or push to GHCR with -staging tag postfix
make push-staging GROUP=universal# After git tag v1.0.0:
VERSION=v1.0.0 make push-production GROUP=universal
VERSION=v1.0.0 make push-production GROUP=ascend
# Then alias base images as stable
make tag-stable BRANCH=featured/base VERSION=v1.0.0 LINEUP=universal
make tag-stable BRANCH=coder/base VERSION=v1.0.0 LINEUP=universal
make tag-stable BRANCH=jupyter/base VERSION=v1.0.0 LINEUP=universal
make tag-stable BRANCH=agent/base VERSION=v1.0.0 LINEUP=universal
make tag-stable BRANCH=featured/base VERSION=v1.0.0 LINEUP=ascend
make tag-stable BRANCH=jupyter/base VERSION=v1.0.0 LINEUP=ascendIn CI, GitHub releases and manual dispatches trigger the production workflow; PRs and pushes to main trigger the staging workflow.
Both publish workflows take two workflow_dispatch inputs:
lineup—universal,ascend, orboth(default). Used whentargetsis empty.targets— bake target or group name. Empty (default) falls back tolineup; non-empty overrides.
When targets is set, exactly one runner job runs (the universal leg — the default leg) and builds whatever the targets value resolves to. The matrix leg label is just the runner slot, not a filter on what's built: a group like agent-ascend or agent-base-all still produces its ascend images, built via qemu on the amd64 runner.
| Want to build… | Pass targets = |
|---|---|
| Just one image variant | agent-base-ascend, featured-speit, … (any single target name) |
| Both lineups of one variant | <branch>-all (e.g. agent-base-all) |
| One flavor × one lineup | <flavor>-<lineup> (e.g. agent-ascend, featured-universal) |
| Whole flavor across lineups | featured, coder, jupyter, agent |
| Whole lineup | universal, ascend |
| Everything | leave targets empty + lineup=both |
Run make discover GROUP=universal (or any other group name) to print the bake plan and confirm a group's contents before dispatching. In production, the tag-stable step is skipped when targets is set; run scripts/tag-stable.sh manually if you need a stable alias from a scoped build.
# docker-compose.yml
services:
idekube_container:
image: ghcr.io/idekube-project/idekube-container-featured-base:stable
ports:
- "3000:80"
volumes:
- idekube_volume:/home/idekube
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: ["gpu"]
ipc: host
volumes:
idekube_volume:
driver: localPre-built multi-arch container images are published on GitHub Container Registry (GHCR) — pull directly into your Kubernetes cluster.
| Image | Repo | Variant tag | Description |
|---|---|---|---|
featured-base |
idekube-container-featured-base |
<version> |
Full desktop (XFCE + noVNC) + Coder + SSH + Miniconda + VirtualGL |
featured-speit |
idekube-container-featured |
speit-<version> |
+ dev tools + Python scientific stack + Iverilog + Digital |
featured-speit-ai |
idekube-container-featured |
speit-ai-<version> |
+ dev tools + PyTorch conda environment |
featured-dind |
idekube-container-featured |
dind-<version> |
+ Docker-in-Docker (dockerd, buildx, compose) |
featured-kathara |
idekube-container-featured |
kathara-<version> |
featured-dind + Kathara network emulation |
featured-ros2 |
idekube-container-featured |
ros2-<version> |
+ ROS 2 Jazzy desktop-full + Gazebo + MoveIt |
coder-base |
idekube-container-coder-base |
<version> |
Coder IDE + SSH, minimal install |
coder-conda |
idekube-container-coder |
conda-<version> |
coder-base + Miniconda |
jupyter-base |
idekube-container-jupyter-base |
<version> |
JupyterLab + SSH + Miniconda |
jupyter-speit-ai |
idekube-container-jupyter |
speit-ai-<version> |
+ scientific stack + PyTorch conda environment |
agent-base |
idekube-container-agent-base |
<version> |
Claude Code + opencode + document toolchain + ttyd + SSH |
agent-openclaw |
idekube-container-agent |
openclaw-<version> |
+ openclaw gateway at /agent |
agent-hermes |
idekube-container-agent |
hermes-<version> |
+ Hermes Agent CLI + gateway |
Tags are suffixed with -ascend.
| Image | Repo | Variant tag | Description |
|---|---|---|---|
featured-base |
idekube-container-featured-base |
<version>-ascend |
Full desktop with Ascend NPU support |
featured-speit-ai |
idekube-container-featured |
speit-ai-<version>-ascend |
Desktop + PyTorch with Ascend NPU |
jupyter-base |
idekube-container-jupyter-base |
<version>-ascend |
JupyterLab with Ascend NPU support |
jupyter-speit-ai |
idekube-container-jupyter |
speit-ai-<version>-ascend |
JupyterLab + PyTorch with Ascend NPU |
| Variable | Purpose | Default |
|---|---|---|
IDEKUBE_INIT_HOME |
Initialize home from /etc/skel |
empty |
IDEKUBE_PREFERED_SHELL |
Path to preferred shell | /bin/bash |
IDEKUBE_USER_UID |
Override container user UID | empty |
IDEKUBE_AUTHORIZED_KEYS |
Base64-encoded SSH authorized keys | empty |
IDEKUBE_ACCESS_TOKEN |
Nginx-level web auth token (excludes /ssh) |
empty |
Host idekube
User idekube
ProxyCommand websocat --binary ws://$INGRESS_HOST$/ssh/Every container exposes /health (no auth) returning JSON for Kubernetes probes:
{
"status": "healthy",
"branch": "featured/base",
"entry": "/vnc/",
"services": {
"vnc": { "port": 6081, "path": "/vnc/", "healthy": true },
"coder": { "port": 3000, "path": "/coder/", "healthy": true },
"ssh": { "port": 2222, "path": "/ssh", "healthy": true }
}
}- For Kubernetes with Nginx Ingress Controller, the
nginx.org/websocket-servicesannotation is required for the coder service. - Chromium sandboxing and FUSE are not available in rootless mode. Use
privileged: trueto enable them.
This project is licensed under the terms of the MIT License. See the LICENSE file at the root of this repository for the full text.
The MIT License applies to the source code in this meta-repository, including the build configuration (docker-bake.hcl and overrides), helper scripts, test suite, CI workflows, and documentation. Submodules referenced under images/, artifacts/, frontend/, and healthcheck/ are governed by the license declared in each respective repository.
Container images published by this project bundle third-party software distributed under its own license. Redistribution and use of the built images must comply with the terms of each bundled component, including but not limited to the operating system base image and the upstream projects acknowledged below.
Many thanks to the authors of docker-novnc, VirtualGL, TurboVNC, and Coder.
