# ─────────────────────────────────────────────────────────── # Alpine Docker Host — Minimal QEMU-Bootable Image # # Purpose: Temporary Docker host running on QEMU (pc-q35-10.0) # atop Windows VMs in traditional deployments. Provides the # Docker daemon that the Ansible control node container runs on. # # What it IS: # • Alpine Linux 3.20 with OpenRC (no systemd) # • Docker daemon + CLI # • SSH server for remote management # • QEMU-bootable via build-qemu.sh # # What it is NOT: # • No Ansible (deployed as a separate container) # • No GCC or build tools # • No Python pip packages # • No quality-of-life packages # # Target size: ~200MB Docker image → ~250MB qcow2 # ─────────────────────────────────────────────────────────── FROM alpine:3.20 LABEL org.opencontainers.image.title="Alpine Docker Host (QEMU)" LABEL org.opencontainers.image.description="Minimal Alpine Linux with Docker daemon for QEMU pc-q35-10.0. Boots in ~6s." # ── Core system (no bloat) ───────────────────────────────── RUN apk add --no-cache \ alpine-base \ linux-virt \ e2fsprogs \ docker \ docker-openrc \ docker-cli-compose \ openssh-server \ openssh-client \ dhcpcd \ sudo \ curl \ ca-certificates \ util-linux \ python3 # ── OpenRC: enable just what's needed ────────────────────── RUN rc-update add devfs sysinit && \ rc-update add dmesg sysinit && \ rc-update add mdev sysinit && \ rc-update add hwdrivers sysinit && \ rc-update add modules boot && \ rc-update add sysctl boot && \ rc-update add bootmisc boot && \ rc-update add hostname boot && \ rc-update add networking boot && \ rc-update add sshd default && \ rc-update add dhcpcd default && \ rc-update add docker default # ── TTY menu: auto-launch on serial console ──────────────── # Uses agetty -l to replace /bin/login with the menu script COPY scripts/tty-menu.sh /usr/local/bin/tty-menu.sh RUN chmod +x /usr/local/bin/tty-menu.sh && \ echo 'ttyS0::respawn:/sbin/agetty -L 115200 ttyS0 xterm-256color -l /usr/local/bin/tty-menu.sh' \ >> /etc/inittab # ── Web UI ──────────────────────────────────────────────── COPY webui/app.py /usr/local/bin/webui.py RUN chmod +x /usr/local/bin/webui.py # OpenRC service for the web UI RUN printf '#!/sbin/openrc-run\n\ name="webui"\n\ description="IEC 62443-3-3 Web UI"\n\ command="/usr/bin/python3"\n\ command_args="/usr/local/bin/webui.py"\n\ command_background=true\n\ pidfile="/run/webui.pid"\n\ depend() {\n\ need net docker\n\ }\n' \ > /etc/init.d/webui && \ chmod +x /etc/init.d/webui && \ rc-update add webui default # ── Shared directories (host ↔ ansible container) ───────── RUN mkdir -p /ansible/playbooks /ansible/reports /ansible/inventory && \ chown -R ansible:ansible /ansible # ── Hostname ────────────────────────────────────────────── RUN echo 'alpine-docker' > /etc/hostname # ── SSH configuration ───────────────────────────────────── RUN ssh-keygen -A && \ sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' \ /etc/ssh/sshd_config && \ sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' \ /etc/ssh/sshd_config && \ echo 'UseDNS no' >> /etc/ssh/sshd_config # ── Users ───────────────────────────────────────────────── RUN echo 'root:ansible' | chpasswd && \ adduser -D ansible && \ echo 'ansible:ansible' | chpasswd && \ addgroup ansible wheel && \ addgroup ansible docker && \ echo '%wheel ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers # ── First-boot: expand rootfs, regenerate SSH host keys ──── RUN printf '#!/bin/sh\n\ ROOTDEV=$(findmnt -n -o SOURCE / 2>/dev/null || echo /dev/vda)\n\ resize2fs "$ROOTDEV" 2>/dev/null || true\n\ if [ ! -f /etc/ssh/.host-keys-generated ]; then\n\ ssh-keygen -A && touch /etc/ssh/.host-keys-generated\n\ fi\n' \ > /etc/local.d/00-first-boot.start && \ chmod +x /etc/local.d/00-first-boot.start && \ rc-update add local default # ── MOTD ────────────────────────────────────────────────── RUN printf '\n\ \e[1;34m╔════════════════════════════════════════════════╗\e[0m\n\ \e[1;34m║ Alpine Docker Host — QEMU pc-q35-10.0 ║\e[0m\n\ \e[1;34m╠════════════════════════════════════════════════╣\e[0m\n\ \e[1;34m║ TTY: This console (auto-menu) ║\e[0m\n\ \e[1;34m║ Web UI: http://:8080 ║\e[0m\n\ \e[1;34m║ SSH: ssh ansible@ -p 22 ║\e[0m\n\ \e[1;34m║ Pass: ansible ║\e[0m\n\ \e[1;34m╚════════════════════════════════════════════════╝\e[0m\n\ ' > /etc/motd WORKDIR /root CMD ["/sbin/init"]