Compare commits
31
Commits
sidetree
...
58c8b81cce
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58c8b81cce | ||
|
|
b96bdaeab7 | ||
|
|
56f95cc377 | ||
|
|
b4678e5437 | ||
|
|
18167e7bc3 | ||
|
|
592d24ce96 | ||
|
|
fe32d0319c | ||
|
|
24d3686f60 | ||
|
|
b8b3bba264 | ||
|
|
abfbc04067 | ||
|
|
23ed72826a | ||
|
|
7288058df6 | ||
|
|
6715f9e9af | ||
|
|
ccec1102ef | ||
|
|
360a6fc5dc | ||
|
|
9a806724af | ||
|
|
ed1ddaad5d | ||
|
|
726b3ee544 | ||
|
|
13309b26e0 | ||
|
|
eddc256bed | ||
|
|
52f821cbba | ||
|
|
0dbc2fff13 | ||
|
|
91ec83bc1c | ||
|
|
9fec1dae39 | ||
|
|
8fb12a2176 | ||
|
|
fe0c7067b6 | ||
|
|
d0f0843774 | ||
|
|
81a5b207ac | ||
|
|
e3d5970ae3 | ||
|
|
85f05c26cb | ||
|
|
fcc7b0d611 |
No files matched your search
@@ -61,11 +61,22 @@ jobs:
|
|||||||
- name: Lint YAML syntax
|
- name: Lint YAML syntax
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
mapfile -t yaml_files < <(
|
||||||
|
git ls-files '*.yaml' '*.yml' \
|
||||||
|
':!node_modules/**' \
|
||||||
|
':!**/.venv/**'
|
||||||
|
)
|
||||||
|
|
||||||
|
if [ "${#yaml_files[@]}" -eq 0 ]; then
|
||||||
|
echo "No YAML files found."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
-v "$PWD:/work" \
|
-v "$PWD:/work" \
|
||||||
-w /work \
|
-w /work \
|
||||||
cytopia/yamllint:latest \
|
cytopia/yamllint:latest \
|
||||||
-c .yamllint .
|
-c .yamllint "${yaml_files[@]}"
|
||||||
|
|
||||||
lint-dockerfiles:
|
lint-dockerfiles:
|
||||||
runs-on: [self-hosted, linux, arch, homelab]
|
runs-on: [self-hosted, linux, arch, homelab]
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
name: deploy
|
name: deploy
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
name: renovate-ci
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate-renovate:
|
||||||
|
runs-on: [self-hosted, linux, arch, homelab]
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Validate Renovate Compose draft
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
trap 'rm -f renovate/.env' EXIT
|
||||||
|
printf '%s\n' \
|
||||||
|
'RENOVATE_ENDPOINT=https://gitea.example/api/v1' \
|
||||||
|
'RENOVATE_TOKEN=test-token' \
|
||||||
|
'RENOVATE_REPOSITORIES=forust/homelab' \
|
||||||
|
> renovate/.env
|
||||||
|
docker compose -f renovate/renovate-compose.yaml config --quiet
|
||||||
|
|
||||||
|
- name: Validate Kubernetes manifests
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
docker run --rm \
|
||||||
|
-v "$PWD:/work" \
|
||||||
|
-w /work \
|
||||||
|
ghcr.io/yannh/kubeconform:latest \
|
||||||
|
-strict \
|
||||||
|
-ignore-missing-schemas \
|
||||||
|
-summary \
|
||||||
|
renovate/k8s/namespace.yaml \
|
||||||
|
renovate/k8s/configmap.yaml \
|
||||||
|
renovate/k8s/cronjob.yaml
|
||||||
|
|
||||||
|
- name: Validate Renovate repository config
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
docker run --rm \
|
||||||
|
-v "$PWD:/work" \
|
||||||
|
-w /work \
|
||||||
|
renovate/renovate:44.83.2 \
|
||||||
|
renovate-config-validator renovate.json
|
||||||
@@ -61,11 +61,22 @@ jobs:
|
|||||||
- name: Lint YAML syntax
|
- name: Lint YAML syntax
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
mapfile -t yaml_files < <(
|
||||||
|
git ls-files '*.yaml' '*.yml' \
|
||||||
|
':!node_modules/**' \
|
||||||
|
':!**/.venv/**'
|
||||||
|
)
|
||||||
|
|
||||||
|
if [ "${#yaml_files[@]}" -eq 0 ]; then
|
||||||
|
echo "No YAML files found."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
docker run --rm \
|
docker run --rm \
|
||||||
-v "$PWD:/work" \
|
-v "$PWD:/work" \
|
||||||
-w /work \
|
-w /work \
|
||||||
cytopia/yamllint:latest \
|
cytopia/yamllint:latest \
|
||||||
-c .yamllint .
|
-c .yamllint "${yaml_files[@]}"
|
||||||
|
|
||||||
lint-dockerfiles:
|
lint-dockerfiles:
|
||||||
runs-on: [self-hosted, linux, arch, homelab]
|
runs-on: [self-hosted, linux, arch, homelab]
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
name: deploy
|
name: deploy
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
@@ -133,6 +130,15 @@ jobs:
|
|||||||
echo " namespaces first: ${ns_files[*]}"
|
echo " namespaces first: ${ns_files[*]}"
|
||||||
kubectl apply -f "${ns_files[@]}"
|
kubectl apply -f "${ns_files[@]}"
|
||||||
fi
|
fi
|
||||||
|
if [ -f "$repo/prometheus-stack/k8s/active" ]; then
|
||||||
|
echo "== Upgrading kube-prometheus-stack =="
|
||||||
|
helm upgrade --install prometheus-stack prometheus-community/kube-prometheus-stack \
|
||||||
|
--namespace prometheus \
|
||||||
|
--version 86.2.3 \
|
||||||
|
--values "$repo/prometheus-stack/k8s/grafana-values.yaml" \
|
||||||
|
--wait
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "${#other_files[@]}" -gt 0 ]; then
|
if [ "${#other_files[@]}" -gt 0 ]; then
|
||||||
echo " resources: ${other_files[*]}"
|
echo " resources: ${other_files[*]}"
|
||||||
kubectl apply "${prune_opts[@]}" -f "${other_files[@]}"
|
kubectl apply "${prune_opts[@]}" -f "${other_files[@]}"
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ traefik/dynamic/fileservers.yml
|
|||||||
traefik/dynamic/*.local.y*ml.*
|
traefik/dynamic/*.local.y*ml.*
|
||||||
traefik/dynamic/*.external.y*ml
|
traefik/dynamic/*.external.y*ml
|
||||||
traefik/k8s/fileservers.y*ml
|
traefik/k8s/fileservers.y*ml
|
||||||
|
traefik/k8s/aliasHeadersStrategy.md
|
||||||
|
|
||||||
traefik/logs/*
|
traefik/logs/*
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
adguard:
|
adguard:
|
||||||
image: adguard/adguardhome:latest
|
image: adguard/adguardhome:v0.107.79
|
||||||
container_name: adguardhome
|
container_name: adguardhome
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: adguard
|
- name: adguard
|
||||||
image: adguard/adguardhome:latest
|
image: adguard/adguardhome:v0.107.79
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
memory: "1.5Gi"
|
memory: "1.5Gi"
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ spec:
|
|||||||
routes:
|
routes:
|
||||||
- match: Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)
|
- match: Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: adguard-service
|
- name: adguard-service
|
||||||
port: 3000
|
port: 3000
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
postgresql:
|
postgresql:
|
||||||
image: docker.io/library/postgres:15-alpine
|
image: docker.io/library/postgres:15.19-alpine
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ metadata:
|
|||||||
data:
|
data:
|
||||||
AUTHENTIK_IMAGE: ghcr.io/goauthentik/server
|
AUTHENTIK_IMAGE: ghcr.io/goauthentik/server
|
||||||
AUTHENTIK_TAG: "2025.10.2"
|
AUTHENTIK_TAG: "2025.10.2"
|
||||||
AUTHENTIK_POSTGRESQL__HOST: authentik-postgres-service
|
AUTHENTIK_POSTGRESQL__HOST: postgres.database.svc.cluster.local
|
||||||
AUTHENTIK_POSTGRESQL__NAME: authentik
|
AUTHENTIK_POSTGRESQL__NAME: authentik
|
||||||
AUTHENTIK_ERROR_REPORTING__ENABLED: "true"
|
AUTHENTIK_ERROR_REPORTING__ENABLED: "true"
|
||||||
@@ -9,6 +9,9 @@ spec:
|
|||||||
routes:
|
routes:
|
||||||
- match: Host(`auth.forust.xyz`)
|
- match: Host(`auth.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: authentik-server-service
|
- name: authentik-server-service
|
||||||
port: 9000
|
port: 9000
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: authentik-postgres-service
|
|
||||||
namespace: authentik
|
|
||||||
spec:
|
|
||||||
clusterIP: None
|
|
||||||
selector:
|
|
||||||
app: authentik-postgres
|
|
||||||
ports:
|
|
||||||
- port: 5432
|
|
||||||
targetPort: 5432
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: StatefulSet
|
|
||||||
metadata:
|
|
||||||
name: authentik-postgres-statefulset
|
|
||||||
namespace: authentik
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: authentik-postgres
|
|
||||||
serviceName: authentik-postgres-service
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: authentik-postgres
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: postgres
|
|
||||||
image: docker.io/library/postgres:15-alpine
|
|
||||||
env:
|
|
||||||
- name: POSTGRES_DB
|
|
||||||
value: authentik
|
|
||||||
- name: POSTGRES_USER
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: authentik-secrets
|
|
||||||
key: AUTHENTIK_POSTGRESQL__USER
|
|
||||||
- name: POSTGRES_PASSWORD
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: authentik-secrets
|
|
||||||
key: AUTHENTIK_POSTGRESQL__PASSWORD
|
|
||||||
ports:
|
|
||||||
- containerPort: 5432
|
|
||||||
name: postgres
|
|
||||||
volumeMounts:
|
|
||||||
- name: postgres-data
|
|
||||||
mountPath: /var/lib/postgresql/data
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
memory: "256Mi"
|
|
||||||
cpu: "200m"
|
|
||||||
limits:
|
|
||||||
memory: "1Gi"
|
|
||||||
cpu: "500m"
|
|
||||||
volumeClaimTemplates:
|
|
||||||
- metadata:
|
|
||||||
name: postgres-data
|
|
||||||
spec:
|
|
||||||
accessModes: ["ReadWriteOnce"]
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
storage: 5Gi
|
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
cloudflare-ddns:
|
cloudflare-ddns:
|
||||||
image: timothyjmiller/cloudflare-ddns:latest
|
image: timothyjmiller/cloudflare-ddns:2.2.0
|
||||||
container_name: cloudflare-ddns
|
container_name: cloudflare-ddns
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
security_opt:
|
security_opt:
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ spec:
|
|||||||
dnsPolicy: ClusterFirstWithHostNet
|
dnsPolicy: ClusterFirstWithHostNet
|
||||||
containers:
|
containers:
|
||||||
- name: cloudflare-ddns
|
- name: cloudflare-ddns
|
||||||
image: timothyjmiller/cloudflare-ddns:latest
|
image: timothyjmiller/cloudflare-ddns:2.2.0
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
checkmk:
|
checkmk:
|
||||||
image: "checkmk/check-mk-raw:2.4.0-latest"
|
image: "checkmk/check-mk-raw:2.4.0-2026.09.14"
|
||||||
container_name: "checkmk"
|
container_name: "checkmk"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# ports:
|
# ports:
|
||||||
|
|||||||
@@ -7,8 +7,12 @@ spec:
|
|||||||
selector:
|
selector:
|
||||||
app: checkmk
|
app: checkmk
|
||||||
ports:
|
ports:
|
||||||
- port: 5000
|
- name: web
|
||||||
|
port: 5000
|
||||||
targetPort: 5000
|
targetPort: 5000
|
||||||
|
- name: agent-receiver
|
||||||
|
port: 8000
|
||||||
|
targetPort: 8000
|
||||||
---
|
---
|
||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: Deployment
|
||||||
@@ -27,14 +31,17 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: checkmk
|
- name: checkmk
|
||||||
image: checkmk/check-mk-raw:2.4.0-latest
|
image: checkmk/check-mk-raw:2.4.0-2026.09.14
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: checkmk-secrets
|
name: checkmk-secrets
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
name: checkmk-config
|
name: checkmk-config
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 5000
|
- name: web
|
||||||
|
containerPort: 5000
|
||||||
|
- name: agent-receiver
|
||||||
|
containerPort: 8000
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: sites
|
- name: sites
|
||||||
mountPath: /omd/sites
|
mountPath: /omd/sites
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ spec:
|
|||||||
routes:
|
routes:
|
||||||
- match: Host(`cmk.forust.xyz`)
|
- match: Host(`cmk.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: checkmk-service
|
- name: checkmk-service
|
||||||
port: 5000
|
port: 5000
|
||||||
@@ -16,6 +19,22 @@ spec:
|
|||||||
certResolver: letsencrypt
|
certResolver: letsencrypt
|
||||||
---
|
---
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRouteTCP
|
||||||
|
metadata:
|
||||||
|
name: checkmk-agent-receiver
|
||||||
|
namespace: checkmk
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- checkmk-agent
|
||||||
|
routes:
|
||||||
|
- match: HostSNI(`*`)
|
||||||
|
services:
|
||||||
|
- name: checkmk-service
|
||||||
|
port: 8000
|
||||||
|
tls:
|
||||||
|
passthrough: true
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
metadata:
|
metadata:
|
||||||
name: checkmk-local
|
name: checkmk-local
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
convertx:
|
convertx:
|
||||||
container_name: convertx
|
container_name: convertx
|
||||||
image: ghcr.io/c4illin/convertx:latest
|
image: ghcr.io/c4illin/convertx:v0.18.0
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "9992:3000"
|
- "9992:3000"
|
||||||
@@ -42,7 +42,7 @@ services:
|
|||||||
|
|
||||||
bentopdf:
|
bentopdf:
|
||||||
container_name: bentopdf
|
container_name: bentopdf
|
||||||
image: bentopdf/bentopdf:latest
|
image: bentopdf/bentopdf@sha256:4eb4ec8f5030faf87c29a73d3d5a2781f28a597cf440c3ab111eb96aee550871
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ spec:
|
|||||||
app: bentopdf
|
app: bentopdf
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- image: bentopdf/bentopdf:latest
|
- image: bentopdf/bentopdf@sha256:4eb4ec8f5030faf87c29a73d3d5a2781f28a597cf440c3ab111eb96aee550871
|
||||||
imagePullPolicy: Always
|
imagePullPolicy: Always
|
||||||
name: bentopdf
|
name: bentopdf
|
||||||
ports:
|
ports:
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ spec:
|
|||||||
app: convertx
|
app: convertx
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- image: ghcr.io/c4illin/convertx:latest
|
- image: ghcr.io/c4illin/convertx:v0.18.0
|
||||||
name: convertx
|
name: convertx
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
|
spec:
|
||||||
|
plugin:
|
||||||
|
crowdsec-bouncer:
|
||||||
|
enabled: true
|
||||||
|
LogLevel: INFO
|
||||||
|
CrowdsecMode: live
|
||||||
|
CrowdsecLapiScheme: http
|
||||||
|
CrowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080
|
||||||
|
CrowdsecLapiKeyFile: "/etc/traefik/secrets/traefik-api-key"
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
container_runtime: containerd
|
||||||
|
agent:
|
||||||
|
env:
|
||||||
|
- name: COLLECTIONS
|
||||||
|
value: "crowdsecurity/traefik crowdsecurity/base-http-scenarios"
|
||||||
|
- name: DISABLE_COLLECTIONS
|
||||||
|
value: "crowdsecurity/linux crowdsecurity/sshd"
|
||||||
|
|
||||||
|
acquisition:
|
||||||
|
- namespace: traefik
|
||||||
|
podName: "*traefik*"
|
||||||
|
program: traefik
|
||||||
|
poll_without_inotify: true
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 100Mi
|
||||||
|
limits:
|
||||||
|
cpu: 200m
|
||||||
|
memory: 500Mi
|
||||||
|
|
||||||
|
lapi:
|
||||||
|
env:
|
||||||
|
- name: COLLECTIONS
|
||||||
|
value: "crowdsecurity/traefik crowdsecurity/base-http-scenarios"
|
||||||
|
- name: DISABLE_COLLECTIONS
|
||||||
|
value: "crowdsecurity/linux crowdsecurity/sshd"
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
persistentVolume:
|
||||||
|
data:
|
||||||
|
enabled: true
|
||||||
|
storageClassName: local-path-retain
|
||||||
|
size: 1Gi
|
||||||
|
config:
|
||||||
|
enabled: true
|
||||||
|
storageClassName: local-path-retain
|
||||||
|
size: 100Mi
|
||||||
|
storeLAPICscliCredentialsInSecret: true
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 150Mi
|
||||||
|
limits:
|
||||||
|
cpu: 400m
|
||||||
|
memory: 500Mi
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
enabled: true
|
||||||
|
serviceMonitor:
|
||||||
|
additionalLabels:
|
||||||
|
release: prometheus-stack
|
||||||
|
enabled: true
|
||||||
|
interval: 30s
|
||||||
|
scrapeTimeout: 10s
|
||||||
|
namespace: prometheus
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: crowdsec
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/part-of: crowdsec
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: crowdsec-lapi
|
||||||
|
namespace: crowdsec
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
k8s-app: crowdsec
|
||||||
|
type: lapi
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: traefik
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: traefik
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
k8s-app: crowdsec
|
||||||
|
type: agent
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 8080
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
dockmon:
|
dockmon:
|
||||||
image: darthnorse/dockmon:latest
|
image: darthnorse/dockmon:2.4.5
|
||||||
container_name: dockmon
|
container_name: dockmon
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# ports:
|
# ports:
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: dockmon
|
- name: dockmon
|
||||||
image: darthnorse/dockmon:latest
|
image: darthnorse/dockmon:2.4.5
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 443
|
- containerPort: 443
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ spec:
|
|||||||
- match: Host(`dockmon.forust.xyz`)
|
- match: Host(`dockmon.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
middlewares:
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
- name: security-headers@file
|
- name: security-headers@file
|
||||||
services:
|
services:
|
||||||
- name: dockmon-service
|
- name: dockmon-service
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
downtify:
|
downtify:
|
||||||
container_name: downtify
|
container_name: downtify
|
||||||
image: ghcr.io/henriquesebastiao/downtify:latest
|
image: ghcr.io/henriquesebastiao/downtify:2.12.0
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# ports:
|
# ports:
|
||||||
# - '7077:8000'
|
# - '7077:8000'
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: downtify
|
- name: downtify
|
||||||
image: ghcr.io/henriquesebastiao/downtify:latest
|
image: ghcr.io/henriquesebastiao/downtify:2.12.0
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 8000
|
- containerPort: 8000
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ spec:
|
|||||||
- match: Host(`downtify.forust.xyz`)
|
- match: Host(`downtify.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
middlewares:
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
- name: security-chain@file
|
- name: security-chain@file
|
||||||
services:
|
services:
|
||||||
- name: downtify-service
|
- name: downtify-service
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
redis:
|
redis:
|
||||||
image: redis:alpine
|
image: redis:8.0.3-alpine
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- redis-data:/data
|
- redis-data:/data
|
||||||
@@ -11,7 +11,7 @@ services:
|
|||||||
retries: 5
|
retries: 5
|
||||||
|
|
||||||
playwright-service:
|
playwright-service:
|
||||||
image: mcr.microsoft.com/playwright:v1.56.0-jammy
|
image: mcr.microsoft.com/playwright:v1.56.1-jammy
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: npx -y playwright@1.56.0 run-server --port 3000 --path /ws
|
command: npx -y playwright@1.56.0 run-server --port 3000 --path /ws
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: playwright
|
- name: playwright
|
||||||
image: mcr.microsoft.com/playwright:v1.56.0-jammy
|
image: mcr.microsoft.com/playwright:v1.56.1-jammy
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
command:
|
command:
|
||||||
- npx
|
- npx
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
apiVersion: apps/v1
|
apiVersion: apps/v1
|
||||||
kind: Deployment
|
kind: StatefulSet
|
||||||
metadata:
|
metadata:
|
||||||
name: redis
|
name: redis
|
||||||
namespace: edu-master
|
namespace: edu-master
|
||||||
labels:
|
labels:
|
||||||
app: edu-master-redis
|
app: edu-master-redis
|
||||||
spec:
|
spec:
|
||||||
|
serviceName: redis
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
@@ -17,7 +18,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: redis
|
- name: redis
|
||||||
image: redis:alpine
|
image: redis:8.0.3-alpine
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 6379
|
- containerPort: 6379
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
initContainers:
|
initContainers:
|
||||||
- name: wait-redis
|
- name: wait-redis
|
||||||
image: redis:alpine
|
image: redis:8.0.3-alpine
|
||||||
command:
|
command:
|
||||||
- /bin/sh
|
- /bin/sh
|
||||||
- -ec
|
- -ec
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ spec:
|
|||||||
# redis healthy -> session-keeper healthy (EXISTS EDU_PHPSESSID) -> playwright started
|
# redis healthy -> session-keeper healthy (EXISTS EDU_PHPSESSID) -> playwright started
|
||||||
initContainers:
|
initContainers:
|
||||||
- name: wait-deps
|
- name: wait-deps
|
||||||
image: redis:alpine
|
image: redis:8.0.3-alpine
|
||||||
command:
|
command:
|
||||||
- /bin/sh
|
- /bin/sh
|
||||||
- -ec
|
- -ec
|
||||||
@@ -55,8 +55,8 @@ spec:
|
|||||||
value: "Europe/Kyiv"
|
value: "Europe/Kyiv"
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
cpu: 25m
|
cpu: "50m"
|
||||||
memory: 128Mi
|
memory: "128Mi"
|
||||||
limits:
|
limits:
|
||||||
cpu: 300m
|
cpu: "600m"
|
||||||
memory: 384Mi
|
memory: "512Mi"
|
||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
server:
|
server:
|
||||||
image: docker.gitea.com/gitea:1.26
|
image: docker.gitea.com/gitea:1.27.3
|
||||||
container_name: gitea
|
container_name: gitea
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
@@ -61,7 +61,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
db:
|
db:
|
||||||
image: docker.io/library/postgres:14
|
image: docker.io/library/postgres:14.24-alpine
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_USER=gitea
|
- POSTGRES_USER=gitea
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ data:
|
|||||||
GITEA__server__SSH_PORT: "2221"
|
GITEA__server__SSH_PORT: "2221"
|
||||||
|
|
||||||
GITEA__database__DB_TYPE: "postgres"
|
GITEA__database__DB_TYPE: "postgres"
|
||||||
GITEA__database__HOST: "gitea-postgres-service:5432"
|
GITEA__database__HOST: "postgres.database.svc.cluster.local:5432"
|
||||||
GITEA__database__NAME: "gitea"
|
GITEA__database__NAME: "gitea"
|
||||||
GITEA__security__REVERSE_PROXY_LIMIT: "1"
|
GITEA__security__REVERSE_PROXY_LIMIT: "1"
|
||||||
GITEA__security__REVERSE_PROXY_TRUSTED_PROXIES: "*"
|
GITEA__security__REVERSE_PROXY_TRUSTED_PROXIES: "*"
|
||||||
|
|
||||||
GITEA__mailer__ENABLED: "false"
|
GITEA__mailer__ENABLED: "false"
|
||||||
|
|
||||||
GITEA__log__logger__access__MODE: "console, file"
|
GITEA__log__logger.access.MODE: "console, file"
|
||||||
USER_UID: "1000"
|
USER_UID: "1000"
|
||||||
USER_GID: "1000"
|
USER_GID: "1000"
|
||||||
@@ -31,7 +31,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: gitea
|
- name: gitea
|
||||||
image: docker.gitea.com/gitea:1.26
|
image: docker.gitea.com/gitea:1.27.3
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
name: gitea-config
|
name: gitea-config
|
||||||
|
|||||||
@@ -9,11 +9,17 @@ spec:
|
|||||||
routes:
|
routes:
|
||||||
- match: Host(`gitea.forust.xyz`)
|
- match: Host(`gitea.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: gitea-service
|
- name: gitea-service
|
||||||
port: 3000
|
port: 3000
|
||||||
- match: Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)
|
- match: Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: gitea-service
|
- name: gitea-service
|
||||||
port: 3000
|
port: 3000
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: gitea-postgres-service
|
|
||||||
namespace: gitea
|
|
||||||
spec:
|
|
||||||
clusterIP: None
|
|
||||||
selector:
|
|
||||||
app: gitea-postgres
|
|
||||||
ports:
|
|
||||||
- port: 5432
|
|
||||||
targetPort: 5432
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: StatefulSet
|
|
||||||
metadata:
|
|
||||||
name: gitea-postgres-statefulset
|
|
||||||
namespace: gitea
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: gitea-postgres
|
|
||||||
serviceName: gitea-postgres-service
|
|
||||||
replicas: 1
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: gitea-postgres
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: gitea-postgres
|
|
||||||
image: postgres:14
|
|
||||||
env:
|
|
||||||
- name: POSTGRES_USER
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: gitea-secrets
|
|
||||||
key: GITEA__database__USER
|
|
||||||
- name: POSTGRES_PASSWORD
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: gitea-secrets
|
|
||||||
key: GITEA__database__PASSWD
|
|
||||||
- name: POSTGRES_DB
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: gitea-secrets
|
|
||||||
key: GITEA__database__USER
|
|
||||||
ports:
|
|
||||||
- containerPort: 5432
|
|
||||||
name: postgres
|
|
||||||
volumeMounts:
|
|
||||||
- name: postgres-data
|
|
||||||
mountPath: /var/lib/postgresql/data
|
|
||||||
volumeClaimTemplates:
|
|
||||||
- metadata:
|
|
||||||
name: postgres-data
|
|
||||||
spec:
|
|
||||||
accessModes: ["ReadWriteOnce"]
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
storage: 1Gi
|
|
||||||
@@ -7,3 +7,4 @@ type: Opaque
|
|||||||
stringData:
|
stringData:
|
||||||
GITEA__database__USER: "gitea"
|
GITEA__database__USER: "gitea"
|
||||||
GITEA__database__PASSWD: "gitea"
|
GITEA__database__PASSWD: "gitea"
|
||||||
|
GITEA__database__NAME: "gitea"
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
services:
|
services:
|
||||||
glance:
|
glance:
|
||||||
container_name: glance
|
container_name: glance
|
||||||
image: glanceapp/glance
|
image: glanceapp/glance:v0.8.6
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- ./config:/app/config:ro
|
- ./config:/app/config:ro
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: glance
|
- name: glance
|
||||||
image: glanceapp/glance
|
image: glanceapp/glance:v0.8.6
|
||||||
envFrom:
|
envFrom:
|
||||||
- secretRef:
|
- secretRef:
|
||||||
name: glance-secrets
|
name: glance-secrets
|
||||||
@@ -56,11 +56,11 @@ spec:
|
|||||||
readOnly: true
|
readOnly: true
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: "30Mi"
|
|
||||||
cpu: "20m"
|
|
||||||
limits:
|
|
||||||
memory: "100Mi"
|
|
||||||
cpu: "50m"
|
cpu: "50m"
|
||||||
|
memory: "64Mi"
|
||||||
|
limits:
|
||||||
|
cpu: "200m"
|
||||||
|
memory: "256Mi"
|
||||||
volumes:
|
volumes:
|
||||||
- name: glance-config
|
- name: glance-config
|
||||||
configMap:
|
configMap:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
headscale:
|
headscale:
|
||||||
image: headscale/headscale:latest
|
image: headscale/headscale:0.29.3
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
container_name: headscale-server
|
container_name: headscale-server
|
||||||
command: serve
|
command: serve
|
||||||
@@ -53,7 +53,7 @@ services:
|
|||||||
- "traefik.http.routers.headscale-metrics-dev.service=headscale-metrics"
|
- "traefik.http.routers.headscale-metrics-dev.service=headscale-metrics"
|
||||||
- "traefik.http.routers.headscale-metrics-dev.tls=true"
|
- "traefik.http.routers.headscale-metrics-dev.tls=true"
|
||||||
headplane:
|
headplane:
|
||||||
image: ghcr.io/tale/headplane:latest
|
image: ghcr.io/tale/headplane:0.7.1
|
||||||
container_name: headplane
|
container_name: headplane
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
@@ -100,7 +100,7 @@ services:
|
|||||||
- "traefik.http.routers.headplane-dev.entrypoints=websecure"
|
- "traefik.http.routers.headplane-dev.entrypoints=websecure"
|
||||||
- "traefik.http.routers.headplane-dev.tls=true"
|
- "traefik.http.routers.headplane-dev.tls=true"
|
||||||
web:
|
web:
|
||||||
image: goodieshq/headscale-admin:latest
|
image: goodieshq/headscale-admin:0.28.0
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- 10080:80
|
- 10080:80
|
||||||
|
|||||||
@@ -23,11 +23,17 @@ spec:
|
|||||||
port: 8080
|
port: 8080
|
||||||
- match: Host(`hs.forust.xyz`) && PathPrefix(`/admin`)
|
- match: Host(`hs.forust.xyz`) && PathPrefix(`/admin`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: headscale-ui-external
|
- name: headscale-ui-external
|
||||||
port: 80
|
port: 80
|
||||||
- match: Host(`hs.forust.xyz`) && PathPrefix(`/metrics`)
|
- match: Host(`hs.forust.xyz`) && PathPrefix(`/metrics`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: headscale-server-external
|
- name: headscale-server-external
|
||||||
port: 9090
|
port: 9090
|
||||||
@@ -47,6 +53,8 @@ spec:
|
|||||||
kind: Rule
|
kind: Rule
|
||||||
middlewares:
|
middlewares:
|
||||||
- name: headplane-prefix
|
- name: headplane-prefix
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: headplane-external
|
- name: headplane-external
|
||||||
port: 3000
|
port: 3000
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ spec:
|
|||||||
routes:
|
routes:
|
||||||
- match: Host(`forust.xyz`) || Host(`www.forust.xyz`)
|
- match: Host(`forust.xyz`) || Host(`www.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
priority: 10
|
priority: 10
|
||||||
services:
|
services:
|
||||||
- name: forust-homepage-service
|
- name: forust-homepage-service
|
||||||
@@ -43,6 +46,9 @@ spec:
|
|||||||
routes:
|
routes:
|
||||||
- match: Host(`xdfnx.cfd`)
|
- match: Host(`xdfnx.cfd`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: xdfnx-homepage-service
|
- name: xdfnx-homepage-service
|
||||||
port: 80
|
port: 80
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
kener:
|
kener:
|
||||||
image: rajnandan1/kener:4.0.23
|
image: rajnandan1/kener:4.1.5
|
||||||
container_name: kener
|
container_name: kener
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# ports:
|
# ports:
|
||||||
@@ -36,7 +36,7 @@ services:
|
|||||||
- proxy
|
- proxy
|
||||||
- kener
|
- kener
|
||||||
redis:
|
redis:
|
||||||
image: redis:7-alpine
|
image: redis:7.4.11-alpine
|
||||||
container_name: kener-redis
|
container_name: kener-redis
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ spec:
|
|||||||
routes:
|
routes:
|
||||||
- match: Host(`status.forust.xyz`)
|
- match: Host(`status.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: kener-service
|
- name: kener-service
|
||||||
port: 3000
|
port: 3000
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: kener
|
- name: kener
|
||||||
image: rajnandan1/kener:4.1.0
|
image: rajnandan1/kener:4.1.5
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
name: kener-config
|
name: kener-config
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: redis
|
- name: redis
|
||||||
image: redis:7-alpine
|
image: redis:7.4.11-alpine
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 6379
|
- containerPort: 6379
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
metube:
|
metube:
|
||||||
image: ghcr.io/alexta69/metube
|
image: ghcr.io/alexta69/metube:2026.08.28
|
||||||
container_name: metube
|
container_name: metube
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# ports:
|
# ports:
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: metube
|
- name: metube
|
||||||
image: ghcr.io/alexta69/metube
|
image: ghcr.io/alexta69/metube:2026.08.28
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
name: metube-config
|
name: metube-config
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
n8n:
|
n8n:
|
||||||
image: docker.n8n.io/n8nio/n8n
|
image: docker.n8n.io/n8nio/n8n:2.38.7
|
||||||
container_name: n8n
|
container_name: n8n
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ spec:
|
|||||||
routes:
|
routes:
|
||||||
- match: Host(`n8n.forust.xyz`)
|
- match: Host(`n8n.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: n8n-service
|
- name: n8n-service
|
||||||
port: 5678
|
port: 5678
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: n8n
|
- name: n8n
|
||||||
image: docker.n8n.io/n8nio/n8n
|
image: docker.n8n.io/n8nio/n8n:2.38.7
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
name: n8n-config
|
name: n8n-config
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
netronome:
|
netronome:
|
||||||
image: ghcr.io/autobrr/netronome:latest
|
image: ghcr.io/autobrr/netronome:v0.14.0
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
container_name: netronome
|
container_name: netronome
|
||||||
ports:
|
ports:
|
||||||
@@ -33,7 +33,7 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
postgres:
|
postgres:
|
||||||
container_name: netronome-postgres
|
container_name: netronome-postgres
|
||||||
image: postgres:17-alpine
|
image: postgres:17.11-alpine
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_USER=netronome
|
- POSTGRES_USER=netronome
|
||||||
- POSTGRES_PASSWORD=netronome
|
- POSTGRES_PASSWORD=netronome
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ metadata:
|
|||||||
namespace: netronome
|
namespace: netronome
|
||||||
data:
|
data:
|
||||||
NETRONOME__DB_TYPE: "postgres"
|
NETRONOME__DB_TYPE: "postgres"
|
||||||
NETRONOME__DB_HOST: "netronome-postgres-service"
|
NETRONOME__DB_HOST: "postgres.database.svc.cluster.local"
|
||||||
NETRONOME__DB_PORT: "5432"
|
NETRONOME__DB_PORT: "5432"
|
||||||
NETRONOME__DB_NAME: "netronome"
|
NETRONOME__DB_NAME: "netronome"
|
||||||
NETRONOME__DB_SSLMODE: "disable"
|
NETRONOME__DB_SSLMODE: "disable"
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ spec:
|
|||||||
routes:
|
routes:
|
||||||
- match: Host(`nm.forust.xyz`)
|
- match: Host(`nm.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: netronome-service
|
- name: netronome-service
|
||||||
port: 7575
|
port: 7575
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: netronome
|
- name: netronome
|
||||||
image: ghcr.io/autobrr/netronome:latest
|
image: ghcr.io/autobrr/netronome:v0.14.0
|
||||||
ports:
|
ports:
|
||||||
- name: netronome-port
|
- name: netronome-port
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: netronome-postgres-service
|
|
||||||
namespace: netronome
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
app: netronome-postgres
|
|
||||||
ports:
|
|
||||||
- protocol: TCP
|
|
||||||
port: 5432
|
|
||||||
targetPort: 5432
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: StatefulSet
|
|
||||||
metadata:
|
|
||||||
name: netronome-postgres
|
|
||||||
namespace: netronome
|
|
||||||
spec:
|
|
||||||
serviceName: "netronome-postgres-service"
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: netronome-postgres
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: netronome-postgres
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: netronome-postgres
|
|
||||||
image: postgres:17-alpine
|
|
||||||
ports:
|
|
||||||
- name: postgres-port
|
|
||||||
protocol: TCP
|
|
||||||
containerPort: 5432
|
|
||||||
env:
|
|
||||||
- name: POSTGRES_USER
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: netronome-secrets
|
|
||||||
key: NETRONOME__DB_USER
|
|
||||||
- name: POSTGRES_PASSWORD
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: netronome-secrets
|
|
||||||
key: NETRONOME__DB_PASSWORD
|
|
||||||
- name: POSTGRES_DB
|
|
||||||
valueFrom:
|
|
||||||
configMapKeyRef:
|
|
||||||
name: netronome-config
|
|
||||||
key: NETRONOME__DB_NAME
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
memory: "512Mi"
|
|
||||||
cpu: "500m"
|
|
||||||
limits:
|
|
||||||
memory: "1Gi"
|
|
||||||
cpu: "1000m"
|
|
||||||
volumeMounts:
|
|
||||||
- name: netronome-pg-data
|
|
||||||
mountPath: /var/lib/postgresql/data
|
|
||||||
volumeClaimTemplates:
|
|
||||||
- metadata:
|
|
||||||
name: netronome-pg-data
|
|
||||||
spec:
|
|
||||||
accessModes:
|
|
||||||
- ReadWriteOnce
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
storage: 1Gi
|
|
||||||
@@ -12,6 +12,8 @@ spec:
|
|||||||
kind: Rule
|
kind: Rule
|
||||||
middlewares:
|
middlewares:
|
||||||
- name: nextcloud-chain@file
|
- name: nextcloud-chain@file
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: nextcloud-apache
|
- name: nextcloud-apache
|
||||||
port: 11000
|
port: 11000
|
||||||
@@ -30,6 +32,8 @@ spec:
|
|||||||
- match: Host(`nextcloud.workstation.internal`) || Host(`nextcloud.gigaforust.internal`)
|
- match: Host(`nextcloud.workstation.internal`) || Host(`nextcloud.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
middlewares:
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
- name: nextcloud-chain@file
|
- name: nextcloud-chain@file
|
||||||
services:
|
services:
|
||||||
- name: nextcloud-apache
|
- name: nextcloud-apache
|
||||||
|
|||||||
+5
-5
@@ -84,7 +84,7 @@ services:
|
|||||||
# - "443:443"
|
# - "443:443"
|
||||||
|
|
||||||
penpot-frontend:
|
penpot-frontend:
|
||||||
image: "penpotapp/frontend:${PENPOT_VERSION:-latest}"
|
image: "penpotapp/frontend:${PENPOT_VERSION:-2.17.2}"
|
||||||
restart: always
|
restart: always
|
||||||
# ports:
|
# ports:
|
||||||
# - 9001:8080
|
# - 9001:8080
|
||||||
@@ -119,7 +119,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
<<: [*penpot-flags, *penpot-http-body-size]
|
<<: [*penpot-flags, *penpot-http-body-size]
|
||||||
penpot-backend:
|
penpot-backend:
|
||||||
image: "penpotapp/backend:${PENPOT_VERSION:-latest}"
|
image: "penpotapp/backend:${PENPOT_VERSION:-2.17.2}"
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
@@ -189,7 +189,7 @@ services:
|
|||||||
# PENPOT_SMTP_SSL: false
|
# PENPOT_SMTP_SSL: false
|
||||||
|
|
||||||
penpot-exporter:
|
penpot-exporter:
|
||||||
image: "penpotapp/exporter:${PENPOT_VERSION:-latest}"
|
image: "penpotapp/exporter:${PENPOT_VERSION:-2.17.2}"
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -209,7 +209,7 @@ services:
|
|||||||
PENPOT_REDIS_URI: redis://penpot-valkey/0
|
PENPOT_REDIS_URI: redis://penpot-valkey/0
|
||||||
|
|
||||||
penpot-postgres:
|
penpot-postgres:
|
||||||
image: "postgres:15"
|
image: "postgres:15.19-alpine"
|
||||||
restart: always
|
restart: always
|
||||||
stop_signal: SIGINT
|
stop_signal: SIGINT
|
||||||
|
|
||||||
@@ -233,7 +233,7 @@ services:
|
|||||||
- POSTGRES_PASSWORD=penpot
|
- POSTGRES_PASSWORD=penpot
|
||||||
|
|
||||||
penpot-valkey:
|
penpot-valkey:
|
||||||
image: valkey/valkey:8.1
|
image: valkey/valkey:8.1.10
|
||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
portainer:
|
portainer:
|
||||||
image: portainer/portainer-ce:2.41.0
|
image: portainer/portainer-ce:2.45.0
|
||||||
container_name: portainer
|
container_name: portainer
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ spec:
|
|||||||
routes:
|
routes:
|
||||||
- match: Host(`portainer.forust.xyz`)
|
- match: Host(`portainer.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: portainer-service
|
- name: portainer-service
|
||||||
port: 9000
|
port: 9000
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: portainer
|
- name: portainer
|
||||||
image: portainer/portainer-ce:2.41.0
|
image: portainer/portainer-ce:2.45.0
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 9000
|
- containerPort: 9000
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
POSTGRES_ADMIN_PASSWORD=
|
||||||
|
AUTHENTIK_DB_PASSWORD=
|
||||||
|
GITEA_DB_PASSWORD=
|
||||||
|
NETRONOME_DB_PASSWORD=
|
||||||
|
PENPOT_DB_PASSWORD=
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Shared PostgreSQL
|
||||||
|
|
||||||
|
This directory contains a PostgreSQL 15 deployment draft for Authentik, Gitea,
|
||||||
|
Netronome, and Penpot. It creates one database and one login role per service;
|
||||||
|
it does not migrate existing data or change application connection settings.
|
||||||
|
|
||||||
|
## Compatibility baseline
|
||||||
|
|
||||||
|
| Service | Current application | Current standalone PostgreSQL | Common PostgreSQL 15 |
|
||||||
|
| --------- | ------------------- | ----------------------------: | ------------------------------------------------------------------------------------ |
|
||||||
|
| Authentik | 2025.10.2 | 15 | Supported (Authentik requires 14+) |
|
||||||
|
| Gitea | 1.27.3 | 14 | Supported (Gitea requires 12+) |
|
||||||
|
| Netronome | 0.14.0 | 17 | Validate in staging; upstream's example uses 17 but no 17-only feature is documented |
|
||||||
|
| Penpot | 2.17.2 | 15 | Supported by the official deployment |
|
||||||
|
|
||||||
|
PostgreSQL 15 is the conservative common major. A major-version downgrade or
|
||||||
|
change must use a logical dump/restore; changing only the image tag while
|
||||||
|
keeping a data directory is not supported. Back up and migrate one application
|
||||||
|
at a time, starting with Netronome because its current standalone deployment
|
||||||
|
uses PostgreSQL 17.
|
||||||
|
|
||||||
|
For Compose, copy `.env.example` to `.env`, set all passwords, and start it with
|
||||||
|
`docker compose -f shared-compose.yaml up -d`. This file is intentionally not
|
||||||
|
named `compose.yaml`, so the repository deploy workflow does not start a second
|
||||||
|
database accidentally.
|
||||||
|
Applications that use this database must also join that external network and use
|
||||||
|
`homelab-postgres:5432`.
|
||||||
|
|
||||||
|
For Kubernetes, create `k8s/secrets.yaml` from the example before applying the
|
||||||
|
manifests. The `k8s/active` marker makes the normal deploy workflow include the
|
||||||
|
namespace, StatefulSet, ConfigMap, and NetworkPolicy. Applications use
|
||||||
|
`postgres.database.svc.cluster.local:5432`.
|
||||||
|
Migrate each existing database with a tested logical dump/restore before
|
||||||
|
switching an application. Do not reuse a PostgreSQL 14 or 17 data directory
|
||||||
|
with PostgreSQL 15.
|
||||||
Executable
+27
@@ -0,0 +1,27 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
: "${AUTHENTIK_DB_PASSWORD:?AUTHENTIK_DB_PASSWORD is required}"
|
||||||
|
: "${GITEA_DB_PASSWORD:?GITEA_DB_PASSWORD is required}"
|
||||||
|
: "${NETRONOME_DB_PASSWORD:?NETRONOME_DB_PASSWORD is required}"
|
||||||
|
: "${PENPOT_DB_PASSWORD:?PENPOT_DB_PASSWORD is required}"
|
||||||
|
|
||||||
|
create_role_and_database() {
|
||||||
|
local role="$1"
|
||||||
|
local database="$2"
|
||||||
|
local password="$3"
|
||||||
|
|
||||||
|
psql --username "$POSTGRES_USER" --dbname postgres \
|
||||||
|
-v role="$role" -v database="$database" -v password="$password" \
|
||||||
|
<<'SQL'
|
||||||
|
SELECT format('CREATE ROLE %I LOGIN PASSWORD %L', :'role', :'password')
|
||||||
|
WHERE NOT EXISTS (SELECT FROM pg_roles WHERE rolname = :'role')\gexec
|
||||||
|
SELECT format('CREATE DATABASE %I OWNER %I', :'database', :'role')
|
||||||
|
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = :'database')\gexec
|
||||||
|
SQL
|
||||||
|
}
|
||||||
|
|
||||||
|
create_role_and_database authentik authentik "$AUTHENTIK_DB_PASSWORD"
|
||||||
|
create_role_and_database gitea gitea "$GITEA_DB_PASSWORD"
|
||||||
|
create_role_and_database netronome netronome "$NETRONOME_DB_PASSWORD"
|
||||||
|
create_role_and_database penpot penpot "$PENPOT_DB_PASSWORD"
|
||||||
Whitespace-only changes.
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: database
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/part-of: homelab-database
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: postgres-ingress
|
||||||
|
namespace: database
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: postgres17
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: authentik
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: gitea
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: netronome
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: penpot
|
||||||
|
- namespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: statuspage
|
||||||
|
ports:
|
||||||
|
- protocol: TCP
|
||||||
|
port: 5432
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: postgres
|
||||||
|
namespace: database
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: postgres17
|
||||||
|
app.kubernetes.io/part-of: homelab-database
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: postgres17
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
port: 5432
|
||||||
|
targetPort: postgres
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: postgres17
|
||||||
|
namespace: database
|
||||||
|
spec:
|
||||||
|
serviceName: postgres17
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: postgres17
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: postgres17
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: postgres
|
||||||
|
image: postgres:17.6-alpine
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
containerPort: 5432
|
||||||
|
env:
|
||||||
|
- name: POSTGRES_DB
|
||||||
|
value: postgres
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
value: postgres
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: postgres-shared-secrets
|
||||||
|
key: POSTGRES_ADMIN_PASSWORD
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: postgres-shared-secrets
|
||||||
|
volumeMounts:
|
||||||
|
- name: postgres-data
|
||||||
|
mountPath: /var/lib/postgresql/data
|
||||||
|
- name: initdb
|
||||||
|
mountPath: /docker-entrypoint-initdb.d/01-create-databases.sh
|
||||||
|
subPath: 01-create-databases.sh
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["pg_isready", "-U", "postgres", "-d", "postgres"]
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["pg_isready", "-U", "postgres", "-d", "postgres"]
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 20
|
||||||
|
volumes:
|
||||||
|
- name: postgres-data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: postgres17-data
|
||||||
|
- name: initdb
|
||||||
|
configMap:
|
||||||
|
name: postgres-initdb
|
||||||
|
defaultMode: 0755
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: postgres17-data
|
||||||
|
namespace: database
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: postgres17
|
||||||
|
app.kubernetes.io/part-of: homelab-database
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
storageClassName: local-path-retain
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 20Gi
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: postgres-initdb
|
||||||
|
namespace: database
|
||||||
|
data:
|
||||||
|
01-create-databases.sh: |
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
: "${AUTHENTIK_DB_PASSWORD:?AUTHENTIK_DB_PASSWORD is required}"
|
||||||
|
: "${GITEA_DB_PASSWORD:?GITEA_DB_PASSWORD is required}"
|
||||||
|
: "${NETRONOME_DB_PASSWORD:?NETRONOME_DB_PASSWORD is required}"
|
||||||
|
: "${PENPOT_DB_PASSWORD:?PENPOT_DB_PASSWORD is required}"
|
||||||
|
: "${STATUSPAGE_DB_PASSWORD:?STATUSPAGE_DB_PASSWORD is required}"
|
||||||
|
|
||||||
|
create_role_and_database() {
|
||||||
|
local role="$1"
|
||||||
|
local database="$2"
|
||||||
|
local password="$3"
|
||||||
|
psql --username "$POSTGRES_USER" --dbname postgres \
|
||||||
|
-v role="$role" -v database="$database" -v password="$password" \
|
||||||
|
<<'SQL'
|
||||||
|
SELECT format('CREATE ROLE %I LOGIN PASSWORD %L', :'role', :'password')
|
||||||
|
WHERE NOT EXISTS (SELECT FROM pg_roles WHERE rolname = :'role')\gexec
|
||||||
|
SELECT format('CREATE DATABASE %I OWNER %I', :'database', :'role')
|
||||||
|
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = :'database')\gexec
|
||||||
|
SQL
|
||||||
|
}
|
||||||
|
|
||||||
|
create_role_and_database authentik authentik "$AUTHENTIK_DB_PASSWORD"
|
||||||
|
create_role_and_database gitea gitea "$GITEA_DB_PASSWORD"
|
||||||
|
create_role_and_database netronome netronome "$NETRONOME_DB_PASSWORD"
|
||||||
|
create_role_and_database penpot penpot "$PENPOT_DB_PASSWORD"
|
||||||
|
create_role_and_database statuspage statuspage "$STATUSPAGE_DB_PASSWORD"
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: postgres-shared-secrets
|
||||||
|
namespace: database
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
POSTGRES_ADMIN_PASSWORD: ""
|
||||||
|
AUTHENTIK_DB_PASSWORD: ""
|
||||||
|
GITEA_DB_PASSWORD: ""
|
||||||
|
NETRONOME_DB_PASSWORD: ""
|
||||||
|
PENPOT_DB_PASSWORD: ""
|
||||||
|
STATUSPAGE_DB_PASSWORD: ""
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:15.19-alpine
|
||||||
|
container_name: homelab-postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: postgres
|
||||||
|
POSTGRES_USER: postgres
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_ADMIN_PASSWORD:?set POSTGRES_ADMIN_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- postgres-data:/var/lib/postgresql/data
|
||||||
|
- ./initdb:/docker-entrypoint-initdb.d:ro
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
networks:
|
||||||
|
- database
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
database:
|
||||||
|
name: homelab-database
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
grafana:
|
grafana:
|
||||||
image: grafana/grafana:11.6.0
|
image: grafana/grafana:13.2.1
|
||||||
container_name: prometheus-grafana
|
container_name: prometheus-grafana
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file:
|
env_file:
|
||||||
@@ -30,7 +30,7 @@ services:
|
|||||||
- proxy
|
- proxy
|
||||||
|
|
||||||
prometheus:
|
prometheus:
|
||||||
image: prom/prometheus:v3.2.1
|
image: prom/prometheus:v3.14.0
|
||||||
container_name: prometheus-prometheus
|
container_name: prometheus-prometheus
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command:
|
command:
|
||||||
@@ -44,7 +44,7 @@ services:
|
|||||||
- proxy
|
- proxy
|
||||||
|
|
||||||
alertmanager:
|
alertmanager:
|
||||||
image: prom/alertmanager:v0.28.1
|
image: prom/alertmanager:v0.34.0
|
||||||
container_name: prometheus-alertmanager
|
container_name: prometheus-alertmanager
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command:
|
command:
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
route:
|
||||||
|
receiver: telegram
|
||||||
|
group_by:
|
||||||
|
- alertname
|
||||||
|
- namespace
|
||||||
|
group_wait: 30s
|
||||||
|
group_interval: 5m
|
||||||
|
repeat_interval: 12h
|
||||||
|
routes:
|
||||||
|
- receiver: null
|
||||||
|
matchers:
|
||||||
|
- alertname="InfoInhibitor"
|
||||||
|
- receiver: null
|
||||||
|
matchers:
|
||||||
|
- alertname="Watchdog"
|
||||||
|
|
||||||
|
inhibit_rules:
|
||||||
|
- source_matchers:
|
||||||
|
- severity="critical"
|
||||||
|
target_matchers:
|
||||||
|
- severity=~"warning|info"
|
||||||
|
equal:
|
||||||
|
- namespace
|
||||||
|
- source_matchers:
|
||||||
|
- severity="warning"
|
||||||
|
target_matchers:
|
||||||
|
- severity="info"
|
||||||
|
equal:
|
||||||
|
- namespace
|
||||||
|
|
||||||
|
receivers:
|
||||||
|
- name: telegram
|
||||||
|
telegram_configs:
|
||||||
|
- bot_token: REPLACE_WITH_TELEGRAM_BOT_TOKEN
|
||||||
|
chat_id: REPLACE_WITH_TELEGRAM_CHAT_ID
|
||||||
|
parse_mode: HTML
|
||||||
|
send_resolved: true
|
||||||
|
- name: null
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: PrometheusRule
|
||||||
|
metadata:
|
||||||
|
name: homelab-infrastructure
|
||||||
|
namespace: prometheus
|
||||||
|
labels:
|
||||||
|
release: prometheus-stack
|
||||||
|
spec:
|
||||||
|
groups:
|
||||||
|
- name: homelab.infrastructure
|
||||||
|
rules:
|
||||||
|
- alert: TargetDown
|
||||||
|
expr: up == 0
|
||||||
|
for: 10m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "Prometheus target is down"
|
||||||
|
description: "{{ $labels.job }} target {{ $labels.instance }} has been down for more than 10 minutes."
|
||||||
|
|
||||||
|
- alert: PodCrashLooping
|
||||||
|
expr: max_over_time(kube_pod_container_status_waiting_reason{reason="CrashLoopBackOff"}[10m]) >= 1
|
||||||
|
for: 10m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "Pod is crash looping"
|
||||||
|
description: "Container {{ $labels.container }} in {{ $labels.namespace }}/{{ $labels.pod }} is in CrashLoopBackOff."
|
||||||
|
|
||||||
|
- alert: PersistentVolumeClaimFillingUp
|
||||||
|
expr: kubelet_volume_stats_available_bytes / kubelet_volume_stats_capacity_bytes < 0.15
|
||||||
|
for: 15m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "PVC has less than 15% free space"
|
||||||
|
description: "{{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }} has less than 15% free space."
|
||||||
|
|
||||||
|
- alert: CPUThrottlingHigh
|
||||||
|
expr: |
|
||||||
|
sum without (id, metrics_path, name, image, endpoint, job, node) (
|
||||||
|
topk by (cluster, namespace, pod, container, instance) (1,
|
||||||
|
increase(container_cpu_cfs_throttled_periods_total{container!="", job="kubelet", metrics_path="/metrics/cadvisor", }[5m])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
/ on (cluster, namespace, pod, container, instance) group_left
|
||||||
|
sum without (id, metrics_path, name, image, endpoint, job, node) (
|
||||||
|
topk by (cluster, namespace, pod, container, instance) (1,
|
||||||
|
increase(container_cpu_cfs_periods_total{job="kubelet", metrics_path="/metrics/cadvisor", }[5m])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
> ( 50 / 100 )
|
||||||
|
for: 30m
|
||||||
|
labels:
|
||||||
|
severity: info
|
||||||
|
annotations:
|
||||||
|
summary: "Processes experience elevated CPU throttling"
|
||||||
|
description: "{{ $value | humanizePercentage }} throttling of CPU in namespace {{ $labels.namespace }} for container {{ $labels.container }} in pod {{ $labels.pod }} on cluster {{ $labels.cluster }}."
|
||||||
|
runbook_url: "https://runbooks.prometheus-operator.dev/runbooks/kubernetes/cputhrottlinghigh"
|
||||||
|
|
||||||
|
- alert: NodeMemoryPressure
|
||||||
|
expr: 100 * (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) > 90
|
||||||
|
for: 15m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "Node memory pressure"
|
||||||
|
description: "Node {{ $labels.instance }} has used more than 90% of memory for 15 minutes."
|
||||||
@@ -14,7 +14,8 @@ grafana:
|
|||||||
|
|
||||||
persistence:
|
persistence:
|
||||||
enabled: true
|
enabled: true
|
||||||
size: 10Gi
|
storageClassName: local-path-retain
|
||||||
|
size: 20Gi
|
||||||
|
|
||||||
ingress:
|
ingress:
|
||||||
enabled: false
|
enabled: false
|
||||||
@@ -24,10 +25,12 @@ grafana:
|
|||||||
|
|
||||||
prometheus:
|
prometheus:
|
||||||
prometheusSpec:
|
prometheusSpec:
|
||||||
|
retention: 60d
|
||||||
|
retentionSize: 32GB
|
||||||
storageSpec:
|
storageSpec:
|
||||||
volumeClaimTemplate:
|
volumeClaimTemplate:
|
||||||
spec:
|
spec:
|
||||||
storageClassName: "local-path"
|
storageClassName: "local-path-retain"
|
||||||
accessModes:
|
accessModes:
|
||||||
- ReadWriteOnce
|
- ReadWriteOnce
|
||||||
resources:
|
resources:
|
||||||
@@ -41,12 +44,17 @@ prometheus:
|
|||||||
memory: "2Gi"
|
memory: "2Gi"
|
||||||
alertmanager:
|
alertmanager:
|
||||||
alertmanagerSpec:
|
alertmanagerSpec:
|
||||||
|
configSecret: alertmanager-config
|
||||||
storage:
|
storage:
|
||||||
volumeClaimTemplate:
|
volumeClaimTemplate:
|
||||||
spec:
|
spec:
|
||||||
|
storageClassName: local-path-retain
|
||||||
accessModes:
|
accessModes:
|
||||||
- ReadWriteOnce
|
- ReadWriteOnce
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: 20Gi
|
storage: 10Gi
|
||||||
|
|
||||||
|
defaultRules:
|
||||||
|
disabled:
|
||||||
|
CPUThrottlingHigh: true
|
||||||
@@ -10,6 +10,8 @@ spec:
|
|||||||
- match: Host(`grafana.forust.xyz`)
|
- match: Host(`grafana.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
middlewares:
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
- name: "security-chain@file"
|
- name: "security-chain@file"
|
||||||
services:
|
services:
|
||||||
- name: prometheus-stack-grafana
|
- name: prometheus-stack-grafana
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: PrometheusRule
|
||||||
|
metadata:
|
||||||
|
name: traefik
|
||||||
|
namespace: prometheus
|
||||||
|
labels:
|
||||||
|
release: prometheus-stack
|
||||||
|
spec:
|
||||||
|
groups:
|
||||||
|
- name: traefik
|
||||||
|
rules:
|
||||||
|
- alert: TraefikDown
|
||||||
|
expr: absent(up{job="traefik"})
|
||||||
|
for: 10m
|
||||||
|
labels:
|
||||||
|
severity: critical
|
||||||
|
annotations:
|
||||||
|
summary: "Traefik metrics are unavailable"
|
||||||
|
description: "Prometheus has no Traefik target."
|
||||||
|
|
||||||
|
- alert: TraefikConfigReloadFailed
|
||||||
|
expr: traefik_config_last_reload_success == 0
|
||||||
|
for: 5m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "Traefik configuration reload failed"
|
||||||
|
description: "Traefik failed to apply its last configuration reload. Check Traefik logs and the dynamic config sources."
|
||||||
|
|
||||||
|
- alert: TraefikServiceHigh5xxRate
|
||||||
|
expr: |
|
||||||
|
sum(rate(traefik_service_requests_total{code=~"5.."}[5m])) by (service)
|
||||||
|
/ sum(rate(traefik_service_requests_total[5m])) by (service) * 100 > 5
|
||||||
|
and sum(rate(traefik_service_requests_total[5m])) by (service) > 0
|
||||||
|
for: 5m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "High 5xx error rate for service {{ $labels.service }}"
|
||||||
|
description: "Service {{ $labels.service }} is returning 5xx errors for more than 5% of requests over the last 5 minutes (current: {{ $value | humanizePercentage }})."
|
||||||
|
|
||||||
|
- alert: TraefikServiceHighLatency
|
||||||
|
expr: |
|
||||||
|
histogram_quantile(0.95,
|
||||||
|
sum(rate(traefik_service_request_duration_seconds_bucket[5m])) by (le, service)) > 2
|
||||||
|
for: 5m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "High latency for service {{ $labels.service }}"
|
||||||
|
description: "P95 latency of {{ $labels.service }} exceeded 2 seconds over the last 5 minutes (current: {{ $value | humanizeDuration }})."
|
||||||
|
|
||||||
|
- alert: TraefikCertExpiringSoon
|
||||||
|
expr: min(traefik_tls_certs_not_after) - time() < 14 * 24 * 60 * 60
|
||||||
|
for: 10m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "Traefik TLS certificate expires soon"
|
||||||
|
description: "A TLS certificate managed by Traefik expires in less than 14 days (in {{ $value | humanizeDuration }})."
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"extends": ["config:recommended"],
|
||||||
|
"enabledManagers": ["docker-compose", "kubernetes"],
|
||||||
|
"kubernetes": {
|
||||||
|
"managerFilePatterns": ["/k8s/.+\\.ya?ml$/"]
|
||||||
|
},
|
||||||
|
"packageRules": [
|
||||||
|
{
|
||||||
|
"description": "Keep private homelab images unchanged",
|
||||||
|
"matchDatasources": ["docker"],
|
||||||
|
"matchPackageNames": ["/gcr\\.forust\\.xyz\\/forust\\/.+/"],
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Require approval for major upgrades",
|
||||||
|
"matchUpdateTypes": ["major"],
|
||||||
|
"dependencyDashboardApproval": true,
|
||||||
|
"automerge": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Group container patch updates",
|
||||||
|
"matchDatasources": ["docker"],
|
||||||
|
"matchUpdateTypes": ["patch"],
|
||||||
|
"groupName": "container patch updates"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
RENOVATE_ENDPOINT=https://gitea.forust.xyz/api/v1
|
||||||
|
RENOVATE_TOKEN=
|
||||||
|
RENOVATE_REPOSITORIES=forust/homelab
|
||||||
|
LOG_LEVEL=info
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# Renovate for Gitea
|
||||||
|
|
||||||
|
Renovate runs as a Kubernetes CronJob and creates container image update pull
|
||||||
|
requests in Gitea. It does not deploy changes itself.
|
||||||
|
|
||||||
|
## Kubernetes
|
||||||
|
|
||||||
|
Create a dedicated Gitea user named `renovate-bot`, create a repository access
|
||||||
|
token, and grant it repository read/write plus issue read/write permissions.
|
||||||
|
Add `read:packages` if Renovate must inspect private Gitea registry images.
|
||||||
|
|
||||||
|
Create the ignored Secret locally; never commit the PAT:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cp renovate/k8s/secrets.yaml.example renovate/k8s/secrets.yaml
|
||||||
|
$EDITOR renovate/k8s/secrets.yaml
|
||||||
|
kubectl apply -f renovate/k8s/namespace.yaml
|
||||||
|
kubectl apply -f renovate/k8s/secrets.yaml
|
||||||
|
kubectl apply -f renovate/k8s/configmap.yaml
|
||||||
|
kubectl apply -f renovate/k8s/cronjob.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
The `renovate/k8s/active` marker makes the normal deployment workflow include
|
||||||
|
the namespace, ConfigMap, and CronJob. The Secret is intentionally excluded
|
||||||
|
from Git and must be applied separately after every new cluster.
|
||||||
|
|
||||||
|
Run it immediately instead of waiting for the six-hour schedule:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
kubectl create job --from=cronjob/renovate renovate-manual-$(date +%s) -n renovate
|
||||||
|
```
|
||||||
|
|
||||||
|
Inspect runs with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
kubectl get cronjob,jobs,pods -n renovate
|
||||||
|
kubectl logs -n renovate job/<job-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
`RENOVATE_GITHUB_COM_TOKEN` is optional but recommended for changelogs and
|
||||||
|
GitHub API rate limits. Set it in the Kubernetes Secret if available.
|
||||||
|
|
||||||
|
## Compose
|
||||||
|
|
||||||
|
Copy `.env.example` to `.env`, set the PAT, and run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker compose -f renovate-compose.yaml run --rm renovate
|
||||||
|
```
|
||||||
|
|
||||||
|
The Compose file is intentionally named `renovate-compose.yaml`, so the
|
||||||
|
repository's automatic deployment discovery does not start it accidentally.
|
||||||
|
|
||||||
|
## How updates flow
|
||||||
|
|
||||||
|
Renovate scans both `compose.yaml` files and Kubernetes manifests, opens a
|
||||||
|
branch and PR with image tag changes, and waits for CI. After merge, the
|
||||||
|
existing deployment workflow applies Kubernetes changes or redeploys Compose
|
||||||
|
stacks. Renovate never updates running workloads directly.
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
module.exports = {
|
||||||
|
platform: 'gitea',
|
||||||
|
endpoint: process.env.RENOVATE_ENDPOINT,
|
||||||
|
enabledManagers: ['docker-compose', 'kubernetes'],
|
||||||
|
kubernetes: {
|
||||||
|
managerFilePatterns: ['/k8s/.+\\.ya?ml$/'],
|
||||||
|
},
|
||||||
|
repositories: (process.env.RENOVATE_REPOSITORIES || '')
|
||||||
|
.split(',')
|
||||||
|
.map((repository) => repository.trim())
|
||||||
|
.filter(Boolean),
|
||||||
|
onboarding: false,
|
||||||
|
requireConfig: 'optional',
|
||||||
|
autodiscover: false,
|
||||||
|
dependencyDashboard: true,
|
||||||
|
prCreation: 'immediate',
|
||||||
|
labels: ['dependencies', 'automated'],
|
||||||
|
extends: [
|
||||||
|
'config:recommended',
|
||||||
|
':dependencyDashboard',
|
||||||
|
],
|
||||||
|
packageRules: [
|
||||||
|
{
|
||||||
|
description: 'Do not update private homelab images',
|
||||||
|
matchDatasources: ['docker'],
|
||||||
|
matchPackageNames: ['/gcr\\.forust\\.xyz\\/forust\\/.+/'],
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'Keep major upgrades manual',
|
||||||
|
matchUpdateTypes: ['major'],
|
||||||
|
dependencyDashboardApproval: true,
|
||||||
|
automerge: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'Group patch updates',
|
||||||
|
matchUpdateTypes: ['patch'],
|
||||||
|
groupName: 'container patch updates',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
Whitespace-only changes.
@@ -0,0 +1,45 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: renovate-config
|
||||||
|
namespace: renovate
|
||||||
|
data:
|
||||||
|
config.js: |
|
||||||
|
module.exports = {
|
||||||
|
platform: 'gitea',
|
||||||
|
endpoint: process.env.RENOVATE_ENDPOINT,
|
||||||
|
enabledManagers: ['docker-compose', 'kubernetes'],
|
||||||
|
kubernetes: {
|
||||||
|
managerFilePatterns: ['/k8s/.+\\.ya?ml$/'],
|
||||||
|
},
|
||||||
|
repositories: (process.env.RENOVATE_REPOSITORIES || '')
|
||||||
|
.split(',')
|
||||||
|
.map((repository) => repository.trim())
|
||||||
|
.filter(Boolean),
|
||||||
|
onboarding: false,
|
||||||
|
requireConfig: 'optional',
|
||||||
|
autodiscover: false,
|
||||||
|
dependencyDashboard: true,
|
||||||
|
prCreation: 'immediate',
|
||||||
|
labels: ['dependencies', 'automated'],
|
||||||
|
extends: ['config:recommended', ':dependencyDashboard'],
|
||||||
|
packageRules: [
|
||||||
|
{
|
||||||
|
description: 'Do not update private homelab images',
|
||||||
|
matchDatasources: ['docker'],
|
||||||
|
matchPackageNames: ['/gcr\\.forust\\.xyz\\/forust\\/.+/'],
|
||||||
|
enabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'Keep major upgrades manual',
|
||||||
|
matchUpdateTypes: ['major'],
|
||||||
|
dependencyDashboardApproval: true,
|
||||||
|
automerge: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: 'Group patch updates',
|
||||||
|
matchUpdateTypes: ['patch'],
|
||||||
|
groupName: 'container patch updates',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
apiVersion: batch/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: renovate
|
||||||
|
namespace: renovate
|
||||||
|
spec:
|
||||||
|
schedule: "17 */6 * * *"
|
||||||
|
concurrencyPolicy: Forbid
|
||||||
|
successfulJobsHistoryLimit: 2
|
||||||
|
failedJobsHistoryLimit: 3
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
backoffLimit: 1
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
restartPolicy: Never
|
||||||
|
containers:
|
||||||
|
- name: renovate
|
||||||
|
image: renovate/renovate:44.83.2
|
||||||
|
env:
|
||||||
|
- name: RENOVATE_PLATFORM
|
||||||
|
value: gitea
|
||||||
|
- name: RENOVATE_ENDPOINT
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: renovate-secrets
|
||||||
|
key: RENOVATE_ENDPOINT
|
||||||
|
- name: RENOVATE_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: renovate-secrets
|
||||||
|
key: RENOVATE_TOKEN
|
||||||
|
- name: RENOVATE_REPOSITORIES
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: renovate-secrets
|
||||||
|
key: RENOVATE_REPOSITORIES
|
||||||
|
- name: RENOVATE_CONFIG_FILE
|
||||||
|
value: /opt/renovate/config.js
|
||||||
|
- name: RENOVATE_BASE_DIR
|
||||||
|
value: /tmp/renovate
|
||||||
|
- name: RENOVATE_GITHUB_COM_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: renovate-secrets
|
||||||
|
key: RENOVATE_GITHUB_COM_TOKEN
|
||||||
|
optional: true
|
||||||
|
- name: LOG_LEVEL
|
||||||
|
value: info
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /opt/renovate/config.js
|
||||||
|
subPath: config.js
|
||||||
|
readOnly: true
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
configMap:
|
||||||
|
name: renovate-config
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: renovate
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/part-of: renovate
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: renovate-secrets
|
||||||
|
namespace: renovate
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
RENOVATE_TOKEN: ""
|
||||||
|
RENOVATE_ENDPOINT: "https://gitea.forust.xyz/api/v1"
|
||||||
|
RENOVATE_REPOSITORIES: "forust/homelab"
|
||||||
|
RENOVATE_GITHUB_COM_TOKEN: ""
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
services:
|
||||||
|
renovate:
|
||||||
|
image: renovate/renovate:44.83.2
|
||||||
|
container_name: renovate
|
||||||
|
restart: "no"
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
RENOVATE_PLATFORM: gitea
|
||||||
|
RENOVATE_ENDPOINT: ${RENOVATE_ENDPOINT:?set RENOVATE_ENDPOINT}
|
||||||
|
RENOVATE_TOKEN: ${RENOVATE_TOKEN:?set RENOVATE_TOKEN}
|
||||||
|
RENOVATE_REPOSITORIES: ${RENOVATE_REPOSITORIES:?set RENOVATE_REPOSITORIES}
|
||||||
|
RENOVATE_CONFIG_FILE: /opt/renovate/config.js
|
||||||
|
RENOVATE_BASE_DIR: /tmp/renovate
|
||||||
|
LOG_LEVEL: ${LOG_LEVEL:-info}
|
||||||
|
volumes:
|
||||||
|
- ./config.js:/opt/renovate/config.js:ro
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
services:
|
services:
|
||||||
core:
|
core:
|
||||||
container_name: searxng-core
|
container_name: searxng-core
|
||||||
image: docker.io/searxng/searxng:${SEARXNG_VERSION:-latest}
|
image: docker.io/searxng/searxng:${SEARXNG_VERSION:-2026.09.13-d4ce87c23}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# ports:
|
# ports:
|
||||||
# - ${SEARXNG_PORT:-8080}
|
# - ${SEARXNG_PORT:-8080}
|
||||||
@@ -31,7 +31,7 @@ services:
|
|||||||
|
|
||||||
valkey:
|
valkey:
|
||||||
container_name: searxng-valkey
|
container_name: searxng-valkey
|
||||||
image: docker.io/valkey/valkey:9-alpine
|
image: docker.io/valkey/valkey:9.1.2-alpine
|
||||||
command: valkey-server --save 30 1 --loglevel warning
|
command: valkey-server --save 30 1 --loglevel warning
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ spec:
|
|||||||
routes:
|
routes:
|
||||||
- match: Host(`s.forust.xyz`) || Host(`search.forust.xyz`)
|
- match: Host(`s.forust.xyz`) || Host(`search.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: searxng-service
|
- name: searxng-service
|
||||||
port: 8080
|
port: 8080
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: searxng
|
- name: searxng
|
||||||
image: docker.io/searxng/searxng:latest
|
image: docker.io/searxng/searxng:2026.09.13-d4ce87c23
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
name: searxng-config
|
name: searxng-config
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: valkey
|
- name: valkey
|
||||||
image: docker.io/valkey/valkey:9-alpine
|
image: docker.io/valkey/valkey:9.1.2-alpine
|
||||||
command:
|
command:
|
||||||
- valkey-server
|
- valkey-server
|
||||||
- --save
|
- --save
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
termix:
|
termix:
|
||||||
image: ghcr.io/lukegus/termix:latest
|
image: ghcr.io/lukegus/termix:2.7.1
|
||||||
container_name: termix
|
container_name: termix
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# ports:
|
# ports:
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ spec:
|
|||||||
routes:
|
routes:
|
||||||
- match: Host(`termix.forust.xyz`)
|
- match: Host(`termix.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: termix-service
|
- name: termix-service
|
||||||
port: 8080
|
port: 8080
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: termix
|
- name: termix
|
||||||
image: ghcr.io/lukegus/termix:latest
|
image: ghcr.io/lukegus/termix:2.7.1
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
name: termix-config
|
name: termix-config
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
traefik:
|
traefik:
|
||||||
image: traefik:v3.7.4
|
image: traefik:v3.7.13
|
||||||
container_name: traefik
|
container_name: traefik
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command:
|
command:
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ spec:
|
|||||||
routes:
|
routes:
|
||||||
- match: Host(`traefik.forust.xyz`)
|
- match: Host(`traefik.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-bouncer
|
||||||
|
namespace: crowdsec
|
||||||
services:
|
services:
|
||||||
- name: api@internal
|
- name: api@internal
|
||||||
kind: TraefikService
|
kind: TraefikService
|
||||||
|
|||||||
Loaded 100 of 106 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user