Provision the wagov devcontainer toolchain with pyinfra
Project description
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.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wagov_devcontainer-2026.6.tar.gz.
File metadata
- Download URL: wagov_devcontainer-2026.6.tar.gz
- Upload date:
- Size: 69.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
32095d0d6c5e2c06046d6cf598462f98ec5eca91daf654f0d40a9a850c1e6e5c
|
|
| MD5 |
220f90d331c8b1d40775172d4ddfe414
|
|
| BLAKE2b-256 |
d8a5b00631ad58e83ece94b4cf8b197a22ac24dc6b5bf945a99eff7335fef9e9
|
Provenance
The following attestation bundles were made for wagov_devcontainer-2026.6.tar.gz:
Publisher:
release.yml on wagov-dtt/devcontainer-base
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wagov_devcontainer-2026.6.tar.gz -
Subject digest:
32095d0d6c5e2c06046d6cf598462f98ec5eca91daf654f0d40a9a850c1e6e5c - Sigstore transparency entry: 1639103063
- Sigstore integration time:
-
Permalink:
wagov-dtt/devcontainer-base@50a1aaa54dff6bc53c74fec59f54e020a2138810 -
Branch / Tag:
refs/tags/v2026.6 - Owner: https://github.com/wagov-dtt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@50a1aaa54dff6bc53c74fec59f54e020a2138810 -
Trigger Event:
push
-
Statement type:
File details
Details for the file wagov_devcontainer-2026.6-py3-none-any.whl.
File metadata
- Download URL: wagov_devcontainer-2026.6-py3-none-any.whl
- Upload date:
- Size: 21.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e28b8c01ee537c8bc5cf47c6c6075cf2bcea22c61f7f35e4d524eecacc2c1b49
|
|
| MD5 |
ce09c213236a8732217f4b3a1725c1b3
|
|
| BLAKE2b-256 |
b110cab743fd4438f553d435356448ec4a2bf22b4cd0c57b0026beee820e05ef
|
Provenance
The following attestation bundles were made for wagov_devcontainer-2026.6-py3-none-any.whl:
Publisher:
release.yml on wagov-dtt/devcontainer-base
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wagov_devcontainer-2026.6-py3-none-any.whl -
Subject digest:
e28b8c01ee537c8bc5cf47c6c6075cf2bcea22c61f7f35e4d524eecacc2c1b49 - Sigstore transparency entry: 1639103169
- Sigstore integration time:
-
Permalink:
wagov-dtt/devcontainer-base@50a1aaa54dff6bc53c74fec59f54e020a2138810 -
Branch / Tag:
refs/tags/v2026.6 - Owner: https://github.com/wagov-dtt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@50a1aaa54dff6bc53c74fec59f54e020a2138810 -
Trigger Event:
push
-
Statement type: