|
| 1 | +# Docker & GHCR Publishing Guide |
| 2 | + |
| 3 | +Reference for building, testing, and publishing HMS service Docker images to GitHub Container Registry. |
| 4 | + |
| 5 | +## Quick Reference |
| 6 | + |
| 7 | +```bash |
| 8 | +# Build locally |
| 9 | +docker build -t hms-nut:test . |
| 10 | + |
| 11 | +# Run locally |
| 12 | +docker run --rm \ |
| 13 | + -e MQTT_BROKER=192.168.2.15 \ |
| 14 | + -e NUT_HOST=localhost \ |
| 15 | + -e DB_HOST=192.168.2.15 \ |
| 16 | + hms-nut:test |
| 17 | + |
| 18 | +# Pull from GHCR |
| 19 | +docker pull ghcr.io/hms-homelab/hms-nut:latest |
| 20 | +docker pull ghcr.io/hms-homelab/hms-nut:1.1.1 |
| 21 | +``` |
| 22 | + |
| 23 | +## Architecture |
| 24 | + |
| 25 | +Multi-stage Dockerfile: |
| 26 | +- **Builder stage:** `debian:trixie-slim` with full build toolchain |
| 27 | +- **Runtime stage:** `debian:trixie-slim` with minimal runtime libs |
| 28 | +- **Platforms:** `linux/amd64`, `linux/arm64` |
| 29 | +- **Image size:** ~108 MB |
| 30 | + |
| 31 | +### Why Trixie (Debian 13)? |
| 32 | + |
| 33 | +Drogon framework (`libdrogon-dev`) is not available in Debian bookworm (12). Trixie provides it as a native package, avoiding the need to build Drogon from source (which would break multi-arch QEMU builds). |
| 34 | + |
| 35 | +## Drogon Dependency Chain |
| 36 | + |
| 37 | +Drogon's cmake config requires **all** its optional database backends at cmake time, even if not used. The builder stage must include: |
| 38 | + |
| 39 | +```dockerfile |
| 40 | +RUN apt-get install -y --no-install-recommends \ |
| 41 | + libdrogon-dev \ # Drogon framework |
| 42 | + libsqlite3-dev \ # Required by Drogon cmake |
| 43 | + default-libmysqlclient-dev \ # Required by Drogon cmake |
| 44 | + libhiredis-dev \ # Required by Drogon cmake (Redis) |
| 45 | + libyaml-cpp-dev \ # Required by Drogon cmake |
| 46 | + ... |
| 47 | +``` |
| 48 | + |
| 49 | +The runtime stage only needs `libdrogon1t64` — its transitive deps are pulled automatically. |
| 50 | + |
| 51 | +## libpqxx Compatibility |
| 52 | + |
| 53 | +Trixie ships `libpqxx-7.10` (dev: `libpqxx-dev`). In libpqxx 6.x and 7.x, `pqxx::connection::close()` is protected. Use `conn_.reset()` instead: |
| 54 | + |
| 55 | +```cpp |
| 56 | +// BAD: won't compile with libpqxx 6.x/7.x in Docker |
| 57 | +conn_->close(); |
| 58 | + |
| 59 | +// GOOD: works across all versions |
| 60 | +conn_.reset(); |
| 61 | +``` |
| 62 | + |
| 63 | +## NUT Package Names |
| 64 | + |
| 65 | +| Debian Version | Dev Package | Runtime Package | |
| 66 | +|---------------|-------------|-----------------| |
| 67 | +| Bookworm (12) | `libnut-dev` | `libupsclient6` | |
| 68 | +| Trixie (13) | `libupsclient-dev` | `libupsclient6t64` | |
| 69 | + |
| 70 | +Both provide `<upsclient.h>` — the API is the same. |
| 71 | + |
| 72 | +## CI/CD Workflow |
| 73 | + |
| 74 | +`.github/workflows/docker-build.yml` triggers on: |
| 75 | +- Push to `main`/`master`/`develop` branches |
| 76 | +- Version tags (`v*`) |
| 77 | +- Pull requests (build only, no push) |
| 78 | + |
| 79 | +### Tag Strategy |
| 80 | + |
| 81 | +| Event | Tags Generated | |
| 82 | +|-------|---------------| |
| 83 | +| Push to main | `latest`, `main`, `sha-abc1234` | |
| 84 | +| Tag `v1.1.1` | `1.1.1`, `1.1`, `sha-abc1234` | |
| 85 | +| PR | `pr-42` (not pushed) | |
| 86 | + |
| 87 | +### Triggering a Release |
| 88 | + |
| 89 | +```bash |
| 90 | +# Bump VERSION file |
| 91 | +echo "1.1.2" > VERSION |
| 92 | + |
| 93 | +# Update CHANGELOG.md |
| 94 | + |
| 95 | +# Commit, tag, push |
| 96 | +git add -A && git commit -m "release: v1.1.2" |
| 97 | +git tag v1.1.2 |
| 98 | +git push origin main && git push origin v1.1.2 |
| 99 | +``` |
| 100 | + |
| 101 | +## Required Files Checklist |
| 102 | + |
| 103 | +For any HMS service to publish to GHCR: |
| 104 | + |
| 105 | +- [ ] `Dockerfile` — Multi-stage build, non-root user, health check, `strip` binary |
| 106 | +- [ ] `.dockerignore` — Exclude `build/`, `.git/`, `tests/`, `docs/`, `sysroot/` |
| 107 | +- [ ] `.github/workflows/docker-build.yml` — CI workflow |
| 108 | +- [ ] `VERSION` — Semver string |
| 109 | +- [ ] `LICENSE` — MIT |
| 110 | +- [ ] `CHANGELOG.md` — Keep a Changelog format |
| 111 | + |
| 112 | +## Troubleshooting |
| 113 | + |
| 114 | +### "Unable to locate package" in runtime stage |
| 115 | + |
| 116 | +Trixie renamed many packages with `t64` suffix (64-bit time_t transition). Check: |
| 117 | +```bash |
| 118 | +docker run --rm debian:trixie-slim bash -c \ |
| 119 | + "apt-get update -qq 2>/dev/null && apt-cache search <keyword>" |
| 120 | +``` |
| 121 | + |
| 122 | +### arm64 build fails but amd64 works |
| 123 | + |
| 124 | +QEMU emulation can break source compilation (especially OpenSSL cross-compile). Always prefer Debian repo packages over building from source. |
| 125 | + |
| 126 | +### Drogon cmake error "Could NOT find X" |
| 127 | + |
| 128 | +Add the missing `-dev` package to the builder stage. Drogon demands SQLite3, MySQL, hiredis, and yaml-cpp headers at cmake time. |
0 commit comments