Skip to main content

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.py and src/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 extra docker-compose binary because docker compose is already included via docker-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:

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

  1. GitHub: Click "Use this template" to create your own repository
  2. Codespaces: Works immediately - click "Code" → "Create codespace"
  3. 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 run usage

Tool Sources

Tools are installed from two sources, preferring APT when available:

  1. APT via extrepo (preferred) - Signed packages from official repos
    • Docker, GitHub CLI, Terraform, kubectl, mise
  2. 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

  1. Fork and clone the repo
  2. Make changes to src/wagov_devcontainer/, Dockerfile, or docs
  3. Test: just build && just test && just dev
  4. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wagov_devcontainer-2026.6.tar.gz (69.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wagov_devcontainer-2026.6-py3-none-any.whl (21.0 kB view details)

Uploaded Python 3

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

Hashes for wagov_devcontainer-2026.6.tar.gz
Algorithm Hash digest
SHA256 32095d0d6c5e2c06046d6cf598462f98ec5eca91daf654f0d40a9a850c1e6e5c
MD5 220f90d331c8b1d40775172d4ddfe414
BLAKE2b-256 d8a5b00631ad58e83ece94b4cf8b197a22ac24dc6b5bf945a99eff7335fef9e9

See more details on using hashes here.

Provenance

The following attestation bundles were made for wagov_devcontainer-2026.6.tar.gz:

Publisher: release.yml on wagov-dtt/devcontainer-base

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file wagov_devcontainer-2026.6-py3-none-any.whl.

File metadata

File hashes

Hashes for wagov_devcontainer-2026.6-py3-none-any.whl
Algorithm Hash digest
SHA256 e28b8c01ee537c8bc5cf47c6c6075cf2bcea22c61f7f35e4d524eecacc2c1b49
MD5 ce09c213236a8732217f4b3a1725c1b3
BLAKE2b-256 b110cab743fd4438f553d435356448ec4a2bf22b4cd0c57b0026beee820e05ef

See more details on using hashes here.

Provenance

The following attestation bundles were made for wagov_devcontainer-2026.6-py3-none-any.whl:

Publisher: release.yml on wagov-dtt/devcontainer-base

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page