diff --git a/openshift/LICENSE b/openshift/LICENSE new file mode 100644 index 00000000..47835467 --- /dev/null +++ b/openshift/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 n8n - Workflow Automation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/openshift/README.md b/openshift/README.md new file mode 100644 index 00000000..b55e6413 --- /dev/null +++ b/openshift/README.md @@ -0,0 +1,74 @@ +# n8n on OpenShift + +Manifests in this folder deploy: + +- `n8n` in namespace `n8n` +- PostgreSQL backend (`postgres:18`) +- Persistent volumes for both workloads +- OpenShift `Route` with TLS edge termination + +Deployment is managed through `kustomization.yaml`. + +## Files in this folder + +- `namespace.yaml`: Creates namespace `n8n` +- `postgres-secret.yaml`: PostgreSQL credentials +- `postgres-configmap.yaml`: DB init script to create non-root DB user +- `postgres-claim0-persistentvolumeclaim.yaml`: PostgreSQL PVC (`300Gi`) +- `postgres-deployment.yaml`: PostgreSQL Deployment +- `postgres-service.yaml`: PostgreSQL headless Service (`postgres-service`) +- `n8n-claim0-persistentvolumeclaim.yaml`: n8n PVC (`2Gi`) +- `n8n-deployment.yaml`: n8n Deployment configured for PostgreSQL +- `n8n-service.yaml`: n8n ClusterIP Service +- `n8n-route.yaml`: Public OpenShift Route for n8n + +## Prerequisites + +- OpenShift cluster access (`oc` logged in) +- Dynamic storage class available for PVC provisioning +- DNS for route host (or host override for testing) + +## Required changes before deploy + +1. Update PostgreSQL credentials in `postgres-secret.yaml`. +2. Update route hostname in `n8n-route.yaml`: + - `spec.host: n8n.example.com` +3. Update n8n webhook URL in `n8n-deployment.yaml`: + - `WEBHOOK_URL=https://n8n.example.com/` + +Recommended: + +- Right-size PostgreSQL resources and storage (`300Gi` may be larger than needed in small labs). + +## Deploy + +From this folder: + +```bash +oc apply -k . +``` + +## Verify + +```bash +oc get all -n n8n +oc get pvc -n n8n +oc get route n8n-web -n n8n +``` + +Wait until both Deployments are available: + +```bash +oc rollout status deploy/postgres -n n8n +oc rollout status deploy/n8n -n n8n +``` + +## Access + +Open the route host configured in `n8n-route.yaml` (for example `https://n8n.example.com`). + +## Cleanup + +```bash +oc delete -k . +``` diff --git a/openshift/kustomization.yaml b/openshift/kustomization.yaml new file mode 100755 index 00000000..57c2e768 --- /dev/null +++ b/openshift/kustomization.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +namespace: n8n + +resources: + - namespace.yaml + - postgres-configmap.yaml + - postgres-secret.yaml + - postgres-claim0-persistentvolumeclaim.yaml + - postgres-deployment.yaml + - postgres-service.yaml + - n8n-claim0-persistentvolumeclaim.yaml + - n8n-deployment.yaml + - n8n-service.yaml + - n8n-route.yaml diff --git a/openshift/n8n-claim0-persistentvolumeclaim.yaml b/openshift/n8n-claim0-persistentvolumeclaim.yaml new file mode 100644 index 00000000..53954840 --- /dev/null +++ b/openshift/n8n-claim0-persistentvolumeclaim.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + service: n8n-claim0 + name: n8n-claim0 + namespace: n8n +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi diff --git a/openshift/n8n-deployment.yaml b/openshift/n8n-deployment.yaml new file mode 100644 index 00000000..edb54107 --- /dev/null +++ b/openshift/n8n-deployment.yaml @@ -0,0 +1,73 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + service: n8n + name: n8n + namespace: n8n +spec: + replicas: 1 + selector: + matchLabels: + service: n8n + strategy: + type: Recreate + template: + metadata: + labels: + service: n8n + spec: + containers: + - command: + - /bin/sh + args: + - -c + - sleep 5; n8n start + env: + - name: DB_TYPE + value: postgresdb + - name: DB_POSTGRESDB_HOST + value: postgres-service.n8n.svc.cluster.local + - name: DB_POSTGRESDB_PORT + value: "5432" + - name: DB_POSTGRESDB_DATABASE + value: n8n + - name: DB_POSTGRESDB_USER + valueFrom: + secretKeyRef: + name: postgres-secret + key: POSTGRES_NON_ROOT_USER + - name: DB_POSTGRESDB_PASSWORD + valueFrom: + secretKeyRef: + name: postgres-secret + key: POSTGRES_NON_ROOT_PASSWORD + # OpenShift + - name: N8N_USER_FOLDER + value: /data + - name: N8N_PROTOCOL + value: https + - name: WEBHOOK_URL + value: https://n8n.example.com/ + - name: N8N_PORT + value: "5678" + image: n8nio/n8n + name: n8n + ports: + - containerPort: 5678 + resources: + requests: + memory: "250Mi" + limits: + memory: "500Mi" + volumeMounts: + - mountPath: /data + name: n8n-claim0 + restartPolicy: Always + volumes: + - name: n8n-claim0 + persistentVolumeClaim: + claimName: n8n-claim0 + - name: postgres-secret + secret: + secretName: postgres-secret diff --git a/openshift/n8n-route.yaml b/openshift/n8n-route.yaml new file mode 100644 index 00000000..fa162b9e --- /dev/null +++ b/openshift/n8n-route.yaml @@ -0,0 +1,17 @@ +kind: Route +apiVersion: route.openshift.io/v1 +metadata: + name: n8n-web + namespace: n8n +spec: + host: n8n.example.com + to: + kind: Service + name: n8n + weight: 100 + port: + targetPort: 5678 + tls: + termination: edge + insecureEdgeTerminationPolicy: Redirect + wildcardPolicy: None \ No newline at end of file diff --git a/openshift/n8n-service.yaml b/openshift/n8n-service.yaml new file mode 100644 index 00000000..ad2d5435 --- /dev/null +++ b/openshift/n8n-service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + service: n8n + name: n8n + namespace: n8n +spec: + type: ClusterIP + ports: + - name: "n8n" + port: 5678 + targetPort: 5678 + protocol: TCP + selector: + service: n8n diff --git a/openshift/namespace.yaml b/openshift/namespace.yaml new file mode 100644 index 00000000..8389695a --- /dev/null +++ b/openshift/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: n8n diff --git a/openshift/postgres-claim0-persistentvolumeclaim.yaml b/openshift/postgres-claim0-persistentvolumeclaim.yaml new file mode 100644 index 00000000..226dd48e --- /dev/null +++ b/openshift/postgres-claim0-persistentvolumeclaim.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: postgresql-pv + namespace: n8n +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 300Gi diff --git a/openshift/postgres-configmap.yaml b/openshift/postgres-configmap.yaml new file mode 100644 index 00000000..564337dc --- /dev/null +++ b/openshift/postgres-configmap.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: init-data + namespace: n8n +data: + init-data.sh: | + #!/bin/bash + set -e; + if [ -n "${POSTGRES_NON_ROOT_USER:-}" ] && [ -n "${POSTGRES_NON_ROOT_PASSWORD:-}" ]; then + ESCAPED_PASSWORD="${POSTGRES_NON_ROOT_PASSWORD//\'/\'\'}" + psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL + CREATE USER "${POSTGRES_NON_ROOT_USER}" WITH PASSWORD '${ESCAPED_PASSWORD}'; + GRANT ALL PRIVILEGES ON DATABASE ${POSTGRES_DB} TO "${POSTGRES_NON_ROOT_USER}"; + GRANT ALL ON SCHEMA public TO "${POSTGRES_NON_ROOT_USER}"; + EOSQL + else + echo "SETUP INFO: No Environment variables given!" + fi \ No newline at end of file diff --git a/openshift/postgres-deployment.yaml b/openshift/postgres-deployment.yaml new file mode 100644 index 00000000..ceb65fe3 --- /dev/null +++ b/openshift/postgres-deployment.yaml @@ -0,0 +1,81 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + service: postgres-n8n + name: postgres + namespace: n8n +spec: + replicas: 1 + selector: + matchLabels: + service: postgres-n8n + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 1 + type: RollingUpdate + template: + metadata: + labels: + service: postgres-n8n + spec: + containers: + - image: postgres:18 + name: postgres + resources: + limits: + cpu: "4" + memory: 4Gi + requests: + cpu: "1" + memory: 2Gi + ports: + - containerPort: 5432 + volumeMounts: + - name: postgresql-pv + mountPath: /var/lib/postgresql/data + - name: init-data + mountPath: /docker-entrypoint-initdb.d/init-n8n-user.sh + subPath: init-data.sh + env: + - name: PGDATA + value: /var/lib/postgresql/data/pgdata + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: postgres-secret + key: POSTGRES_USER + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: postgres-secret + key: POSTGRES_PASSWORD + - name: POSTGRES_DB + value: n8n + - name: POSTGRES_NON_ROOT_USER + valueFrom: + secretKeyRef: + name: postgres-secret + key: POSTGRES_NON_ROOT_USER + - name: POSTGRES_NON_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: postgres-secret + key: POSTGRES_NON_ROOT_PASSWORD + - name: POSTGRES_HOST + value: postgres-service + - name: POSTGRES_PORT + value: '5432' + restartPolicy: Always + volumes: + - name: postgresql-pv + persistentVolumeClaim: + claimName: postgresql-pv + - name: postgres-secret + secret: + secretName: postgres-secret + - name: init-data + configMap: + name: init-data + defaultMode: 0744 diff --git a/openshift/postgres-secret.yaml b/openshift/postgres-secret.yaml new file mode 100644 index 00000000..29d006c8 --- /dev/null +++ b/openshift/postgres-secret.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Secret +metadata: + namespace: n8n + name: postgres-secret +type: Opaque +stringData: + POSTGRES_USER: changeUser + POSTGRES_PASSWORD: changePassword + POSTGRES_DB: n8n + POSTGRES_NON_ROOT_USER: changeUser + POSTGRES_NON_ROOT_PASSWORD: changePassword \ No newline at end of file diff --git a/openshift/postgres-service.yaml b/openshift/postgres-service.yaml new file mode 100644 index 00000000..ab755fe3 --- /dev/null +++ b/openshift/postgres-service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + service: postgres-n8n + name: postgres-service + namespace: n8n +spec: + clusterIP: None + ports: + - name: "5432" + port: 5432 + targetPort: 5432 + protocol: TCP + selector: + service: postgres-n8n