modified: README.md modified: compose.yml modified: configuration.py new file: haproxy.cfg new file: init-patroni-users.sql renamed: entrypoint.sh -> netbox-entrypoint.sh renamed: Containerfile -> netbox.Containerfile modified: nginx.conf new file: patroni-entrypoint.sh new file: patroni.Containerfile new file: patroni.yml
163 lines
5.1 KiB
Markdown
163 lines
5.1 KiB
Markdown
# 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
|
|
```
|