Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7ee7d0c961 | ||
|
|
71e769c002 | ||
|
|
16dd67c2c0 | ||
|
|
c536a16a2a |
No files matched your search
@@ -89,27 +89,10 @@ stage_validate() {
|
|||||||
cd "$REPO"
|
cd "$REPO"
|
||||||
select_manifests
|
select_manifests
|
||||||
local m k cf
|
local m k cf
|
||||||
# Compose .env files and secret files are gitignored by design, so the
|
|
||||||
# workstation never has real values for them. Validate structure only:
|
|
||||||
# skip interpolation, env-file resolution, and path resolution so that
|
|
||||||
# required-variable guards (:?) and missing local files don't fail CI.
|
|
||||||
# Normalization and consistency checks stay enabled.
|
|
||||||
local compose_validate_flags=()
|
|
||||||
local compose_config_help
|
|
||||||
compose_config_help="$(docker compose config --help 2>/dev/null || true)"
|
|
||||||
if printf '%s' "$compose_config_help" | grep -q -- '--no-interpolate'; then
|
|
||||||
compose_validate_flags+=(--no-interpolate)
|
|
||||||
fi
|
|
||||||
if printf '%s' "$compose_config_help" | grep -q -- '--no-env-resolution'; then
|
|
||||||
compose_validate_flags+=(--no-env-resolution)
|
|
||||||
fi
|
|
||||||
if printf '%s' "$compose_config_help" | grep -q -- '--no-path-resolution'; then
|
|
||||||
compose_validate_flags+=(--no-path-resolution)
|
|
||||||
fi
|
|
||||||
log "Validate compose stacks"
|
log "Validate compose stacks"
|
||||||
for cf in ${COMPOSE_STACKS[@]+"${COMPOSE_STACKS[@]}"}; do
|
for cf in ${COMPOSE_STACKS[@]+"${COMPOSE_STACKS[@]}"}; do
|
||||||
echo " config: $cf"
|
echo " config: $cf"
|
||||||
docker compose -f "$cf" config --quiet "${compose_validate_flags[@]}"
|
docker compose -f "$cf" config --quiet
|
||||||
done
|
done
|
||||||
log "Validate k8s manifests (kubectl dry-run=client)"
|
log "Validate k8s manifests (kubectl dry-run=client)"
|
||||||
for m in ${K8S_MANIFESTS[@]+"${K8S_MANIFESTS[@]}"}; do
|
for m in ${K8S_MANIFESTS[@]+"${K8S_MANIFESTS[@]}"}; do
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
POSTGRES_DB=netbox
|
||||||
|
POSTGRES_USER=netbox
|
||||||
|
POSTGRES_PASSWORD=CHANGE_ME_POSTGRES_PASSWORD
|
||||||
|
|
||||||
|
DB_NAME=netbox
|
||||||
|
DB_USER=netbox
|
||||||
|
DB_PASSWORD=CHANGE_ME_POSTGRES_PASSWORD
|
||||||
|
DB_HOST=postgres
|
||||||
|
DB_PORT=5432
|
||||||
|
DB_SSLMODE=disable
|
||||||
|
|
||||||
|
REDIS_HOST=redis
|
||||||
|
REDIS_PORT=6379
|
||||||
|
REDIS_PASSWORD=CHANGE_ME_REDIS_PASSWORD
|
||||||
|
REDIS_DATABASE=0
|
||||||
|
REDIS_CACHE_HOST=redis-cache
|
||||||
|
REDIS_CACHE_PORT=6379
|
||||||
|
REDIS_CACHE_PASSWORD=CHANGE_ME_REDIS_CACHE_PASSWORD
|
||||||
|
REDIS_CACHE_DATABASE=1
|
||||||
|
|
||||||
|
ALLOWED_HOSTS=localhost,127.0.0.1,[::1],netbox.forust.xyz,netbox.workstation.internal
|
||||||
|
CSRF_TRUSTED_ORIGINS=https://netbox.forust.xyz,https://netbox.workstation.internal
|
||||||
|
|
||||||
|
SECRET_KEY=CHANGE_ME_DJANGO_SECRET_KEY
|
||||||
|
API_TOKEN_PEPPER_1=CHANGE_ME_API_TOKEN_PEPPER
|
||||||
|
TIME_ZONE=Europe/Bratislava
|
||||||
|
TZ=Europe/Bratislava
|
||||||
|
|
||||||
|
SKIP_SUPERUSER=false
|
||||||
|
SUPERUSER_NAME=admin
|
||||||
|
SUPERUSER_EMAIL=admin@example.com
|
||||||
|
SUPERUSER_PASSWORD=CHANGE_ME_SUPERUSER_PASSWORD
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
# 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.
|
||||||
File renamed without changes.
@@ -0,0 +1,137 @@
|
|||||||
|
services:
|
||||||
|
netbox:
|
||||||
|
image: docker.io/netboxcommunity/netbox:v4.7-5.1.1
|
||||||
|
container_name: netbox
|
||||||
|
restart: unless-stopped
|
||||||
|
user: "netbox:root"
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:8000:8080"
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
GRANIAN_WORKERS: "2"
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
redis-cache:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- ./configuration:/etc/netbox/config:z,ro
|
||||||
|
- netbox-media-files:/opt/netbox/netbox/media
|
||||||
|
- netbox-reports-files:/opt/netbox/netbox/reports
|
||||||
|
- netbox-scripts-files:/opt/netbox/netbox/scripts
|
||||||
|
networks:
|
||||||
|
- default
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.services.netbox.loadbalancer.server.port=8080"
|
||||||
|
|
||||||
|
# Prod Router
|
||||||
|
- "traefik.http.routers.netbox.rule=Host(`netbox.forust.xyz`)"
|
||||||
|
- "traefik.http.routers.netbox.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.netbox.middlewares=security-headers@file"
|
||||||
|
- "traefik.http.routers.netbox.tls.certresolver=letsencrypt"
|
||||||
|
# Local Router
|
||||||
|
- "traefik.http.routers.netbox-local.rule=Host(`netbox.workstation.internal`)"
|
||||||
|
- "traefik.http.routers.netbox-local.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.netbox-local.tls=true"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "/opt/netbox/health.sh"]
|
||||||
|
start_period: 600s
|
||||||
|
timeout: 5s
|
||||||
|
interval: 15s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
|
netbox-worker:
|
||||||
|
image: docker.io/netboxcommunity/netbox:v4.7-5.1.1
|
||||||
|
container_name: netbox-worker
|
||||||
|
restart: unless-stopped
|
||||||
|
user: "netbox:root"
|
||||||
|
command:
|
||||||
|
- /opt/netbox/venv/bin/python
|
||||||
|
- /opt/netbox/netbox/manage.py
|
||||||
|
- rqworker
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
depends_on:
|
||||||
|
netbox:
|
||||||
|
condition: service_healthy
|
||||||
|
volumes:
|
||||||
|
- ./configuration:/etc/netbox/config:z,ro
|
||||||
|
- netbox-media-files:/opt/netbox/netbox/media
|
||||||
|
- netbox-reports-files:/opt/netbox/netbox/reports
|
||||||
|
- netbox-scripts-files:/opt/netbox/netbox/scripts
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "ps -ef | grep -q '[r]qworker'"]
|
||||||
|
start_period: 30s
|
||||||
|
timeout: 5s
|
||||||
|
interval: 15s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: docker.io/postgres:18.6-alpine
|
||||||
|
container_name: netbox-postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: "${POSTGRES_DB:?POSTGRES_DB must be set}"
|
||||||
|
POSTGRES_USER: "${POSTGRES_USER:?POSTGRES_USER must be set}"
|
||||||
|
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD must be set}"
|
||||||
|
volumes:
|
||||||
|
- netbox-postgres:/var/lib/postgresql
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", 'pg_isready -q -t 2 -d "$${POSTGRES_DB}" -U "$${POSTGRES_USER}"']
|
||||||
|
start_period: 20s
|
||||||
|
timeout: 5s
|
||||||
|
interval: 10s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: docker.io/valkey/valkey:9.1.2-alpine
|
||||||
|
container_name: netbox-redis
|
||||||
|
restart: unless-stopped
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- valkey-server --appendonly yes --requirepass "$$REDIS_PASSWORD"
|
||||||
|
environment:
|
||||||
|
REDIS_PASSWORD: "${REDIS_PASSWORD:?REDIS_PASSWORD must be set}"
|
||||||
|
volumes:
|
||||||
|
- netbox-redis-data:/data
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", 'valkey-cli --pass "$${REDIS_PASSWORD}" ping | grep -q PONG']
|
||||||
|
start_period: 5s
|
||||||
|
timeout: 5s
|
||||||
|
interval: 5s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
|
redis-cache:
|
||||||
|
image: docker.io/valkey/valkey:9.1.2-alpine
|
||||||
|
container_name: netbox-redis-cache
|
||||||
|
restart: unless-stopped
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- valkey-server --requirepass "$$REDIS_CACHE_PASSWORD"
|
||||||
|
environment:
|
||||||
|
REDIS_CACHE_PASSWORD: "${REDIS_CACHE_PASSWORD:?REDIS_CACHE_PASSWORD must be set}"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", 'valkey-cli --pass "$${REDIS_CACHE_PASSWORD}" ping | grep -q PONG']
|
||||||
|
start_period: 5s
|
||||||
|
timeout: 5s
|
||||||
|
interval: 5s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
netbox-media-files:
|
||||||
|
netbox-reports-files:
|
||||||
|
netbox-scripts-files:
|
||||||
|
netbox-postgres:
|
||||||
|
netbox-redis-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def _csv(name, default=""):
|
||||||
|
return [item.strip() for item in os.environ.get(name, default).split(",") if item.strip()]
|
||||||
|
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = _csv("ALLOWED_HOSTS", "localhost,127.0.0.1,[::1]")
|
||||||
|
CSRF_TRUSTED_ORIGINS = _csv("CSRF_TRUSTED_ORIGINS")
|
||||||
|
USE_X_FORWARDED_HOST = True
|
||||||
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
"default": {
|
||||||
|
"NAME": os.environ["DB_NAME"],
|
||||||
|
"USER": os.environ["DB_USER"],
|
||||||
|
"PASSWORD": os.environ["DB_PASSWORD"],
|
||||||
|
"HOST": os.environ["DB_HOST"],
|
||||||
|
"PORT": os.environ.get("DB_PORT", "5432"),
|
||||||
|
"OPTIONS": {"sslmode": os.environ.get("DB_SSLMODE", "disable")},
|
||||||
|
"CONN_MAX_AGE": int(os.environ.get("DB_CONN_MAX_AGE", "300")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REDIS = {
|
||||||
|
"tasks": {
|
||||||
|
"HOST": os.environ["REDIS_HOST"],
|
||||||
|
"PORT": int(os.environ.get("REDIS_PORT", "6379")),
|
||||||
|
"PASSWORD": os.environ["REDIS_PASSWORD"],
|
||||||
|
"DATABASE": int(os.environ.get("REDIS_DATABASE", "0")),
|
||||||
|
"SSL": False,
|
||||||
|
},
|
||||||
|
"caching": {
|
||||||
|
"HOST": os.environ["REDIS_CACHE_HOST"],
|
||||||
|
"PORT": int(os.environ.get("REDIS_CACHE_PORT", "6379")),
|
||||||
|
"PASSWORD": os.environ["REDIS_CACHE_PASSWORD"],
|
||||||
|
"DATABASE": int(os.environ.get("REDIS_CACHE_DATABASE", "1")),
|
||||||
|
"SSL": False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
SECRET_KEY = os.environ["SECRET_KEY"]
|
||||||
|
API_TOKEN_PEPPERS = {1: os.environ["API_TOKEN_PEPPER_1"]}
|
||||||
|
TIME_ZONE = os.environ.get("TIME_ZONE", "UTC")
|
||||||
|
MEDIA_ROOT = "/opt/netbox/netbox/media"
|
||||||
|
REPORTS_ROOT = "/opt/netbox/netbox/reports"
|
||||||
|
SCRIPTS_ROOT = "/opt/netbox/netbox/scripts"
|
||||||
|
CENSUS_REPORTING_ENABLED = False
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: netbox-prod-tls
|
||||||
|
namespace: netbox
|
||||||
|
spec:
|
||||||
|
secretName: netbox-prod-tls
|
||||||
|
dnsNames:
|
||||||
|
- netbox.forust.xyz
|
||||||
|
issuerRef:
|
||||||
|
name: letsencrypt-prod
|
||||||
|
kind: ClusterIssuer
|
||||||
|
---
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: internal-wildcard-tls
|
||||||
|
namespace: netbox
|
||||||
|
spec:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
|
dnsNames:
|
||||||
|
- "*.workstation.internal"
|
||||||
|
- "*.gigaforust.internal"
|
||||||
|
- workstation.internal
|
||||||
|
- gigaforust.internal
|
||||||
|
issuerRef:
|
||||||
|
name: internal-ca
|
||||||
|
kind: ClusterIssuer
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: netbox-config
|
||||||
|
namespace: netbox
|
||||||
|
data:
|
||||||
|
DB_HOST: "postgres.database.svc.cluster.local"
|
||||||
|
DB_PORT: "5432"
|
||||||
|
DB_SSLMODE: "disable"
|
||||||
|
REDIS_HOST: "netbox-valkey"
|
||||||
|
REDIS_PORT: "6379"
|
||||||
|
REDIS_DATABASE: "0"
|
||||||
|
REDIS_CACHE_HOST: "netbox-valkey"
|
||||||
|
REDIS_CACHE_PORT: "6379"
|
||||||
|
REDIS_CACHE_DATABASE: "1"
|
||||||
|
TIME_ZONE: "Europe/Bratislava"
|
||||||
|
TZ: "Europe/Bratislava"
|
||||||
|
GRANIAN_WORKERS: "2"
|
||||||
|
ALLOWED_HOSTS: "netbox.forust.xyz,netbox.workstation.internal,netbox.gigaforust.internal"
|
||||||
|
CSRF_TRUSTED_ORIGINS: "https://netbox.forust.xyz,https://netbox.workstation.internal,https://netbox.gigaforust.internal"
|
||||||
|
SKIP_SUPERUSER: "false"
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: netbox-prod
|
||||||
|
namespace: netbox
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`netbox.forust.xyz`)
|
||||||
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
|
services:
|
||||||
|
- name: netbox-service
|
||||||
|
port: 8080
|
||||||
|
tls:
|
||||||
|
secretName: netbox-prod-tls
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: netbox-local
|
||||||
|
namespace: netbox
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`netbox.workstation.internal`) || Host(`netbox.gigaforust.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: netbox-service
|
||||||
|
port: 8080
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: netbox
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: netbox-service
|
||||||
|
namespace: netbox
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: netbox
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 8080
|
||||||
|
targetPort: http
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: netbox-deployment
|
||||||
|
namespace: netbox
|
||||||
|
labels:
|
||||||
|
app: netbox
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
progressDeadlineSeconds: 300
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: netbox
|
||||||
|
strategy:
|
||||||
|
# ReadWriteOnce PVC
|
||||||
|
type: Recreate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: netbox
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: netbox
|
||||||
|
image: docker.io/netboxcommunity/netbox:v4.7-5.1.1
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 8080
|
||||||
|
envFrom:
|
||||||
|
- configMapRef:
|
||||||
|
name: netbox-config
|
||||||
|
- secretRef:
|
||||||
|
name: netbox-secrets
|
||||||
|
volumeMounts:
|
||||||
|
- name: netbox-config
|
||||||
|
mountPath: /etc/netbox/config
|
||||||
|
readOnly: true
|
||||||
|
- name: netbox-media
|
||||||
|
mountPath: /opt/netbox/netbox/media
|
||||||
|
- name: netbox-reports
|
||||||
|
mountPath: /opt/netbox/netbox/reports
|
||||||
|
- name: netbox-scripts
|
||||||
|
mountPath: /opt/netbox/netbox/scripts
|
||||||
|
startupProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- /opt/netbox/venv/bin/python
|
||||||
|
- -c
|
||||||
|
- >-
|
||||||
|
exec /usr/bin/curl --fail --silent --show-error --max-time 4
|
||||||
|
--header 'Host: netbox.forust.xyz'
|
||||||
|
http://127.0.0.1:8080/login/ >/dev/null
|
||||||
|
failureThreshold: 90
|
||||||
|
periodSeconds: 10
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- /opt/netbox/venv/bin/python
|
||||||
|
- -c
|
||||||
|
- >-
|
||||||
|
exec /usr/bin/curl --fail --silent --show-error --max-time 4
|
||||||
|
--header 'Host: netbox.forust.xyz'
|
||||||
|
http://127.0.0.1:8080/login/ >/dev/null
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- /opt/netbox/venv/bin/python
|
||||||
|
- -c
|
||||||
|
- >-
|
||||||
|
exec /usr/bin/curl --fail --silent --show-error --max-time 4
|
||||||
|
--header 'Host: netbox.forust.xyz'
|
||||||
|
http://127.0.0.1:8080/login/ >/dev/null
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 30
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: "100m"
|
||||||
|
memory: "512Mi"
|
||||||
|
limits:
|
||||||
|
cpu: "2"
|
||||||
|
memory: "2Gi"
|
||||||
|
volumes:
|
||||||
|
- name: netbox-config
|
||||||
|
configMap:
|
||||||
|
name: netbox-settings
|
||||||
|
- name: netbox-media
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: netbox-media-pvc
|
||||||
|
- name: netbox-reports
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: netbox-reports-pvc
|
||||||
|
- name: netbox-scripts
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: netbox-scripts-pvc
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: netbox-worker-deployment
|
||||||
|
namespace: netbox
|
||||||
|
labels:
|
||||||
|
app: netbox-worker
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
progressDeadlineSeconds: 300
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: netbox-worker
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: netbox-worker
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: netbox-worker
|
||||||
|
image: docker.io/netboxcommunity/netbox:v4.7-5.1.1
|
||||||
|
command:
|
||||||
|
- /opt/netbox/venv/bin/python
|
||||||
|
- netbox/manage.py
|
||||||
|
- rqworker
|
||||||
|
workingDir: /opt/netbox
|
||||||
|
envFrom:
|
||||||
|
- configMapRef:
|
||||||
|
name: netbox-config
|
||||||
|
- secretRef:
|
||||||
|
name: netbox-secrets
|
||||||
|
volumeMounts:
|
||||||
|
- name: netbox-config
|
||||||
|
mountPath: /etc/netbox/config
|
||||||
|
readOnly: true
|
||||||
|
- name: netbox-media
|
||||||
|
mountPath: /opt/netbox/netbox/media
|
||||||
|
- name: netbox-reports
|
||||||
|
mountPath: /opt/netbox/netbox/reports
|
||||||
|
- name: netbox-scripts
|
||||||
|
mountPath: /opt/netbox/netbox/scripts
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: "50m"
|
||||||
|
memory: "256Mi"
|
||||||
|
limits:
|
||||||
|
cpu: "1"
|
||||||
|
memory: "1Gi"
|
||||||
|
volumes:
|
||||||
|
- name: netbox-config
|
||||||
|
configMap:
|
||||||
|
name: netbox-settings
|
||||||
|
- name: netbox-media
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: netbox-media-pvc
|
||||||
|
- name: netbox-reports
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: netbox-reports-pvc
|
||||||
|
- name: netbox-scripts
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: netbox-scripts-pvc
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: netbox-media-pvc
|
||||||
|
namespace: netbox
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 2Gi
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: netbox-reports-pvc
|
||||||
|
namespace: netbox
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: netbox-scripts-pvc
|
||||||
|
namespace: netbox
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: netbox-secrets
|
||||||
|
namespace: netbox
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
DB_NAME: "netbox"
|
||||||
|
DB_USER: "netbox"
|
||||||
|
DB_PASSWORD: "CHANGE_ME_POSTGRES_PASSWORD"
|
||||||
|
REDIS_PASSWORD: "CHANGE_ME_VALKEY_PASSWORD"
|
||||||
|
REDIS_CACHE_PASSWORD: "CHANGE_ME_VALKEY_PASSWORD"
|
||||||
|
VALKEY_PASSWORD: "CHANGE_ME_VALKEY_PASSWORD"
|
||||||
|
SECRET_KEY: "CHANGE_ME_DJANGO_SECRET_KEY"
|
||||||
|
API_TOKEN_PEPPER_1: "CHANGE_ME_API_TOKEN_PEPPER"
|
||||||
|
SUPERUSER_NAME: "admin"
|
||||||
|
SUPERUSER_EMAIL: "admin@example.com"
|
||||||
|
SUPERUSER_PASSWORD: "CHANGE_ME_SUPERUSER_PASSWORD"
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: netbox-settings
|
||||||
|
namespace: netbox
|
||||||
|
data:
|
||||||
|
# Sync wit netbox/configuration/configuration.py (the Docker mounts that file).
|
||||||
|
configuration.py: |
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
def _csv(name, default=""):
|
||||||
|
return [item.strip() for item in os.environ.get(name, default).split(",") if item.strip()]
|
||||||
|
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = _csv("ALLOWED_HOSTS", "localhost,127.0.0.1,[::1]")
|
||||||
|
CSRF_TRUSTED_ORIGINS = _csv("CSRF_TRUSTED_ORIGINS")
|
||||||
|
USE_X_FORWARDED_HOST = True
|
||||||
|
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
"default": {
|
||||||
|
"NAME": os.environ["DB_NAME"],
|
||||||
|
"USER": os.environ["DB_USER"],
|
||||||
|
"PASSWORD": os.environ["DB_PASSWORD"],
|
||||||
|
"HOST": os.environ["DB_HOST"],
|
||||||
|
"PORT": os.environ.get("DB_PORT", "5432"),
|
||||||
|
"OPTIONS": {"sslmode": os.environ.get("DB_SSLMODE", "disable")},
|
||||||
|
"CONN_MAX_AGE": int(os.environ.get("DB_CONN_MAX_AGE", "300")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REDIS = {
|
||||||
|
"tasks": {
|
||||||
|
"HOST": os.environ["REDIS_HOST"],
|
||||||
|
"PORT": int(os.environ.get("REDIS_PORT", "6379")),
|
||||||
|
"PASSWORD": os.environ["REDIS_PASSWORD"],
|
||||||
|
"DATABASE": int(os.environ.get("REDIS_DATABASE", "0")),
|
||||||
|
"SSL": False,
|
||||||
|
},
|
||||||
|
"caching": {
|
||||||
|
"HOST": os.environ["REDIS_CACHE_HOST"],
|
||||||
|
"PORT": int(os.environ.get("REDIS_CACHE_PORT", "6379")),
|
||||||
|
"PASSWORD": os.environ["REDIS_CACHE_PASSWORD"],
|
||||||
|
"DATABASE": int(os.environ.get("REDIS_CACHE_DATABASE", "1")),
|
||||||
|
"SSL": False,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
SECRET_KEY = os.environ["SECRET_KEY"]
|
||||||
|
API_TOKEN_PEPPERS = {1: os.environ["API_TOKEN_PEPPER_1"]}
|
||||||
|
TIME_ZONE = os.environ.get("TIME_ZONE", "UTC")
|
||||||
|
MEDIA_ROOT = "/opt/netbox/netbox/media"
|
||||||
|
REPORTS_ROOT = "/opt/netbox/netbox/reports"
|
||||||
|
SCRIPTS_ROOT = "/opt/netbox/netbox/scripts"
|
||||||
|
CENSUS_REPORTING_ENABLED = False
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: netbox-valkey
|
||||||
|
namespace: netbox
|
||||||
|
labels:
|
||||||
|
app: netbox-valkey
|
||||||
|
spec:
|
||||||
|
clusterIP: None
|
||||||
|
selector:
|
||||||
|
app: netbox-valkey
|
||||||
|
ports:
|
||||||
|
- name: valkey
|
||||||
|
port: 6379
|
||||||
|
targetPort: valkey
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: netbox-valkey
|
||||||
|
namespace: netbox
|
||||||
|
labels:
|
||||||
|
app: netbox-valkey
|
||||||
|
spec:
|
||||||
|
serviceName: netbox-valkey
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: netbox-valkey
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: netbox-valkey
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: valkey
|
||||||
|
image: docker.io/valkey/valkey:9.1.2-alpine
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- valkey-server --appendonly yes --save 30 1 --loglevel warning --requirepass "$VALKEY_PASSWORD"
|
||||||
|
env:
|
||||||
|
- name: VALKEY_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: netbox-secrets
|
||||||
|
key: VALKEY_PASSWORD
|
||||||
|
ports:
|
||||||
|
- name: valkey
|
||||||
|
containerPort: 6379
|
||||||
|
volumeMounts:
|
||||||
|
- name: valkey-data
|
||||||
|
mountPath: /data
|
||||||
|
startupProbe:
|
||||||
|
exec:
|
||||||
|
command: ["sh", "-c", 'valkey-cli --pass "$VALKEY_PASSWORD" ping | grep -q PONG']
|
||||||
|
failureThreshold: 20
|
||||||
|
periodSeconds: 5
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["sh", "-c", 'valkey-cli --pass "$VALKEY_PASSWORD" ping | grep -q PONG']
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["sh", "-c", 'valkey-cli --pass "$VALKEY_PASSWORD" ping | grep -q PONG']
|
||||||
|
initialDelaySeconds: 20
|
||||||
|
periodSeconds: 20
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: "25m"
|
||||||
|
memory: "64Mi"
|
||||||
|
limits:
|
||||||
|
cpu: "250m"
|
||||||
|
memory: "256Mi"
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: valkey-data
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
+2
-1
@@ -1,7 +1,7 @@
|
|||||||
# Shared PostgreSQL
|
# Shared PostgreSQL
|
||||||
|
|
||||||
This directory contains the shared PostgreSQL 17 deployment for Authentik,
|
This directory contains the shared PostgreSQL 17 deployment for Authentik,
|
||||||
Gitea, Netronome, and Statuspage. It creates one database and one login role
|
Gitea, NetBox, Netronome, and Statuspage. It creates one database and one login role
|
||||||
per service. Per-service standalone databases were removed after the
|
per service. Per-service standalone databases were removed after the
|
||||||
migration (Sep 2026); Penpot stays on its own compose PostgreSQL (archived,
|
migration (Sep 2026); Penpot stays on its own compose PostgreSQL (archived,
|
||||||
not part of the shared instance).
|
not part of the shared instance).
|
||||||
@@ -12,6 +12,7 @@ not part of the shared instance).
|
|||||||
| ---------- | ------------------- | -------------------------------------- |
|
| ---------- | ------------------- | -------------------------------------- |
|
||||||
| Authentik | 2025.10.x | Supported (Authentik requires 14+) |
|
| Authentik | 2025.10.x | Supported (Authentik requires 14+) |
|
||||||
| Gitea | 1.27.3 | Supported (Gitea requires 12+) |
|
| Gitea | 1.27.3 | Supported (Gitea requires 12+) |
|
||||||
|
| NetBox | 4.7.x | Supported (NetBox 4.x requires 13+) |
|
||||||
| Netronome | 0.14.0 | Supported (upstream's example uses 17) |
|
| Netronome | 0.14.0 | Supported (upstream's example uses 17) |
|
||||||
| Statuspage | custom | Supported |
|
| Statuspage | custom | Supported |
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ set -euo pipefail
|
|||||||
|
|
||||||
: "${AUTHENTIK_DB_PASSWORD:?AUTHENTIK_DB_PASSWORD is required}"
|
: "${AUTHENTIK_DB_PASSWORD:?AUTHENTIK_DB_PASSWORD is required}"
|
||||||
: "${GITEA_DB_PASSWORD:?GITEA_DB_PASSWORD is required}"
|
: "${GITEA_DB_PASSWORD:?GITEA_DB_PASSWORD is required}"
|
||||||
|
: "${NETBOX_DB_PASSWORD:?NETBOX_DB_PASSWORD is required}"
|
||||||
: "${NETRONOME_DB_PASSWORD:?NETRONOME_DB_PASSWORD is required}"
|
: "${NETRONOME_DB_PASSWORD:?NETRONOME_DB_PASSWORD is required}"
|
||||||
: "${PENPOT_DB_PASSWORD:?PENPOT_DB_PASSWORD is required}"
|
: "${PENPOT_DB_PASSWORD:?PENPOT_DB_PASSWORD is required}"
|
||||||
: "${STATUSPAGE_DB_PASSWORD:?STATUSPAGE_DB_PASSWORD is required}"
|
: "${STATUSPAGE_DB_PASSWORD:?STATUSPAGE_DB_PASSWORD is required}"
|
||||||
@@ -23,6 +24,7 @@ SQL
|
|||||||
|
|
||||||
create_role_and_database authentik authentik "$AUTHENTIK_DB_PASSWORD"
|
create_role_and_database authentik authentik "$AUTHENTIK_DB_PASSWORD"
|
||||||
create_role_and_database gitea gitea "$GITEA_DB_PASSWORD"
|
create_role_and_database gitea gitea "$GITEA_DB_PASSWORD"
|
||||||
|
create_role_and_database netbox netbox "$NETBOX_DB_PASSWORD"
|
||||||
create_role_and_database netronome netronome "$NETRONOME_DB_PASSWORD"
|
create_role_and_database netronome netronome "$NETRONOME_DB_PASSWORD"
|
||||||
create_role_and_database penpot penpot "$PENPOT_DB_PASSWORD"
|
create_role_and_database penpot penpot "$PENPOT_DB_PASSWORD"
|
||||||
create_role_and_database statuspage statuspage "$STATUSPAGE_DB_PASSWORD"
|
create_role_and_database statuspage statuspage "$STATUSPAGE_DB_PASSWORD"
|
||||||
@@ -17,6 +17,9 @@ spec:
|
|||||||
- namespaceSelector:
|
- namespaceSelector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
kubernetes.io/metadata.name: gitea
|
kubernetes.io/metadata.name: gitea
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: netbox
|
||||||
- namespaceSelector:
|
- namespaceSelector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
kubernetes.io/metadata.name: netronome
|
kubernetes.io/metadata.name: netronome
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ data:
|
|||||||
|
|
||||||
: "${AUTHENTIK_DB_PASSWORD:?AUTHENTIK_DB_PASSWORD is required}"
|
: "${AUTHENTIK_DB_PASSWORD:?AUTHENTIK_DB_PASSWORD is required}"
|
||||||
: "${GITEA_DB_PASSWORD:?GITEA_DB_PASSWORD is required}"
|
: "${GITEA_DB_PASSWORD:?GITEA_DB_PASSWORD is required}"
|
||||||
|
: "${NETBOX_DB_PASSWORD:?NETBOX_DB_PASSWORD is required}"
|
||||||
: "${NETRONOME_DB_PASSWORD:?NETRONOME_DB_PASSWORD is required}"
|
: "${NETRONOME_DB_PASSWORD:?NETRONOME_DB_PASSWORD is required}"
|
||||||
: "${PENPOT_DB_PASSWORD:?PENPOT_DB_PASSWORD is required}"
|
: "${PENPOT_DB_PASSWORD:?PENPOT_DB_PASSWORD is required}"
|
||||||
: "${STATUSPAGE_DB_PASSWORD:?STATUSPAGE_DB_PASSWORD is required}"
|
: "${STATUSPAGE_DB_PASSWORD:?STATUSPAGE_DB_PASSWORD is required}"
|
||||||
@@ -133,6 +134,7 @@ data:
|
|||||||
|
|
||||||
create_role_and_database authentik authentik "$AUTHENTIK_DB_PASSWORD"
|
create_role_and_database authentik authentik "$AUTHENTIK_DB_PASSWORD"
|
||||||
create_role_and_database gitea gitea "$GITEA_DB_PASSWORD"
|
create_role_and_database gitea gitea "$GITEA_DB_PASSWORD"
|
||||||
|
create_role_and_database netbox netbox "$NETBOX_DB_PASSWORD"
|
||||||
create_role_and_database netronome netronome "$NETRONOME_DB_PASSWORD"
|
create_role_and_database netronome netronome "$NETRONOME_DB_PASSWORD"
|
||||||
create_role_and_database penpot penpot "$PENPOT_DB_PASSWORD"
|
create_role_and_database penpot penpot "$PENPOT_DB_PASSWORD"
|
||||||
create_role_and_database statuspage statuspage "$STATUSPAGE_DB_PASSWORD"
|
create_role_and_database statuspage statuspage "$STATUSPAGE_DB_PASSWORD"
|
||||||
@@ -8,6 +8,7 @@ stringData:
|
|||||||
POSTGRES_ADMIN_PASSWORD: ""
|
POSTGRES_ADMIN_PASSWORD: ""
|
||||||
AUTHENTIK_DB_PASSWORD: ""
|
AUTHENTIK_DB_PASSWORD: ""
|
||||||
GITEA_DB_PASSWORD: ""
|
GITEA_DB_PASSWORD: ""
|
||||||
|
NETBOX_DB_PASSWORD: ""
|
||||||
NETRONOME_DB_PASSWORD: ""
|
NETRONOME_DB_PASSWORD: ""
|
||||||
PENPOT_DB_PASSWORD: ""
|
PENPOT_DB_PASSWORD: ""
|
||||||
STATUSPAGE_DB_PASSWORD: ""
|
STATUSPAGE_DB_PASSWORD: ""
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
services:
|
||||||
|
rackpeek:
|
||||||
|
image: docker.io/aptacode/rackpeek:v2.1.0
|
||||||
|
container_name: rackpeek
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:8080:8080"
|
||||||
|
environment:
|
||||||
|
TZ: "Europe/Bratislava"
|
||||||
|
volumes:
|
||||||
|
- rackpeek-config:/app/config
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.services.rackpeek.loadbalancer.server.port=8080"
|
||||||
|
|
||||||
|
# Local Router
|
||||||
|
- "traefik.http.routers.rackpeek-local.rule=Host(`rackpeek.workstation.internal`) || Host(`rack.workstation.internal`) || Host(`rackpeek.gigaforust.internal`) || Host(`rack.gigaforust.internal`)"
|
||||||
|
- "traefik.http.routers.rackpeek-local.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.rackpeek-local.tls=true"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/health || exit 1"]
|
||||||
|
start_period: 15s
|
||||||
|
timeout: 5s
|
||||||
|
interval: 30s
|
||||||
|
retries: 3
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
rackpeek-config:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
File renamed without changes.
@@ -0,0 +1,15 @@
|
|||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: internal-wildcard-tls
|
||||||
|
namespace: rackpeek
|
||||||
|
spec:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
|
dnsNames:
|
||||||
|
- "*.workstation.internal"
|
||||||
|
- "*.gigaforust.internal"
|
||||||
|
- workstation.internal
|
||||||
|
- gigaforust.internal
|
||||||
|
issuerRef:
|
||||||
|
name: internal-ca
|
||||||
|
kind: ClusterIssuer
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: rackpeek-local
|
||||||
|
namespace: rackpeek
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`rackpeek.workstation.internal`) || Host(`rack.workstation.internal`) || Host(`rackpeek.gigaforust.internal`) || Host(`rack.gigaforust.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: rackpeek-service
|
||||||
|
port: 8080
|
||||||
|
tls:
|
||||||
|
secretName: internal-wildcard-tls
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: rackpeek
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: rackpeek-service
|
||||||
|
namespace: rackpeek
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: rackpeek
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 8080
|
||||||
|
targetPort: http
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: rackpeek-deployment
|
||||||
|
namespace: rackpeek
|
||||||
|
labels:
|
||||||
|
app: rackpeek
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: rackpeek
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: rackpeek
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
# Image runs as uid/gid 1654
|
||||||
|
fsGroup: 1654
|
||||||
|
containers:
|
||||||
|
- name: rackpeek
|
||||||
|
image: docker.io/aptacode/rackpeek:v2.1.0
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 8080
|
||||||
|
env:
|
||||||
|
- name: RPK_YAML_DIR
|
||||||
|
value: "/app/config"
|
||||||
|
- name: TZ
|
||||||
|
value: "Europe/Bratislava"
|
||||||
|
volumeMounts:
|
||||||
|
- name: rackpeek-config
|
||||||
|
mountPath: /app/config
|
||||||
|
startupProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
failureThreshold: 30
|
||||||
|
periodSeconds: 5
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 20
|
||||||
|
periodSeconds: 30
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
volumes:
|
||||||
|
- name: rackpeek-config
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: rackpeek-pvc
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: rackpeek-pvc
|
||||||
|
namespace: rackpeek
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
storageClassName: local-path-retain
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 2Gi
|
||||||
Reference in new issue
Block a user