dev-containers-16-09-2026
Yesterday I failed to write something to my blog. But I wanted to add that I started working with dev containers. And I kind of like it. I still have to learn more about it. Or rather just use it a bit more. For my use case I’m using it for my Angular project. So in this case I have a Angular json file as well. Yesterday I failed to write something to my blog. The way it works I see is that you have a directory which inside is also lets say where you would put your out put in. So it looks something like this:
…/Projects/test ❯ tree -a -L 2
.
├── .devcontainer
│ ├── devcontainer.json
│ └── setup-tools.sh
└── my-app
├── .angular
├── angular.json
├── dist
├── .editorconfig
├── .gitignore
├── node_modules
├── package.json
├── package-lock.json
├── .prettierrc
├── public
├── README.md
├── src
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
└── .vscodeInside the .devcontainer direectory there I place the json thats needed. Beside that is there a setup-tools script that is getting all the extra tools I like to use when it comes to developing. I’m not quite sure yet if I want to keep it like this or rather get something like this directly from my dotfiles.
The nice thing about it is I don’t have to fysically install anything on my own machine. But it will rather stay inside a container which is using docker engine. I could also have went with Podman. But this seems a bit different then I’m use too and will be maybe done at a later stage.
About devcontainer.json: The linux environement comes with zsh which I never use. I’m not sure yet whether it comes with the image provided. I have to have an extra look at this still.
Below are all the files that we helpfull to set things up.
setup script for install devpod
# Installs the host prerequisites for using DevPod with a Docker backend.
# Agnostic: no language/framework-specific config is generated here.
set -e
ORANGE='\033[38;5;214m'
NC='\033[0m'
GREEN='\e[1;32m'
resolve_devpod() {
if command -v devpod >/dev/null 2>&1; then
echo "$(command -v devpod)"
else
echo "$HOME/.local/bin/devpod"
fi
}
create_welcome_message() {
clear
echo -e "${ORANGE}══════════════════════════════════════════════════${NC}"
echo -e "${ORANGE} DEVPOD / DEV CONTAINER PREREQUISITES${NC}"
echo -e "${ORANGE}══════════════════════════════════════════════════${NC}\n"
}
setup_docker() {
if ! groups | grep -qw docker; then
echo "→ Adding user to docker group..."
sudo usermod -aG docker "$USER"
echo -e "${GREEN}✓ group added — re-login needed before Docker works:\n newgrp docker (or log out/in)${NC}"
fi
if ! systemctl is-active --quiet docker; then
echo "→ Starting & enabling Docker daemon..."
sudo systemctl enable --now docker
fi
echo -e "${GREEN}✓ Docker ready${NC}"
}
install_devpod() {
DEVPOD_BIN="$(resolve_devpod)"
if [[ -x "$DEVPOD_BIN" ]]; then
echo -e "${GREEN}✓ DevPod already installed: $("$DEVPOD_BIN" --version)${NC}"
return
fi
mkdir -p "$HOME/.local/bin"
echo "→ Downloading DevPod CLI..."
curl -fsSL -o "$HOME/.local/bin/devpod" \
https://github.com/loft-sh/devpod/releases/latest/download/devpod-linux-amd64
chmod +x "$HOME/.local/bin/devpod"
echo -e "${GREEN}✓ DevPod installed: $("$HOME/.local/bin/devpod" --version)${NC}"
}
configure_devpod() {
DEVPOD_BIN="$(resolve_devpod)"
"$DEVPOD_BIN" provider add docker >/dev/null 2>&1 || true
"$DEVPOD_BIN" ide use none >/dev/null 2>&1 || true
echo -e "${GREEN}✓ DevPod configured (docker provider, no IDE)${NC}"
}
print_next_steps() {
echo -e "\n${GREEN}Next steps:${NC}"
if ! groups | grep -qw docker; then
echo " 1. newgrp docker # activate docker group in this shell"
fi
echo " 1. cd <project> # project with a .devcontainer/ or Dockerfile"
echo " 2. devpod up . # build & start the workspace"
echo " 3. devpod ssh <name>.devpod # shell into the container"
}
create_welcome_message
setup_docker
install_devpod
configure_devpod
print_next_stepsdevcontainer.json
{
"name": "Angular Dev",
"image": "mcr.microsoft.com/devcontainers/typescript-node:22",
"containerEnv": {
"XDG_CONFIG_HOME": "/home/node/.config"
},
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {},
"ghcr.io/stu-bell/devcontainer-features/neovim:0": {}
},
"mounts": [
"source=${localEnv:HOME}/.config/nvim,target=/home/node/.config/nvim,type=bind",
"source=${localEnv:HOME}/.config/tmux,target=/home/node/.config/tmux,type=bind"
],
"forwardPorts": [4200],
"portsAttributes": { "4200": { "label": "Angular Dev Server" } },
"postCreateCommand": "sudo bash .devcontainer/setup-tools.sh && sudo npm install -g npm@latest @angular/cli opencode-ai"
}setup-tools.sh
# Installs terminal/CLI tools LazyVim plugins expect: fzf, fd, ripgrep, bat, tmux, lazygit.
set -euo pipefail
apt-get update -y >/dev/null
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
fzf fd-find bat ripgrep tmux >/dev/null
# Debian ships fd as `fdfind` and bat as `batcat` — provide the expected names.
[ -e /usr/bin/fdfind ] && ln -sf /usr/bin/fdfind /usr/local/bin/fd
[ -e /usr/bin/batcat ] && ln -sf /usr/bin/batcat /usr/local/bin/bat
# lazygit (not in Debian repos) — static binary from the latest release.
# Resolve the version tag via the /releases/latest redirect, avoiding GitHub API rate limits.
if ! command -v lazygit >/dev/null 2>&1; then
tag="$(curl -fsSI https://github.com/jesseduffield/lazygit/releases/latest \
| grep -i '^location:' | tr -d '\r' | sed -E 's#.*/tag/(v[0-9][^ /]*) *$#\1#')"
if [[ -n "$tag" ]]; then
curl -fsSL "https://github.com/jesseduffield/lazygit/releases/download/$tag/lazygit_${tag#v}_Linux_x86_64.tar.gz" \
| tar -xz -C /tmp lazygit
install -m755 /tmp/lazygit /usr/local/bin/lazygit
else
echo "lazygit download skipped (could not resolve latest tag)"
fi
fi
echo "Installed: fzf fd rg bat tmux lazygit"