# Netbox Stack This project provides a fully working Netbox Installation connected to a BIND9 Server for DNS distribution. Further components like acme certificate management will be added eventually. ## Build images You can either build the netbox and patroni-postgres containers yourself or let compose pull them from the repository at git.luethi.co. Note that the reason i pushed all images to my repo that compose relies on is simply convenience and reducing load on dockerhub. You can modify `compose.yml` to source all but the `netbox` and `patroni-postgres` images from dockerhub instead. ```bash # Build all images (bakes in netbox plugins + patroni) podman-compose --podman-build-args '\-\-network=host' build ``` ## Start the Stack via compose ```bash # Start the full stack (etcd + patroni HA + netbox) podman compose up -d ``` --- ## Building the image directly without compose ```bash # NetBox podman build \ -f netbox.Containerfile \ --build-arg PYTHON_VERSION=3.14 \ --build-arg NETBOX_VERSION=4.6.5 \ --tag localhost/netbox:4.6.5 \ . # Patroni-Postgres podman build \ -f patroni.Containerfile \ --build-arg POSTGRES_VERSION=16 \ --tag localhost/patroni-postgres:16 \ . ``` --- ## Updating NetBox 1. Bump `PYTHON_VERSION` and `NETBOX_VERSION` in `.env` 2. Rebuild: `podman-compose --podman-build-args '\-\-network=host build --no-cache` 3. Restart: `podman-compose up -d` Migrations run automatically on startup via the entrypoint. --- ## PostgreSQL HA with Patroni PostgreSQL runs as a 3-node Patroni cluster (1 leader + 2 replicas) with etcd as the Distributed Configuration Store (DCS). HAProxy routes write traffic to the current leader via Patroni REST API health checks. ### Architecture ``` ┌──────────────┐ │ etcd │ :2379 └──────┬───────┘ │ ┌───────────────────┼───────────────────┐ │ │ │ ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ │ patroni1 │ │ patroni2 │ │ patroni3 │ │ pg :5432 │ │ pg :5433 │ │ pg :5434 │ │ api :8008 │ │ api :8009 │ │ api :8010 │ │ (leader) │◄───│ (replica) │◄───│ (replica) │ └──────┬──────┘ └─────────────┘ └─────────────┘ │ ┌──────▼──────┐ │ HAProxy │ :5000 → leader :7000 → stats └──────┬──────┘ │ ┌──────▼──────┐ │ NetBox │ connects to localhost:5000 └─────────────┘ ``` ### Ports | Service | PostgreSQL | Patroni API | |----------|-----------|-------------| | patroni1 | 5432 | 8008 | | patroni2 | 5433 | 8009 | | patroni3 | 5434 | 8010 | HAProxy listens on :5000 (write) and :7000 (stats UI). ### Cluster management ```bash # Show cluster topology podman exec patroni1 patronictl list # Switchover (planned leader change) podman exec patroni1 patronictl switchover # Check cluster health curl http://localhost:8008/health curl http://localhost:8008/cluster | jq . # HAProxy stats UI open http://localhost:7000 ``` ### Converting existing standalone PostgreSQL to Patroni If you have an existing `postgres_data` volume from the old standalone postgres service, follow these steps to convert it to a Patroni-managed cluster: 1. **Stop the stack:** ```bash podman compose down ``` 2. **Start only the old postgres temporarily** to create Patroni users: ```bash podman compose run --rm --no-deps postgres \ psql -U netbox -d netbox -f /init-patroni-users.sql ``` *(If the `postgres` service no longer exists in compose, use any postgres 16-alpine container with the same volume mounted.)* 3. **Update pg_hba.conf** in the existing data volume to allow replication: ```bash echo 'host replication replicator 0.0.0.0/0 md5' >> \ /var/lib/containers/storage/volumes/netbox_postgres_data/_data/pg_hba.conf ``` 4. **Start the new Patroni stack:** ```bash podman compose up -d ``` - patroni1 detects the existing data and takes over management without re-initializing. - patroni2 and patroni3 start with empty data dirs and are bootstrapped as replicas via `pg_basebackup` from patroni1. 5. **Verify:** ```bash podman exec patroni1 patronictl list ``` Should show 1 Leader + 2 Replicas in `running` / `streaming` state. ### Fresh start (no existing data) If you don't need to preserve existing data, simply remove the old volume and start fresh — Patroni will run `initdb` on patroni1 and bootstrap replicas: ```bash podman volume rm netbox_postgres_data podman compose up -d ```