Professional development containers for Ada, C++, Go, and Rust — with embedded (ARM Cortex-M/A) support for Ada, C++, and Rust.
| Image | Language | Base | Architectures | Embedded |
|---|---|---|---|---|
dev-container-ada |
Ada (Alire-managed GNAT) | Ubuntu 22.04 | amd64 | Cortex-M/A |
dev-container-ada-system |
Ada (APT gnat-13) |
Ubuntu 24.04 | amd64, arm64 | Cortex-M/A |
dev-container-cpp |
C++ (Clang 20, CMake, vcpkg) | Ubuntu 24.04 | amd64, arm64 | Cortex-M/A |
dev-container-cpp-system |
C++ (GCC 13, Clang 18, apt) | Ubuntu 24.04 | amd64, arm64 | Cortex-M/A |
dev-container-go |
Go 1.26.1, protobuf, Bazelisk | Ubuntu 24.04 | amd64, arm64 | — |
dev-container-rust |
Rust stable (rustup) | Ubuntu 24.04 | amd64, arm64 | Cortex-M/A |
All images are published to GitHub Container Registry:
ghcr.io/abitofhelp/<image-name>:latest
# From your project directory:
make -f ~/containers/dev_containers/ada/Makefile pull-systemcd ~/Ada/github.com/abitofhelp/my_project
make -f ~/containers/dev_containers/ada/Makefile run-systemThe Makefile auto-detects the container CLI (docker on macOS/Windows, nerdctl
on Linux), generates a sequential container name (dev-container-ada-system-1,
-2, etc.), passes host identity for runtime user adaptation, and mounts your
current directory at /workspace.
If your .zshrc has the convenience functions configured:
adast # Ada system image — cd's to source root, launches container
cppt # C++ upstream image
got # Go image
rustt # Rust image| Command | Image | amd64 (x86_64) | arm64 |
|---|---|---|---|
adat |
dev-container-ada (Alire) | yes | no |
adast |
dev-container-ada-system (APT) | yes | yes |
cppt |
dev-container-cpp | yes | yes |
cppst |
dev-container-cpp-system (APT) | yes | yes |
got |
dev-container-go | yes | yes |
rustt |
dev-container-rust | yes | yes |
Each container provides a reproducible development environment that adapts to the host user at runtime. Any developer can pull a pre-built image and run it without rebuilding.
The included .zshrc detects when it is running inside a container and
visibly marks the prompt:
mike@container /workspace (main) [ctr:rootless]
❯
This prevents common mistakes: editing in the wrong terminal, confusing host and container environments, or debugging UID/mount issues.
| Category | Tools |
|---|---|
| Version control | git, patch, openssh-client |
| Editors | vim, neovim, nano |
| Search | ripgrep (rg), fd-find (fdfind), fzf |
| Network | curl, wget, rsync |
| Archives | tar, zip, unzip, xz, gzip, bzip2 |
| Python | python3, pip3, python3-venv |
| Shell | zsh (default), bash, zsh-autosuggestions, zsh-syntax-highlighting |
| Container | gosu, sudo |
| Debugger | gdb, strace |
| Build | make, pkg-config |
| Pagers | less, more, file, jq, lsof |
See each image's Dockerfile for the full list of language-specific tools.
The image ships with a fallback user (dev:1000:1000) for CI and Kubernetes.
At run time, entrypoint.sh reads HOST_USER, HOST_UID, and HOST_GID
from environment variables and adapts the in-container user to match.
The Makefile and container_run.py launcher script automatically detect
the host platform:
| Host | CLI | Runtime |
|---|---|---|
| macOS | docker | Docker Desktop |
| Linux | nerdctl | Rootless containerd |
| Windows | docker | Docker Desktop |
Override with CONTAINER_CLI=docker or the --cli flag.
Containers are named sequentially: dev-container-ada-1, -2, -3, etc.
This allows multiple containers from the same image to run simultaneously
with predictable names.
| Runtime | Container UID 0 is... | Bind mount access via... | Security boundary |
|---|---|---|---|
| Docker rootful | Real root (dangerous) | gosu drop to HOST_UID | Container isolation |
| nerdctl rootless | Host user (safe) | Stay UID 0 (= host user) | User namespace |
| Podman rootless | Host user (safe) | --userns=keep-id | User namespace |
| Kubernetes | Blocked by policy | fsGroup in pod spec | Pod security standards |
Before running containers on a headless Ubuntu server (24.04+), complete these one-time setup steps:
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
sudo sh -c 'echo "kernel.apparmor_restrict_unprivileged_userns=0" >> /etc/sysctl.d/99-rootless.conf'containerd-rootless-setuptool.sh installcontainerd-rootless-setuptool.sh install-buildkitsudo loginctl enable-linger $(whoami)This keeps your systemd session alive across SSH connections so that a second terminal can see running containers.
echo $XDG_RUNTIME_DIR
# Should show: /run/user/<uid>If empty, add to your shell profile:
export XDG_RUNTIME_DIR=/run/user/$(id -u)nerdctl ps # Should return without errorsdev_containers/
├── .github/workflows/ ← matrix build + publish
├── .dockerignore
├── .gitignore
├── entrypoint.sh ← shared across all images
├── LICENSE
├── Makefile.common ← shared Makefile targets
├── README.md
├── USER_GUIDE.md
├── CHANGELOG.md
├── ada/
│ ├── Dockerfile ← Alire-managed toolchain (Ubuntu 22.04)
│ ├── Dockerfile.system ← system toolchain (Ubuntu 24.04)
│ ├── Makefile ← thin: sets vars, includes Makefile.common
│ ├── .zshrc ← Ada-specific shell config
│ └── examples/hello_ada/
├── cpp/
│ ├── Dockerfile ← upstream Clang 20, CMake, vcpkg
│ ├── Dockerfile.system ← system GCC 13, Clang 18
│ ├── Makefile
│ ├── .zshrc
│ └── examples/hello_cpp/
├── go/
│ ├── Dockerfile ← Go 1.26.1, protobuf, Bazelisk
│ ├── Makefile
│ ├── .zshrc
│ └── examples/hello_go/
└── rust/
├── Dockerfile ← Rust stable via rustup
├── Makefile
├── .zshrc
└── examples/hello_rust/
Run make -f <lang>/Makefile help for the full list. Common targets:
make -f ada/Makefile build # Build the image
make -f ada/Makefile run # Launch container (auto-detects CLI)
make -f ada/Makefile run-system # Launch system-toolchain variant
make -f ada/Makefile test # Smoke test
make -f ada/Makefile inspect # Show configured variables
make -f ada/Makefile help # Full target listContainer launch logic lives in container_run.py from the
hybrid_scripts_python
repository. The Makefile auto-detects its location by platform. For
standalone use or ad-hoc projects, clone the scripts repo directly:
# macOS
git clone git@github.com:abitofhelp/hybrid_scripts_python.git \
~/Ada/github.com/abitofhelp/hybrid_scripts_python
# Linux
git clone git@github.com:abitofhelp/hybrid_scripts_python.git \
~/ada/github.com/abitofhelp/hybrid_scripts_pythonOverride the path with the HYBRID_SCRIPTS_PYTHON environment variable
if your clone is elsewhere.
BSD-3-Clause — see LICENSE.
This project was developed by Michael Gardner with AI assistance from Claude (Anthropic) and GPT (OpenAI). AI tools were used for design review, architecture decisions, and code generation. All code has been reviewed and approved by the human author. The human maintainer holds responsibility for all code in this repository.