deploy / validate (push) Skipped
renovate-ci / validate-renovate (push) Skipped
ci / lint-dockerfiles (push) Successful in 1s
ci / validate (push) Successful in 1s
ci / build (push) Skipped
ci / lint-prettier (pull_request) Successful in 3s
ci / lint-ruff (pull_request) Successful in 0s
ci / lint-yaml (pull_request) Successful in 2s
ci / validate (pull_request) Successful in 1s
ci / build (pull_request) Skipped
renovate-ci / validate-renovate (pull_request) Successful in 8s
ci / lint-prettier (push) Successful in 2s
ci / lint-ruff (push) Successful in 1s
ci / lint-yaml (push) Successful in 2s
ci / lint-dockerfiles (pull_request) Successful in 1s
97 lines
4.4 KiB
Markdown
97 lines
4.4 KiB
Markdown
# NetBox
|
|
|
|
NetBox for homelab documentation and visualization. Two runtimes are available:
|
|
|
|
| Runtime | Manifest | Purpose |
|
|
| ------- | -------------- | -------------------------------------------------------------- |
|
|
| Docker | `compose.yaml` | Local stand on `127.0.0.1:8000` (no public exposure) |
|
|
| k8s | `k8s/` | Homelab service on `netbox.forust.xyz` (and the internal name) |
|
|
|
|
Both use the same image (`netboxcommunity/netbox:v4.7-5.1.1`) and Valkey for tasks
|
|
plus a second logical database for caching. The Docker stand keeps its own
|
|
PostgreSQL container, while the k8s deployment uses the shared `database` cluster
|
|
(`postgres.database.svc.cluster.local:5432`, role/database `netbox`); only Valkey
|
|
stays a per-service StatefulSet.
|
|
|
|
## Docker Compose
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
# replace CHANGE_ME
|
|
docker compose up -d
|
|
```
|
|
|
|
The UI is available at <http://localhost:8000>. The port is bound to `127.0.0.1`
|
|
intentionally, so this stand is not exposed on the LAN or public interfaces.
|
|
|
|
The `netbox` service is also attached to the external `proxy` network and carries
|
|
Traefik labels for `netbox.forust.xyz` and `netbox.workstation.internal`. Those
|
|
labels only take effect while the Docker Traefik stack is running; it is currently
|
|
stopped, and the live ingress path in this homelab is the k8s Traefik.
|
|
|
|
Inspect startup and health with:
|
|
|
|
```bash
|
|
docker compose ps
|
|
docker compose logs -f netbox
|
|
```
|
|
|
|
Stop it with `docker compose down`; data is kept in the named volumes
|
|
`netbox-postgres`, `netbox-media-files`, `netbox-reports-files`,
|
|
`netbox-scripts-files` and `netbox-redis-data`.
|
|
|
|
## Kubernetes
|
|
|
|
`k8s/` is deployed in the homelab cluster and serves `netbox.forust.xyz` publicly
|
|
plus `netbox.workstation.internal` / `netbox.gigaforust.internal` internally. To
|
|
rebuild it from scratch:
|
|
|
|
```bash
|
|
# 1. shared PostgreSQL: the password lives in the shared secret, NetBox keeps a copy
|
|
kubectl -n database patch secret postgres-shared-secrets \
|
|
--type merge -p '{"stringData":{"NETBOX_DB_PASSWORD":"<same value>"}}'
|
|
kubectl -n database exec postgres17-0 -- psql -U postgres -d postgres \
|
|
-c 'CREATE ROLE netbox LOGIN PASSWORD ...' -c 'CREATE DATABASE netbox OWNER netbox'
|
|
|
|
# 2. secrets first: the deploy workflow never applies *secret*.yaml
|
|
cp k8s/secrets.yaml.example k8s/secrets.yaml # replace CHANGE_ME
|
|
kubectl apply -f k8s/secrets.yaml
|
|
|
|
# 3. manifests
|
|
kubectl apply -f k8s/
|
|
```
|
|
|
|
The shared cluster is reached at `postgres.database.svc.cluster.local:5432`. Its
|
|
NetworkPolicy (`postgres/k8s/network-policy.yaml`) must list the `netbox` namespace
|
|
or connections are dropped, and `postgres/initdb/01-create-databases.sh` already
|
|
creates the role and database on a fresh data directory. NetBox has no PostgreSQL
|
|
StatefulSet of its own — only `netbox-valkey`.
|
|
|
|
`netbox.forust.xyz` resolves to this host (`78.98.72.122`) through the `DOMAINS`
|
|
list in the `default/cfddns` secret. cert-manager issues `netbox-prod-tls` with the
|
|
`letsencrypt-prod` issuer, the internal route uses `internal-wildcard-tls`.
|
|
|
|
Resources are permanent again now that the first-boot migrations are complete:
|
|
the web container reserves `100m`/`512Mi` and is capped at `2` CPU/`2Gi`, the
|
|
worker reserves `50m`/`256Mi` and is capped at `1` CPU/`1Gi`, and Valkey reserves
|
|
`25m`/`64Mi` and is capped at `250m`/`256Mi`. The deliberately generous CPU caps
|
|
leave enough headroom for future schema migrations without letting one process
|
|
consume the whole node.
|
|
|
|
The first start applies ~810 migrations, each in its own transaction with DDL and
|
|
a commit; every later start is a no-op. The startup probe allows 15 minutes and
|
|
`progressDeadlineSeconds` is 1800 for the same reason. Probes run inside the pod
|
|
and explicitly set `Host: netbox.forust.xyz`; a kubelet `httpGet.host` field would
|
|
replace the probe destination with that public hostname and bypass the pod.
|
|
|
|
## Secrets
|
|
|
|
- `netbox/.env` (compose) and `netbox/k8s/secrets.yaml` (k8s) are gitignored. Only
|
|
`.env.example` and `k8s/secrets.yaml.example` are committed.
|
|
- `netbox/configuration/configuration.py` is env-driven: hosts, database, Redis and
|
|
the Django keys all come from the environment, so the same settings file works in
|
|
both runtimes. The k8s copy lives in the `netbox-settings` ConfigMap
|
|
(`k8s/settings.yaml`) and must be kept in sync with the file.
|
|
- Rotating `SECRET_KEY` invalidates all sessions; rotating `API_TOKEN_PEPPER_1`
|
|
invalidates every API token.
|