{"id":51126784,"url":"https://github.com/abitofhelp/dev_containers","last_synced_at":"2026-06-25T08:32:18.823Z","repository":{"id":349671822,"uuid":"1203330486","full_name":"abitofhelp/dev_containers","owner":"abitofhelp","description":"'dev_containers' provides professional development containers for desktop and embedded (ARM Cortex-M/A) platforms.","archived":false,"fork":false,"pushed_at":"2026-06-23T01:48:10.000Z","size":157,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-23T03:20:41.678Z","etag":null,"topics":["ada","ada-2022","arm-cortex-a","arm-cortex-m","containerd","cpp","dev-container","docker","go","kubernetes","linux","rust","ubuntu","zshembedded"],"latest_commit_sha":null,"homepage":null,"language":"Dockerfile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/abitofhelp.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-07T00:15:31.000Z","updated_at":"2026-06-23T01:47:57.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/abitofhelp/dev_containers","commit_stats":null,"previous_names":["abitofhelp/dev_containers"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/abitofhelp/dev_containers","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abitofhelp%2Fdev_containers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abitofhelp%2Fdev_containers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abitofhelp%2Fdev_containers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abitofhelp%2Fdev_containers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/abitofhelp","download_url":"https://codeload.github.com/abitofhelp/dev_containers/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/abitofhelp%2Fdev_containers/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34767543,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-25T02:00:05.521Z","response_time":101,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ada","ada-2022","arm-cortex-a","arm-cortex-m","containerd","cpp","dev-container","docker","go","kubernetes","linux","rust","ubuntu","zshembedded"],"created_at":"2026-06-25T08:32:15.568Z","updated_at":"2026-06-25T08:32:18.814Z","avatar_url":"https://github.com/abitofhelp.png","language":"Dockerfile","funding_links":[],"categories":[],"sub_categories":[],"readme":"# dev_containers\n\n[![Build](https://github.com/abitofhelp/dev_containers/actions/workflows/docker-build.yml/badge.svg)](https://github.com/abitofhelp/dev_containers/actions/workflows/docker-build.yml) [![Publish](https://github.com/abitofhelp/dev_containers/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/abitofhelp/dev_containers/actions/workflows/docker-publish.yml) [![License: BSD-3-Clause](https://img.shields.io/badge/License-BSD--3--Clause-blue.svg)](LICENSE)\n\nProfessional development containers for Ada, C++, Go, and Rust — with\nembedded (ARM Cortex-M/A) support for Ada, C++, and Rust, including\nTeensy 4.1 bare-metal Rust support.\n\n## Available Images\n\n| Image | Language | Base | Architectures | Embedded |\n|-------|----------|------|---------------|----------|\n| `dev-container-ada` | Ada (Alire-managed GNAT) | Ubuntu 22.04 | amd64 | Cortex-M/A |\n| `dev-container-ada-system` | Ada (APT `gnat-13`) | Ubuntu 24.04 | amd64, arm64 | Cortex-M/A |\n| `dev-container-cpp` | C++ (Clang 20, CMake, vcpkg) | Ubuntu 24.04 | amd64, arm64 | Cortex-M/A |\n| `dev-container-cpp-system` | C++ (GCC 13, Clang 18, apt) | Ubuntu 24.04 | amd64, arm64 | Cortex-M/A |\n| `dev-container-go` | Go 1.26.1, protobuf, Bazelisk | Ubuntu 24.04 | amd64, arm64 | — |\n| `dev-container-rust` | Rust stable (rustup) | Ubuntu 24.04 | amd64, arm64 | Cortex-M/A, Teensy 4.1 |\n\nAll images are published to GitHub Container Registry:\n\n```text\nghcr.io/abitofhelp/\u003cimage-name\u003e:latest\nghcr.io/abitofhelp/\u003cimage-name\u003e:v\u003cX.Y.Z\u003e\n```\n\n### Versioning\n\nAll six images share a single repository version. A `vX.Y.Z` tag on this\nrepo produces the matching `ghcr.io/abitofhelp/\u003cimage\u003e:vX.Y.Z` for every\nimage in the same release. The `:latest` tag always points to the most\nrecent non-pre-release version. See [CHANGELOG.md](CHANGELOG.md) for the\ncurrent release and history.\n\n## Quick Start\n\n### 1. Pull an image\n\n```bash\n# From your project directory:\nmake -f ~/containers/dev_containers/ada/Makefile pull-system\n```\n\n### 2. Launch a container\n\n```bash\ncd ~/Ada/github.com/abitofhelp/my_project\nmake -f ~/containers/dev_containers/ada/Makefile run-system\n```\n\nThe Makefile auto-detects the container CLI (docker on macOS/Windows, nerdctl\non Linux), generates a sequential container name (`dev-container-ada-system-1`,\n`-2`, etc.), passes host identity for runtime user adaptation, and mounts your\ncurrent directory at `/workspace`.\n\n### 3. Or use the shell aliases\n\nIf your `.zshrc` has the convenience functions configured:\n\n```bash\nadast    # Ada system image — cd's to source root, launches container\ncppt     # C++ upstream image\ngot      # Go image\nrustt    # Rust image\n```\n\n| Command | Image | amd64 (x86_64) | arm64 |\n|---------|-------|:---:|:---:|\n| `adat` | dev-container-ada (Alire) | yes | no |\n| `adast` | dev-container-ada-system (APT) | yes | yes |\n| `cppt` | dev-container-cpp | yes | yes |\n| `cppst` | dev-container-cpp-system (APT) | yes | yes |\n| `got` | dev-container-go | yes | yes |\n| `rustt` | dev-container-rust | yes | yes |\n\n## Why These Containers Are Useful\n\nEach container provides a reproducible development environment that adapts to\nthe host user at runtime.  Any developer can pull a pre-built image and run it\nwithout rebuilding.\n\nThe included `.zshrc` detects when it is running inside a container and\nvisibly marks the prompt:\n\n```text\nmike@container /workspace (main) [ctr:rootless]\n❯\n```\n\nThis prevents common mistakes: editing in the wrong terminal, confusing host\nand container environments, or debugging UID/mount issues.\n\n## Pre-installed Tools (All Images)\n\n| Category | Tools |\n|----------|-------|\n| **Version control** | git, patch, openssh-client |\n| **Editors** | vim, neovim, nano |\n| **Search** | ripgrep (rg), fd-find (fdfind), fzf |\n| **Network** | curl, wget, rsync |\n| **Archives** | tar, zip, unzip, xz, gzip, bzip2 |\n| **Python** | python3, pip3, python3-venv |\n| **Shell** | zsh (default), bash, zsh-autosuggestions, zsh-syntax-highlighting |\n| **Container** | gosu, sudo |\n| **Debugger** | gdb, strace |\n| **Build** | make, pkg-config |\n| **Pagers** | less, more, file, jq, lsof |\n| **Documentation** | typst (formal document compiler) |\n\nSee each image's Dockerfile for the full list of language-specific tools.\n\n### Rust Embedded / Teensy 4.1 Support\n\nThe Rust image supports both generic embedded Rust targets and a concrete\nPJRC Teensy 4.1 workflow. Teensy 4.1 uses the NXP i.MX RT1062 Cortex-M7, so\nRust projects target `thumbv7em-none-eabihf` and produce Intel HEX files for\nPJRC's loader.\n\n| Target | Typical hardware | Runtime shape | Primary output |\n|--------|------------------|---------------|----------------|\n| `thumbv6m-none-eabi` | Cortex-M0/M0+ | `no_std` bare metal | ELF / BIN / HEX |\n| `thumbv7m-none-eabi` | Cortex-M3 | `no_std` bare metal | ELF / BIN / HEX |\n| `thumbv7em-none-eabi` | Cortex-M4/M7, soft-float ABI | `no_std` bare metal | ELF / BIN / HEX |\n| `thumbv7em-none-eabihf` | Cortex-M4F/M7F, including Teensy 4.1 | `no_std` bare metal | ELF / Intel HEX |\n| `thumbv8m.main-none-eabihf` | Cortex-M33-class MCUs | `no_std` bare metal | ELF / BIN / HEX |\n| `armv7-unknown-linux-gnueabihf` | ARMv7 Linux SBCs / MPU targets | Linux userspace | Linux executable |\n\nThe Teensy 4.1 path includes:\n\n- `cargo-binutils` / `cargo objcopy` for Intel HEX generation.\n- `teensy_loader_cli` for PJRC command-line flashing.\n- `cargo-generate` plus shell helpers for the upstream `teensy4-rs-template`.\n- A smoke example at `rust/examples/teensy41_blink`.\n- Detailed notes in [`rust/EMBEDDED.md`](rust/EMBEDDED.md).\n\nCargo cache behavior: the Rust image stores the pinned toolchain and\npreinstalled cargo tools under `/opt`, while runtime Cargo cache and user cargo\ninstalls use `${HOME}/.cargo`. This keeps the image reproducible and avoids\npermission problems when building bind-mounted projects as the adapted host\nuser.\n\nInside the Rust container:\n\n```bash\ncd rust/examples/teensy41_blink\ncargo objcopy --release -- -O ihex teensy41_blink.hex\n```\n\nFlash from a Linux host/container with USB access:\n\n```bash\nteensy_loader_cli --mcu=TEENSY41 -w -v teensy41_blink.hex\n```\n\nThe container can always build the `.hex`. Direct flashing also requires host\nUSB access. On Linux, install PJRC's Teensy udev rules on the host. On macOS\nwith Docker Desktop, build in the container and flash from the macOS host with\nthe PJRC graphical Teensy Loader or a host-installed `teensy_loader_cli`.\n\n## Reproducibility Policy\n\nTo keep image builds reproducible, every tool installed in a Dockerfile MUST\nbe pinned to a specific version. When downloading binaries or tarballs,\nalso verify a SHA256 checksum.\n\nPin at the most specific level available:\n\n- **Base images** — pin by SHA256 digest (e.g., `ubuntu:24.04@sha256:…`).\n- **Downloadable binaries/tarballs** — pin `*_VERSION` and verify `*_SHA256`.\n- **Package managers** — pin tool versions (e.g., `go install …@v1.2.3`,\n  `cargo install --version X.Y.Z`, `rustup toolchain install 1.85.1`).\n- **Git clones** — check out a tagged release, not a moving branch.\n- **APT packages** — use versioned package names where available\n  (`gnat-13`, `clang-20`); Ubuntu's archive rotates exact versions, so\n  exact-version apt pinning is discouraged.\n\nAvoid `@latest`, `stable`, `HEAD`, `main`, and unverified downloads. If\nyou add a tool, add a `TOOLNAME_VERSION` (and `TOOLNAME_SHA256` where the\ntool ships a binary release) to the `ARG` block at the top of the\nDockerfile.\n\nThe Ada images are the current reference for this policy: the Ubuntu base\nimage, Alire, GNAT, and GPRBuild are all version-pinned with SHA256\nverification where applicable.\n\n## How It Works\n\n### Runtime-Adaptive User Identity\n\nThe image ships with a fallback user (`dev:1000:1000`) for CI and Kubernetes.\nAt run time, `entrypoint.sh` reads `HOST_USER`, `HOST_UID`, and `HOST_GID`\nfrom environment variables and adapts the in-container user to match.\n\n### Container CLI Auto-Detection\n\nThe Makefile and `container_run.py` launcher script automatically detect\nthe host platform:\n\n| Host | CLI | Runtime |\n|------|-----|---------|\n| macOS | docker | Docker Desktop |\n| Linux | nerdctl | Rootless containerd |\n| Windows | docker | Docker Desktop |\n\nOverride with `CONTAINER_CLI=docker` or the `--cli` flag.\n\n### Container Naming\n\nContainers are named sequentially: `dev-container-ada-1`, `-2`, `-3`, etc.\nThis allows multiple containers from the same image to run simultaneously\nwith predictable names.\n\n## Deployment Environments\n\n| Runtime | Container UID 0 is... | Bind mount access via... | Security boundary |\n|---------|----------------------|--------------------------|-------------------|\n| Docker rootful | Real root (dangerous) | gosu drop to HOST_UID | Container isolation |\n| nerdctl rootless | Host user (safe) | Stay UID 0 (= host user) | User namespace |\n| Podman rootless | Host user (safe) | --userns=keep-id | User namespace |\n| Kubernetes | Blocked by policy | fsGroup in pod spec | Pod security standards |\n\n## Linux Host Prerequisites\n\nBefore running containers on a headless Ubuntu server (24.04+), complete\nthese one-time setup steps:\n\n### 1. Allow unprivileged user namespaces (Ubuntu 24.04)\n\n```bash\nsudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0\nsudo sh -c 'echo \"kernel.apparmor_restrict_unprivileged_userns=0\" \u003e\u003e /etc/sysctl.d/99-rootless.conf'\n```\n\n### 2. Install rootless containerd\n\n```bash\ncontainerd-rootless-setuptool.sh install\n```\n\n### 3. Install BuildKit (required for `nerdctl build`)\n\n```bash\ncontainerd-rootless-setuptool.sh install-buildkit\n```\n\n### 4. Enable linger for your user\n\n```bash\nsudo loginctl enable-linger $(whoami)\n```\n\nThis keeps your systemd session alive across SSH connections so that a\nsecond terminal can see running containers.\n\n### 5. Verify XDG_RUNTIME_DIR\n\n```bash\necho $XDG_RUNTIME_DIR\n# Should show: /run/user/\u003cuid\u003e\n```\n\nIf empty, add to your shell profile:\n\n```bash\nexport XDG_RUNTIME_DIR=/run/user/$(id -u)\n```\n\n### 6. Verify\n\n```bash\nnerdctl ps    # Should return without errors\n```\n\n## Repository Layout\n\n```text\ndev_containers/\n├── .github/workflows/       ← matrix build + publish\n├── .dockerignore\n├── .gitignore\n├── entrypoint.sh            ← shared across all images\n├── LICENSE\n├── Makefile.common          ← shared Makefile targets\n├── README.md\n├── USER_GUIDE.md\n├── CHANGELOG.md\n├── ada/\n│   ├── Dockerfile           ← Alire-managed toolchain (Ubuntu 22.04)\n│   ├── Dockerfile.system    ← system toolchain (Ubuntu 24.04)\n│   ├── Makefile             ← thin: sets vars, includes Makefile.common\n│   ├── .zshrc               ← Ada-specific shell config\n│   └── examples/hello_ada/\n├── cpp/\n│   ├── Dockerfile           ← upstream Clang 20, CMake, vcpkg\n│   ├── Dockerfile.system    ← system GCC 13, Clang 18\n│   ├── Makefile\n│   ├── .zshrc\n│   └── examples/hello_cpp/\n├── go/\n│   ├── Dockerfile           ← Go 1.26.1, protobuf, Bazelisk\n│   ├── Makefile\n│   ├── .zshrc\n│   └── examples/hello_go/\n└── rust/\n    ├── Dockerfile           ← Rust stable via rustup\n    ├── Makefile\n    ├── .zshrc\n    └── examples/hello_rust/\n```\n\n## Makefile Targets\n\nRun `make -f \u003clang\u003e/Makefile help` for the full list.  Common targets:\n\n```bash\nmake -f ada/Makefile build          # Build the image\nmake -f ada/Makefile run            # Launch container (auto-detects CLI)\nmake -f ada/Makefile run-system     # Launch system-toolchain variant\nmake -f ada/Makefile test           # Smoke test\nmake -f ada/Makefile inspect        # Show configured variables\nmake -f ada/Makefile help           # Full target list\n```\n\nFor hosts that should explicitly use Docker Desktop, such as macOS, use the\nDocker convenience aliases from the repository root:\n\n```bash\nmake -f rust/Makefile docker-build\nmake -f rust/Makefile test-docker\nmake -f rust/Makefile test-teensy41-docker\n```\n\nThe Docker and Podman aliases stay in the same Makefile invocation as the\nlanguage wrapper, so they preserve the `-f \u003clang\u003e/Makefile` context and the\nshared repo-root build context.\n\n## Shared Python Launcher\n\nContainer launch logic lives in `container_run.py` from the\n[hybrid_scripts_python](https://github.com/abitofhelp/hybrid_scripts_python)\nrepository.  The Makefile auto-detects its location by platform.  For\nstandalone use or ad-hoc projects, clone the scripts repo directly:\n\n```bash\n# macOS\ngit clone git@github.com:abitofhelp/hybrid_scripts_python.git \\\n    ~/Ada/github.com/abitofhelp/hybrid_scripts_python\n\n# Linux\ngit clone git@github.com:abitofhelp/hybrid_scripts_python.git \\\n    ~/ada/github.com/abitofhelp/hybrid_scripts_python\n```\n\nOverride the path with the `HYBRID_SCRIPTS_PYTHON` environment variable\nif your clone is elsewhere.\n\n## License\n\nBSD-3-Clause — see [LICENSE](LICENSE).\n\n## AI Assistance and Authorship\n\nThis project was developed by Michael Gardner with AI assistance from Claude\n(Anthropic) and GPT (OpenAI).  AI tools were used for design review,\narchitecture decisions, and code generation.  All code has been reviewed and\napproved by the human author.  The human maintainer holds responsibility for\nall code in this repository.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabitofhelp%2Fdev_containers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fabitofhelp%2Fdev_containers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fabitofhelp%2Fdev_containers/lists"}