first commit

This commit is contained in:
sttlab
2026-07-22 14:41:10 +00:00
commit e1577fe061
35 changed files with 1847 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
# One-off Job to create the "n8n" database on the shared Postgres instance.
# Mirrors k8s/miniflux/create-db-job.yaml.
apiVersion: batch/v1
kind: Job
metadata:
name: create-db-n8n
namespace: postgres
spec:
backoffLimit: 3
template:
spec:
restartPolicy: Never
containers:
- name: create-db
image: postgres:18-alpine
envFrom:
- secretRef:
name: postgres-admin
command:
- sh
- -c
- |
set -e
psql "postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres-postgresql:5432/postgres" \
-tc "SELECT 1 FROM pg_database WHERE datname = 'n8n'" | grep -q 1 \
|| psql "postgres://$POSTGRES_USER:$POSTGRES_PASSWORD@postgres-postgresql:5432/postgres" \
-c "CREATE DATABASE n8n"
+97
View File
@@ -0,0 +1,97 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: n8n
namespace: watch
labels:
app.kubernetes.io/name: n8n
spec:
replicas: 1
strategy:
type: Recreate # single ReadWriteOnce PVC, avoid two pods mounting it at once
selector:
matchLabels:
app.kubernetes.io/name: n8n
template:
metadata:
labels:
app.kubernetes.io/name: n8n
spec:
securityContext:
fsGroup: 1000 # matches the "node" user baked into the n8n image
containers:
- name: n8n
image: n8nio/n8n:latest
ports:
- name: http
containerPort: 5678
envFrom:
- secretRef:
name: n8n-credentials
env:
- name: DB_TYPE
value: postgresdb
- name: DB_POSTGRESDB_HOST
value: postgres-postgresql.postgres.svc.cluster.local
- name: DB_POSTGRESDB_PORT
value: "5432"
- name: DB_POSTGRESDB_DATABASE
value: n8n
- name: N8N_HOST
value: n8n.sttlab.pc
- name: N8N_PORT
value: "5678"
- name: N8N_PROTOCOL
value: https
- name: N8N_WEBHOOK_URL
value: https://n8n.sttlab.pc/
- name: GENERIC_TIMEZONE
value: Europe/Paris
- name: TZ
value: Europe/Paris
- name: N8N_RESTRICT_FILE_ACCESS_TO
value: "/data" # single path only (no list support)
volumeMounts:
- name: data
mountPath: /home/node/.n8n
- name: digest-workspace
mountPath: /data # dedicated volume for Read/Write File nodes, separate from n8n's own
# internal directory (which n8n always blocks file-node access to, regardless of
# N8N_RESTRICT_FILE_ACCESS_TO, via N8N_BLOCK_FILE_ACCESS_TO_N8N_FILES)
- name: digest-prompt
mountPath: /data/prompts/digest.md
subPath: digest.md # avoids the ConfigMap symlink indirection, which trips n8n's file-access allowlist check
readOnly: true
- name: digest-prompt
mountPath: /data/prompts/editorial.md
subPath: editorial.md
readOnly: true
resources:
requests:
cpu: 200m
memory: 512Mi
limits:
cpu: 1000m
memory: 2Gi
readinessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 10
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: http
initialDelaySeconds: 30
periodSeconds: 20
volumes:
- name: data
persistentVolumeClaim:
claimName: n8n-data
- name: digest-workspace
persistentVolumeClaim:
claimName: n8n-digest-workspace
- name: digest-prompt
configMap:
name: n8n-digest-prompt
+20
View File
@@ -0,0 +1,20 @@
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: n8n
namespace: watch
spec:
gatewayClassName: envoy
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: n8n.sttlab.pc
allowedRoutes:
namespaces:
from: Same
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: sttlab-pc-tls
+21
View File
@@ -0,0 +1,21 @@
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: n8n
namespace: watch
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: n8n
hostnames:
- n8n.sttlab.pc
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- kind: Service
name: n8n
port: 80
@@ -0,0 +1,20 @@
# Copy to miniflux-token-secret.yaml, fill in the real token, and apply with:
# kubectl apply -f miniflux-token-secret.yaml
# Never commit the filled-in file to git.
#
# Generate the token in the Miniflux UI under Settings -> API Keys (no
# public REST endpoint creates one). Kept here as the source of truth /
# backup; the digest workflow itself should use an n8n "Header Auth"
# credential (header name X-Auth-Token) created in the n8n UI from these
# same values, not a raw env var — n8n blocks $env access from workflow
# expressions by default (N8N_BLOCK_ENV_ACCESS_IN_NODE), so this Secret is
# not wired into the n8n Deployment's envFrom.
apiVersion: v1
kind: Secret
metadata:
name: miniflux-api-token
namespace: watch
type: Opaque
stringData:
MINIFLUX_URL: https://miniflux.sttlab.pc/v1/
MINIFLUX_API_TOKEN: changeme
+26
View File
@@ -0,0 +1,26 @@
# Persists /home/node/.n8n (encryption key backup, local binary data cache,
# community nodes). Workflow/execution data itself lives in Postgres.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: n8n-data
namespace: watch
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 2Gi
---
# Separate volume for Read/Write File nodes (digest prompt + output), kept
# apart from n8n-data (n8n's own internal directory, which n8n always
# blocks file-node access to regardless of N8N_RESTRICT_FILE_ACCESS_TO).
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: n8n-digest-workspace
namespace: watch
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
+19
View File
@@ -0,0 +1,19 @@
# Copy to secret.yaml, fill in real values, and apply with:
# kubectl apply -f secret.yaml
# Never commit the filled-in secret.yaml to git.
#
# DB_POSTGRESDB_USER/PASSWORD must match k8s/postgres/secret.yaml.
#
# N8N_ENCRYPTION_KEY encrypts credentials stored in the n8n database.
# Generate once with `openssl rand -hex 24` and never change it afterwards
# (rotating it locks n8n out of every credential already saved).
apiVersion: v1
kind: Secret
metadata:
name: n8n-credentials
namespace: watch
type: Opaque
stringData:
DB_POSTGRESDB_USER: postgres
DB_POSTGRESDB_PASSWORD: changeme
N8N_ENCRYPTION_KEY: changeme
+14
View File
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: n8n
namespace: watch
labels:
app.kubernetes.io/name: n8n
spec:
selector:
app.kubernetes.io/name: n8n
ports:
- name: http
port: 80
targetPort: 5678