Cloud Native Devcontainer
Production-ready development container with modern tooling for cloud-native and infrastructure development.
What's Inside
Languages: Go, Node.js, Python, Rust (via cargo-binstall), uv, pnpm, aube
Cloud: AWS CLI, Terraform, Kubernetes (kubectl, k9s, k3d, helm, kustomize)
Development: Docker-outside-of-Docker, OpenCode, oy, git, just, mise, direnv, starship, zellij, neovim, lazygit, delta, difftastic
Security: Semgrep, cosign, SLSA verifier, lychee (link checker), Trivy, Syft, sops, age
Linting/formatting: ShellCheck, shfmt, actionlint, taplo, typos, hadolint, yamlfmt
Utilities: ripgrep, fzf, jq, yq, httpie, hurl, btop, restic, rclone
Complete list: See
src/wagov_devcontainer/spec.pyandsrc/wagov_devcontainer/deploy.py
Quick Start
VS Code Devcontainer (Recommended)
Create .devcontainer/devcontainer.json:
{
"name": "My Project",
"image": "ghcr.io/wagov-dtt/devcontainer-base",
"features": {
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {
"moby": false,
"dockerDashComposeVersion": "none"
}
},
"remoteEnv": {
"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}"
},
"remoteUser": "vscode"
}
Open in VS Code: Cmd/Ctrl+Shift+P → "Dev Containers: Reopen in Container"
Why these settings?
docker-outside-of-docker- Reuses the host Docker socket without privileged mode and handles socket permissions/rootless setups more robustly than a manual bind mount.moby: false- Uses the Docker CLI already baked into this Debian stable-backports image. The feature's default Moby packages are not available on Debian Trixie.dockerDashComposeVersion: "none"- Avoids installing an extradocker-composebinary becausedocker composeis already included viadocker-compose-plugin.LOCAL_WORKSPACE_FOLDER- Makes the host workspace path available for Docker bind mounts from inside the container.remoteUser: vscode- Correct user permissions
If you need compatibility with an older Docker daemon, set DOCKER_API_VERSION in remoteEnv as a project-specific workaround rather than by default.
Rootless Docker
For rootless Docker, override the feature's default socket mount to point at your user socket:
{
"name": "My Project",
"image": "ghcr.io/wagov-dtt/devcontainer-base",
"features": {
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {
"moby": false,
"dockerDashComposeVersion": "none"
}
},
"mounts": [
{
"source": "/run/user/1000/docker.sock",
"target": "/var/run/docker-host.sock",
"type": "bind"
}
],
"remoteUser": "vscode"
}
Replace 1000 with id -u from your host.
Docker bind mounts from inside the devcontainer
Docker commands run against the host daemon, so bind-mount source paths must exist on the host. Use LOCAL_WORKSPACE_FOLDER when invoking Docker:
docker run --rm -v "${LOCAL_WORKSPACE_FOLDER}:/workspace" debian:stable-slim pwd
For projects with Docker Compose files that assume container paths match host paths, mount the workspace at the same absolute path:
{
"workspaceFolder": "${localWorkspaceFolder}",
"workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind"
}
This is not available when using VS Code's Clone Repository in Container Volume flow, because ${localWorkspaceFolder} does not exist there.
Docker CLI
The image still includes Docker CLI/buildx/compose for direct docker run usage outside VS Code Dev Containers:
# Basic usage (mount host Docker socket)
docker run -it --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
--group-add $(stat -c '%g' /var/run/docker.sock) \
ghcr.io/wagov-dtt/devcontainer-base
# With your projects mounted
docker run -it --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
--group-add $(stat -c '%g' /var/run/docker.sock) \
-v ~/projects:/workspaces \
ghcr.io/wagov-dtt/devcontainer-base
Install on Existing System
Works on Debian/Ubuntu, including Ubuntu 26.04. On atomic or other brew-based hosts, the pyinfra deploy can use Homebrew for user-space tooling instead of attempting APT/extrepo or Docker daemon changes.
For direct uvx/pipx run usage, install these first:
- GitHub CLI (
gh) - either uv (
uvx) or pipx
To avoid GitHub API rate limits during tool installs, export a token from gh first:
export GITHUB_TOKEN="$(gh auth token)"
# Preferred: run the published package directly
uvx wagov-devcontainer
# Or with pipx
pipx run --spec wagov-devcontainer wagov-devcontainer
# Repo helper script for Debian/Ubuntu, including Ubuntu 26.04
curl -sSL https://raw.githubusercontent.com/wagov-dtt/devcontainer-base/main/install.sh | sh
The helper script also auto-detects GITHUB_TOKEN from gh auth token when gh is installed.
On non-APT hosts, use uvx or pipx run directly; the helper script will not try to bootstrap packages there. If brew is on PATH, the deploy installs the needed user-space packages itself and then runs mise install --yes once mise is available.
Use as Template
- GitHub: Click "Use this template" to create your own repository
- Codespaces: Works immediately - click "Code" → "Create codespace"
- Local: Clone and customize as needed
CI/CD Integration
Run tests in the devcontainer for guaranteed consistency:
- name: Run tests in devcontainer
uses: devcontainers/ci@v0.3
with:
imageName: local/devcontainer
push: never
runCmd: |
just test
mise run lint
See .github/workflows/test-devcontainer.yml for complete example.
How It Works
Architecture
- Base: Debian stable-backports (currently Trixie/13)
- Package Management: APT for system tools, mise for development tools
- Build: Python package (
wagov-devcontainer) runs a pyinfra deploy during Docker build or local install - Docker-outside-of-Docker: Host socket reuse via the upstream Dev Containers feature; Docker CLI/buildx/compose are also pre-installed for plain
docker runusage
Tool Sources
Tools are installed from two sources, preferring APT when available:
- APT via extrepo (preferred) - Signed packages from official repos
- Docker, GitHub CLI, Terraform, kubectl, mise
- mise - Cross-platform tools not in APT, or needing version flexibility
- Languages (Go, Node, Python), k9s, starship
- npm-backed tools are installed through aube (
npm.package_manager = "aube") - Cargo-backed tools use cargo-binstall when prebuilt binaries are available
Key Features
- Security: SBOM, signed images, Semgrep in-container
- Performance: Multi-platform builds (amd64/arm64), layer caching
- Flexibility: mise auto-switches tool versions per project
- Supply Chain: Verified packages via extrepo
Adding Tools
Edit src/wagov_devcontainer/spec.py and add to the appropriate mapping:
MISE_TOOLS = {
# Simple: tool name -> pinned to "latest"
"pipx:your-tool": "latest", # or npm:, cargo:, github:user/repo
# Complex: use structured values for inline TOML tables
"pipx:tool": {"version": "latest", "extras": "extra", "uvx_args": "--with dep"},
}
MISE_SETTINGS is also structured Python data, and MISE_TOML is rendered from it.
For provisioning behaviour, edit src/wagov_devcontainer/deploy.py. Then rebuild: just build
See CONTRIBUTING.md for contributor guidance.
Optional Cloud CLIs
GCP CLI and Azure CLI are not installed by default (saves ~1 GB). Install them when needed:
# GCP CLI (repo already enabled via extrepo)
sudo apt-get update && sudo apt-get install -y google-cloud-cli
# Azure CLI (repo not available for Trixie, use pipx)
pipx install azure-cli
Development Commands
just # List all commands
just build # Build test image
just test # Test Docker-outside-of-Docker
just dev # Interactive shell
just lint # Format and lint Python sources
just clean # Clean up images
For maintainers:
just publish # Multi-platform build + push
just shell # Run published image interactively
Troubleshooting
| Issue | Solution |
|---|---|
| Docker not working | Ensure Docker is running and the host socket is available. For rootless Docker, override the socket mount as shown above. |
| Tool missing | Check src/wagov_devcontainer/spec.py |
| Build fails | Run just clean then just build |
| Docker permission errors | Rebuild the devcontainer so the docker-outside-of-docker feature can refresh socket access. For direct docker run, pass --group-add $(stat -c '%g' /var/run/docker.sock). |
| mise issues | Run mise doctor inside container |
Contributing
- Fork and clone the repo
- Make changes to
src/wagov_devcontainer/,Dockerfile, or docs - Test:
just build && just test && just dev - Submit PR with test results
What to contribute:
- New tools or tool updates
- Documentation improvements
- Bug fixes
- Performance optimisations
See CONTRIBUTING.md for contributor guidance and project philosophy.
Metadata
Release files for wagov-devcontainer 2026.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| wagov_devcontainer-2026.6.tar.gz | 69.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| wagov_devcontainer-2026.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 90.4 kB
Release files / wagov_devcontainer-2026.6.tar.gz
| Download URL | wagov_devcontainer-2026.6.tar.gz |
|---|---|
| Size | 69.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
32095d0d6c5e2c06046d6cf598462f98ec5eca91daf654f0d40a9a850c1e6e5c
|
|
BLAKE2b-256 checksum How to use checksums |
d8a5b00631ad58e83ece94b4cf8b197a22ac24dc6b5bf945a99eff7335fef9e9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 27, 2026.
Transparency logRelease files / wagov_devcontainer-2026.6-py3-none-any.whl
| Download URL | wagov_devcontainer-2026.6-py3-none-any.whl |
|---|---|
| Size | 21.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e28b8c01ee537c8bc5cf47c6c6075cf2bcea22c61f7f35e4d524eecacc2c1b49
|
|
BLAKE2b-256 checksum How to use checksums |
b110cab743fd4438f553d435356448ec4a2bf22b4cd0c57b0026beee820e05ef
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 27, 2026.
Transparency log