add devcontainer

This commit is contained in:
daniel fusser
2026-07-09 00:33:52 +02:00
parent e65c3331b4
commit f1f2d9c2e5
3 changed files with 140 additions and 0 deletions
+2
View File
@@ -6,6 +6,8 @@
!hooks/* !hooks/*
!bin/ !bin/
!bin/* !bin/*
!devcontainer/
!devcontainer/*
!dircolors/ !dircolors/
!dircolors/* !dircolors/*
!git/ !git/
+117
View File
@@ -0,0 +1,117 @@
# Alpine dev container with dropbear SSH access and this dotfiles repo
# pre-cloned and installed.
#
# Build:
# docker build -t dev-container \
# --build-arg USERNAME=dafu \
# --build-arg GITHUB_USER=dafu \
# devcontainer
#
# Run:
# docker run -d -p 2222:22 --name dev-container dev-container
# ssh -p 2222 dafu@localhost
FROM alpine:latest
ARG USERNAME=dafu
# public keys are pulled from https://github.com/<GITHUB_USER>.keys at build time
ARG GITHUB_USER=dafu
ARG REPO_URL=https://git.dafu.dev/dafu/dot.config.git
# gid of the docker group on the host, so it lines up with the mounted
# /var/run/docker.sock (check with: stat -c '%g' /var/run/docker.sock)
ARG DOCKER_GID=104
# edge repos, aliased so packages stay on the stable branch by default;
# pull a specific package from edge with `apk add <pkg>@edge`
RUN cat <<'EOF' > /etc/apk/repositories
https://dl-cdn.alpinelinux.org/alpine/edge/main
https://dl-cdn.alpinelinux.org/alpine/edge/community
https://dl-cdn.alpinelinux.org/alpine/edge/testing
EOF
RUN apk update
RUN apk add --no-cache \
dropbear htop fd fzf fzf-tmux gnupg age go-task gopass ripgrep lnav lazygit mysql-client \
nmap p7zip restic rsync shellcheck tree-sitter tree-sitter-cli tree-sitter-go tree-sitter-markdown \
tzdata zk \
git go \
neovim \
tmux \
mksh \
curl \
foot-extra-terminfo \
doas \
docker-cli \
tini
RUN ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime && \
echo "Europe/Berlin" > /etc/timezone
ENV TZ=Europe/Berlin
# make mksh a valid login shell
RUN echo "/bin/mksh" >> /etc/shells
# create the user with mksh as its shell, no password (pubkey-only login)
RUN adduser -D -s /bin/mksh "$USERNAME"
# let the user talk to the docker socket mounted in at runtime without doas:
# reuse whatever group already owns DOCKER_GID, or create "docker" if free
RUN addgroup -g "$DOCKER_GID" docker 2>/dev/null; \
docker_group="$(getent group "$DOCKER_GID" | cut -d: -f1)" && \
addgroup "$USERNAME" "$docker_group"
# passwordless doas for package installs etc. (no password auth is set up
# for the user at all, so this must be nopass)
RUN echo "permit nopass $USERNAME as root" > /etc/doas.conf && \
chown root:root /etc/doas.conf && \
chmod 0400 /etc/doas.conf
# ssh access: authorized_keys sourced from GitHub, pubkey auth only
RUN mkdir -p "/home/$USERNAME/.ssh" && \
curl -fsSL "https://github.com/${GITHUB_USER}.keys" -o "/home/$USERNAME/.ssh/authorized_keys" && \
test -s "/home/$USERNAME/.ssh/authorized_keys" && \
chown -R "$USERNAME:$USERNAME" "/home/$USERNAME/.ssh" && \
chmod 700 "/home/$USERNAME/.ssh" && \
chmod 600 "/home/$USERNAME/.ssh/authorized_keys"
# clone the dotfiles repo and run its installer as the login user
USER $USERNAME
RUN git clone "$REPO_URL" "/home/$USERNAME/.config" && \
"/home/$USERNAME/.config/install.sh"
USER root
RUN mkdir -p /etc/dropbear
# crontab spool lives on the home-data volume so it survives rebuilds; the
# standard /var/spool/cron/crontabs path is symlinked to it so crond and
# `crontab -e` keep working with no extra flags
RUN mkdir -p "/home/$USERNAME/.crontabs" && \
touch "/home/$USERNAME/.crontabs/$USERNAME" && \
chown -R "$USERNAME:$USERNAME" "/home/$USERNAME/.crontabs" && \
chmod 700 "/home/$USERNAME/.crontabs" && \
chmod 600 "/home/$USERNAME/.crontabs/$USERNAME" && \
mkdir -p /var/spool/cron && \
ln -s "/home/$USERNAME/.crontabs" /var/spool/cron/crontabs
RUN <<'EOF' cat > /usr/local/bin/entrypoint.sh
#!/bin/sh
set -e
# host keys are generated on first start rather than at build time, so a
# shared private key never ends up baked into the image.
for t in rsa ed25519; do
key="/etc/dropbear/dropbear_${t}_host_key"
[ -f "$key" ] || dropbearkey -t "$t" -f "$key"
done
# busybox crond daemonizes itself by default (no -f), so this returns
# immediately; tini (real PID 1) reaps it and any of its orphaned children
crond -L /dev/stdout
# -F: foreground, -E: log to stderr, -w: no root login, -s: no password auth
exec dropbear -F -E -w -s -p 22
EOF
RUN chmod +x /usr/local/bin/entrypoint.sh
EXPOSE 22
ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/entrypoint.sh"]
+21
View File
@@ -0,0 +1,21 @@
services:
dev:
build:
context: .
dockerfile: Dockerfile
args:
USERNAME: dafu
GITHUB_USER: dafu
REPO_URL: https://git.dafu.dev/dafu/dot.config.git
DOCKER_GID: "104"
container_name: dev-container
hostname: dev-container
ports:
- "2222:22"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- home-data:/home/dafu
restart: unless-stopped
volumes:
home-data: