# broker-control — internal control sidecar (spec §29) # # PID-namespace OWNER: the broker joins THIS container's PID namespace # (compose `pid: "service:mosquitto-control"` on the mosquitto service). # Owning the namespace means the sidecar survives broker restarts — it # was previously the other way around and the kernel killed the sidecar # whenever the broker exited. tini runs as PID 1: it forwards signals to # python and reaps the broker's zombies (the broker re-parents to tini # when its container entrypoint forks). # # Responsibilities (deliberately minimal, spec §29): # - validate staged configuration (mosquitto -c --test-config) # - activate a configuration revision (atomic rename into place) # - signal config reload (mosquitto_signal -p config-reload) # - signal broker restart (SIGTERM; Docker policy revives the broker) # - check broker process state FROM eclipse-mosquitto:2.1.2-alpine # Same image as the broker → --test-config validates with the exact # broker binary that will load the config. # The base image ships NO Python. control.py is stdlib-only, so the # distro package is sufficient (no pip, no venv needed). # tini: minimal init as PID 1 — signal forwarding + zombie reaping. RUN apk add --no-cache python3 tini COPY control.py /app/control.py # The base image has no USER directive, so this sidecar runs as root. # Deliberate: it writes /mosquitto/config (owned by uid 1883 in the fresh # volume) and signals the broker via the shared PID namespace. The API # is token-guarded, internal-network-only, and no docker.sock is mounted # (spec §29). # Clear the CMD inherited from the base image — its default CMD # (`mosquitto -c ...`) would otherwise be appended to our entrypoint. CMD [] EXPOSE 8090 ENTRYPOINT ["/sbin/tini", "--", "python3", "/app/control.py"]