diff --git a/.github/configs/ct-install.yaml b/.github/configs/ct-install.yaml index ed27887..f4d7946 100644 --- a/.github/configs/ct-install.yaml +++ b/.github/configs/ct-install.yaml @@ -6,7 +6,8 @@ chart-dirs: - charts chart-repos: - plural=https://pluralsh.github.io/plural-helm-charts -helm-extra-args: "--timeout 600s" + - bitnami=https://charts.bitnami.com/bitnami +helm-extra-args: "--timeout 600s" validate-chart-schema: false validate-maintainers: true validate-yaml: true diff --git a/.github/configs/ct-lint.yaml b/.github/configs/ct-lint.yaml index 3f9d6d7..162a3d7 100644 --- a/.github/configs/ct-lint.yaml +++ b/.github/configs/ct-lint.yaml @@ -6,7 +6,8 @@ chart-dirs: - charts chart-repos: - plural=https://pluralsh.github.io/plural-helm-charts -helm-extra-args: "--timeout 600s" + - bitnami=https://charts.bitnami.com/bitnami +helm-extra-args: "--timeout 600s" validate-chart-schema: false validate-maintainers: true validate-yaml: true diff --git a/charts/n8n/CHANGELOG.md b/charts/n8n/CHANGELOG.md new file mode 100644 index 0000000..0498d16 --- /dev/null +++ b/charts/n8n/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog + +This file documents all notable changes to the [n8n-helm-chart](https://github.com/8gears/n8n-helm-chart/). The release numbering uses [semantic versioning](http://semver.org). + +The actual changelog is located in (./Chart.yaml)[Chart.yaml]. diff --git a/charts/n8n/Chart.lock b/charts/n8n/Chart.lock new file mode 100644 index 0000000..09104cb --- /dev/null +++ b/charts/n8n/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: redis + repository: https://charts.bitnami.com/bitnami + version: 17.2.0 +digest: sha256:989a8e3f05d54b04db15e782bd24ca5a5872a36f5dc02b7882b25491a5a5ddde +generated: "2022-09-30T08:49:11.0457529+02:00" diff --git a/charts/n8n/Chart.yaml b/charts/n8n/Chart.yaml new file mode 100644 index 0000000..bc7600e --- /dev/null +++ b/charts/n8n/Chart.yaml @@ -0,0 +1,41 @@ +apiVersion: v2 +name: n8n +version: 0.12.0 +appVersion: 1.5.1 +type: application + +description: "A Kubernetes Helm chart for n8n a free and open fair-code licensed node based Workflow Automation Tool. Easily automate tasks across different services." +home: https://github.com/8gears/n8n-helm-chart +icon: https://avatars1.githubusercontent.com/u/45487711?s=200&v=4 +keywords: + - Workflow Automation + - Workflow + - iPaaS + - integration-framework + - low-code-plattform + - low-code +sources: + - https://github.com/n8n-io/n8n + - https://n8n.io/ +maintainers: + - name: Vadim Bauer + +dependencies: + - name: redis + version: 17.2.0 + repository: https://charts.bitnami.com/bitnami + condition: redis.enabled + +annotations: + artifacthub.io/changes: | + - kind: changed + description: "Updated App Version to 1.5.1" + - kind: added + description: "Added support for specifying initContainers and probes" + - kind: changed + description: "Updated App Version to 0.236.3" + - kind: added + description: "Support Kubernetes 1.25" + links: + - name: GitHub PR + url: https://github.com/8gears/n8n-helm-chart/pull/46 diff --git a/charts/n8n/LICENSE b/charts/n8n/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/charts/n8n/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/charts/n8n/README.md b/charts/n8n/README.md new file mode 100644 index 0000000..dfaf9c1 --- /dev/null +++ b/charts/n8n/README.md @@ -0,0 +1,323 @@ +# n8n Helm Chart for Kubernetes + +[n8n](https://github.com/n8n-io/n8n) is an extendable workflow automation tool. + +[![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/open-8gears)](https://artifacthub.io/packages/search?repo=open-8gears) + +The Helm chart source code location is [github.com/8gears/n8n-helm-chart](https://github.com/8gears/n8n-helm-chart) + + +## Requirements + +Before you start make sure you have the following dependencies ready and working: + +- Helm > 3 +- Postgres DB | MySQL | Embedded SQLite +- Helmfile (Optional) + +## Configuration + +The `values.yaml` file is divided into a n8n specific configuration section, and a Kubernetes deployment specific section. +The shown values represent Helm defaults not application defaults. The comments behind the values provide a description and display the application default. +Every possible n8n config can be set that are also described in the: [n8n configuration options](https://github.com/n8n-io/n8n/blob/master/packages/cli/src/config/schema.ts). + +These n8n config options should be attached to Secret or Config. +You decide what should be a secret and what should be a config the options are the same. + +# N8N Specific Config Section +This is only an excerpt. All options are supported, see https://github.com/n8n-io/n8n/blob/master/packages/cli/src/config/schema.ts + +```yaml +database: + type: # Type of database to use - Other possible types ['sqlite', 'mariadb', 'mysqldb', 'postgresdb'] - default: sqlite + tablePrefix: # Prefix for table names - default: '' + postgresdb: + database: # PostgresDB Database - default: n8n + host: # PostgresDB Host - default: localhost + password: # PostgresDB Password - default: '' + port: # PostgresDB Port - default: 5432 + user: # PostgresDB User - default: root + schema: # PostgresDB Schema - default: public + ssl: + ca: # SSL certificate authority - default: '' + cert: # SSL certificate - default: '' + key: # SSL key - default: '' + rejectUnauthorized: # If unauthorized SSL connections should be rejected - default: true + mysqldb: + database: # MySQL Database - default: n8n + host: # MySQL Host - default: localhost + password: # MySQL Password - default: '' + port: # MySQL Port - default: 3306 + user: # MySQL User - default: root +credentials: + overwrite: + data: # Overwrites for credentials - default: "{}" + endpoint: # Fetch credentials from API - default: '' + +executions: + process: # In what process workflows should be executed - possible values [main, own] - default: own + timeout: # Max run time (seconds) before stopping the workflow execution - default: -1 + maxTimeout: # Max execution time (seconds) that can be set for a workflow individually - default: 3600 + saveDataOnError: # What workflow execution data to save on error - possible values [all , none] - default: all + saveDataOnSuccess: # What workflow execution data to save on success - possible values [all , none] - default: all + saveDataManualExecutions: # Save data of executions when started manually via editor - default: false + pruneData: # Delete data of past executions on a rolling basis - default: false + pruneDataMaxAge: # How old (hours) the execution data has to be to get deleted - default: 336 + pruneDataTimeout: # Timeout (seconds) after execution data has been pruned - default: 3600 +generic: + timezone: # The timezone to use - default: America/New_York +path: # Path n8n is deployed to - default: "/" +host: # Host name n8n can be reached - default: localhost +port: # HTTP port n8n can be reached - default: 5678 +listen_address: # IP address n8n should listen on - default: 0.0.0.0 +protocol: # HTTP Protocol via which n8n can be reached - possible values [http , https] - default: http +ssl_key: # SSL Key for HTTPS Protocol - default: '' +ssl_cert: # SSL Cert for HTTPS Protocol - default: '' +security: + excludeEndpoints: # Additional endpoints to exclude auth checks. Multiple endpoints can be separated by colon - default: '' + basicAuth: + active: # If basic auth should be activated for editor and REST-API - default: false + user: # The name of the basic auth user - default: '' + password: # The password of the basic auth user - default: '' + hash: # If password for basic auth is hashed - default: false + jwtAuth: + active: # If JWT auth should be activated for editor and REST-API - default: false + jwtHeader: # The request header containing a signed JWT - default: '' + jwtHeaderValuePrefix: # The request header value prefix to strip (optional) default: '' + jwksUri: # The URI to fetch JWK Set for JWT authentication - default: '' + jwtIssuer: # JWT issuer to expect (optional) - default: '' + jwtNamespace: # JWT namespace to expect (optional) - default: '' + jwtAllowedTenantKey: # JWT tenant key name to inspect within JWT namespace (optional) - default: '' + jwtAllowedTenant: # JWT tenant to allow (optional) - default: '' +endpoints: + rest: # Path for rest endpoint default: rest + webhook: # Path for webhook endpoint default: webhook + webhookTest: # Path for test-webhook endpoint default: webhook-test +externalHookFiles: # Files containing external hooks. Multiple files can be separated by colon - default: '' +nodes: + exclude: # Nodes not to load - default: "[]" + errorTriggerType: # Node Type to use as Error Trigger - default: n8n-nodes-base.errorTrigger +# the list goes on... +``` + + +### Values +The values file consits of n8n specific sections `config` and `secret` where you paste the n8n config like shown above + +```yaml +# The n8n related part of the config +config: # Dict with all n8n config options +# database: +# type: postgresdb +# postgresdb: +# database: n8n +# host: localhost +# +# existingSecret and secret are exclusive, with existingSecret taking priority. +# existingSecret: "" # Use an existing Kubernetes secret, e.g created by hand or Vault operator. +secret: # Dict with all n8n config options, unlike config the values here will end up in a secret. +# database: +# postgresdb: +# password: here_db_root_password + +## +## +## Common Kubernetes Config Settings +persistence: + ## If true, use a Persistent Volume Claim, If false, use emptyDir + ## + enabled: false + type: emptyDir # what type volume, possible options are [existing, emptyDir, dynamic] dynamic for Dynamic Volume Provisioning, existing for using an existing Claim + ## Persistent Volume Storage Class + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is + ## set, choosing the default provisioner. (gp2 on AWS, standard on + ## GKE, AWS & OpenStack) + ## + # storageClass: "-" + ## PVC annotations + # + # If you need this annotation include it under values.yml file and pvc.yml template will add it. + # This is not maintained at Helm v3 anymore. + # https://github.com/8gears/n8n-helm-chart/issues/8 + # + # annotations: + # helm.sh/resource-policy: keep + ## Persistent Volume Access Mode + ## + accessModes: + - ReadWriteOnce + ## Persistent Volume size + ## + size: 1Gi + ## Use an existing PVC + ## + # existingClaim: + +# Set additional environment variables on the Deployment +extraEnv: {} +# Set this if running behind a reverse proxy and the external port is different from the port n8n runs on +# WEBHOOK_TUNNEL_URL: "https://n8n.myhost.com/ + +replicaCount: 1 + +image: + repository: n8nio/n8n + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [ ] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: { } + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: { } + +podSecurityContext: { } +# fsGroup: 2000 + +securityContext: { } + # capabilities: + # drop: + # - ALL +# readOnlyRootFilesystem: true +# runAsNonRoot: true +# runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + annotations: {} + +ingress: + enabled: false + annotations: { } + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: [ ] + tls: [ ] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: { } + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi +# requests: +# cpu: 100m +# memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: { } + +tolerations: [ ] + +affinity: { } + +scaling: + enabled: false + + worker: + count: 2 + concurrency: 2 + + webhook: + enabled: false + count: 1 + + redis: + host: + password: + +redis: + enabled: false + # Other default redis values: https://github.com/bitnami/charts/blob/master/bitnami/redis/values.yaml +``` + +# Typical Values Example +A typical example of a config in combination with a secret. + + +```yaml +# values.yaml + +config: + database: + type: postgresdb + postgresdb: + host: 192.168.0.52 +secret: + database: + postgresdb: + password: 'big secret' + +``` +## Setup + +```shell +helm install -f values.yaml -n n8n deploymentname n8n +``` + +## Scaling + +n8n provides a **queue-mode**, where the workload is shared between multiple instances of same n8n installation. +This provide a shared load over multiple instances and a limited high availability, because the controller instance remain as Single-Point-Of-Failure. + +With the help of an internal/external redis server and by using the excelent BullMQ, the tasks can be shared over different instances, which also can run on different hosts. + +[See docs about this Queue-Mode](https://docs.n8n.io/hosting/scaling/queue-mode/) + +To enable this mode within this helm chart, you simple should set scaling.enable to true. This chart is configured to spawn by default 2 worker instances. + +```yaml +scaling: + enabled: true +``` + +You can define to spawn more worker, by set scaling.worker.count to a higher number. Also it is possible to define your own external redis server. + +```yaml +scaling: + enabled: true + redis: + host: "redis-hostname" + password: "redis-password-if-set" +``` + +If you want to use the internal redis server, set **redis.enable** to "**true**". By default no redis server is spawned. + +At last scaling option is it possible to create dedicated webhook instances, which only process the webhooks. If you set **scaling.webhook.enabled** to "true", then webhook processing on main instance is disabled and by default a single webhook instance is started. + +## Chart Deployment + + +```shell script + +helm repo add --username='robot$helmcli' --password="$PASSWD" open-8gears https://8gears.container-registry.com/chartrepo/library +helm push --username='robot$helmcli' --password="$PASSWD" . open-8gears + +``` + diff --git a/charts/n8n/charts/redis-17.2.0.tgz b/charts/n8n/charts/redis-17.2.0.tgz new file mode 100644 index 0000000..20075b9 Binary files /dev/null and b/charts/n8n/charts/redis-17.2.0.tgz differ diff --git a/charts/n8n/helmfile.yaml b/charts/n8n/helmfile.yaml new file mode 100644 index 0000000..c8cd4e3 --- /dev/null +++ b/charts/n8n/helmfile.yaml @@ -0,0 +1,30 @@ +environments: + default: + values: + - namespace: n8n-dev + - domain: "n8ndev.app.8gears.com" + - encryption_key: "iam not a secret" + - db_password: "iam not a secret" + +helmDefaults: + wait: true + timeout: 66 + +repositories: + - name: 8gears + url: https://8gears.container-registry.com/chartrepo/library + +releases: + - name: n8n + namespace: {{ .Values.namespace }} + chart: . + values: + - n8n: + encryption_key: {{ .Values.encryption_key }} + - config: + host: {{ .Values.domain }} + - persistence: + enabled: true + type: dynamic + + diff --git a/charts/n8n/templates/NOTES.txt b/charts/n8n/templates/NOTES.txt new file mode 100644 index 0000000..d8818c9 --- /dev/null +++ b/charts/n8n/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "n8n.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "n8n.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "n8n.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "n8n.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/charts/n8n/templates/_helpers.tpl b/charts/n8n/templates/_helpers.tpl new file mode 100644 index 0000000..77b0492 --- /dev/null +++ b/charts/n8n/templates/_helpers.tpl @@ -0,0 +1,141 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "n8n.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "n8n.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "n8n.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "n8n.labels" -}} +helm.sh/chart: {{ include "n8n.chart" . }} +{{ include "n8n.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "n8n.selectorLabels" -}} +app.kubernetes.io/name: {{ include "n8n.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "n8n.deploymentPodEnvironments" -}} +{{- range $key, $value := .Values.extraEnv }} +- name: {{ $key }} + value: {{ $value | quote}} +{{ end }} +{{- range $key, $value := .Values.extraEnvSecrets }} +- name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ $value.name | quote }} + key: {{ $value.key | quote }} +{{ end }} +- name: "N8N_PORT" #! we better set the port once again as ENV Var, see: https://community.n8n.io/t/default-config-is-not-set-or-the-port-to-be-more-precise/3158/3?u=vad1mo + value: {{ get .Values.config "port" | default "5678" | quote }} +{{- if .Values.n8n.encryption_key }} +- name: "N8N_ENCRYPTION_KEY" + valueFrom: + secretKeyRef: + key: N8N_ENCRYPTION_KEY + name: {{ include "n8n.fullname" . }} +{{- end }} +{{- if or .Values.config .Values.secret }} +- name: "N8N_CONFIG_FILES" + value: {{ include "n8n.configFiles" . | quote }} +{{ end }} +{{- if .Values.scaling.enabled }} +- name: "QUEUE_BULL_REDIS_HOST" + {{- if .Values.scaling.redis.host }} + value: "{{ .Values.scaling.redis.host }}" + {{ else }} + value: "{{ .Release.Name }}-redis-master" + {{ end }} +- name: "EXECUTIONS_MODE" + value: "queue" +{{ end }} +{{- if .Values.scaling.redis.password }} +- name: "QUEUE_BULL_REDIS_PASSWORD" + value: "{{ .Values.scaling.redis.password }}" +{{ end }} +{{- if .Values.scaling.webhook.enabled }} +- name: "N8N_DISABLE_PRODUCTION_MAIN_PROCESS" + value: "true" +{{ end }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "n8n.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "n8n.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* Create a list of config files for n8n */}} +{{- define "n8n.configFiles" -}} + {{- $conf_val := "" }} + {{- $sec_val := "" }} + {{- $separator := "" }} + {{- if .Values.config }} + {{- $conf_val = "/n8n-config/config.json" }} + {{- end }} + {{- if .Values.secret }} + {{- $sec_val = "/n8n-secret/secret.json" }} + {{- end }} + {{- if and .Values.config .Values.secret }} + {{- $separator = "," }} + {{- end }} + {{- print $conf_val $separator $sec_val }} +{{- end }} + + +{{/* PVC existing, emptyDir, Dynamic */}} +{{- define "n8n.pvc" -}} +{{- if or (not .Values.persistence.enabled) (eq .Values.persistence.type "emptyDir") -}} + emptyDir: {} +{{- else if and .Values.persistence.enabled .Values.persistence.existingClaim -}} + persistentVolumeClaim: + claimName: {{ .Values.persistence.existingClaim }} +{{- else if and .Values.persistence.enabled (eq .Values.persistence.type "dynamic") -}} + persistentVolumeClaim: + claimName: {{ include "n8n.fullname" . }} +{{- end }} +{{- end }} diff --git a/charts/n8n/templates/configmap.yaml b/charts/n8n/templates/configmap.yaml new file mode 100644 index 0000000..98d5102 --- /dev/null +++ b/charts/n8n/templates/configmap.yaml @@ -0,0 +1,12 @@ +{{- if .Values.config }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "n8n.fullname" . }} + labels: + {{- include "n8n.labels" . | nindent 4 }} +data: + config.json: | +{{ .Values.config | toPrettyJson | indent 4 }} + +{{- end }} diff --git a/charts/n8n/templates/deployment.webhooks.yaml b/charts/n8n/templates/deployment.webhooks.yaml new file mode 100644 index 0000000..582f53b --- /dev/null +++ b/charts/n8n/templates/deployment.webhooks.yaml @@ -0,0 +1,99 @@ +{{- if .Values.scaling.webhook.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "n8n.fullname" . }}-webhook + labels: + {{- include "n8n.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.scaling.webhook.count }} + {{- end }} + strategy: + type: {{ .Values.deploymentStrategy.type }} + selector: + matchLabels: + {{- include "n8n.selectorLabels" . | nindent 6 }} + app.kubernetes.io/type: webhooks + template: + metadata: + annotations: + checksum/config: {{ print .Values | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "n8n.selectorLabels" . | nindent 8 }} + app.kubernetes.io/type: webhooks + {{- if .Values.podLabels }} + {{ toYaml .Values.podLabels | nindent 8 }} + {{- end }} + + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "n8n.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- if .Values.initContainers }} + initContainers: + {{ tpl (toYaml .Values.initContainers) . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ["n8n"] + args: ["webhook"] + env: + {{- include "n8n.deploymentPodEnvironments" . | nindent 12 }} + ports: + - name: http + containerPort: {{ get .Values.config "port" | default 5678 }} + protocol: TCP + resources: + {{- toYaml .Values.webhookResources | nindent 12 }} + volumeMounts: + - name: data + mountPath: {{ if semverCompare ">=1.0" .Values.image.tag | default .Chart.AppVersion }}/home/node/.n8n{{ else }}/root/.n8n{{ end }} + {{- if .Values.config }} + - name: config-volume + mountPath: /n8n-config + {{- end }} + {{- if .Values.secret }} + - name: secret-volume + mountPath: /n8n-secret + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: "data" + {{ include "n8n.pvc" . }} + {{- if .Values.config }} + - name: config-volume + configMap: + name: {{ include "n8n.fullname" . }} + {{- end }} + {{- if or (.Values.secret) (.Values.existingSecret) }} + - name: secret-volume + secret: + secretName: {{ if .Values.existingSecret }}{{ .Values.existingSecret }}{{ else }}{{ include "n8n.fullname" . }}{{ end }} + items: + - key: "secret.json" + path: "secret.json" + {{- end }} +{{- end }} diff --git a/charts/n8n/templates/deployment.worker.yaml b/charts/n8n/templates/deployment.worker.yaml new file mode 100644 index 0000000..f13bc02 --- /dev/null +++ b/charts/n8n/templates/deployment.worker.yaml @@ -0,0 +1,99 @@ +{{- if .Values.scaling.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "n8n.fullname" . }}-worker + labels: + {{- include "n8n.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.scaling.worker.count }} + {{- end }} + strategy: + type: {{ .Values.deploymentStrategy.type }} + selector: + matchLabels: + {{- include "n8n.selectorLabels" . | nindent 6 }} + app.kubernetes.io/type: worker + template: + metadata: + annotations: + checksum/config: {{ print .Values | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "n8n.selectorLabels" . | nindent 8 }} + app.kubernetes.io/type: worker + {{- if .Values.podLabels }} + {{ toYaml .Values.podLabels | nindent 8 }} + {{- end }} + + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "n8n.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- if .Values.initContainers }} + initContainers: + {{ tpl (toYaml .Values.initContainers) . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ["n8n"] + args: ["worker", "--concurrency={{ .Values.scaling.worker.concurrency }}"] + env: + {{- include "n8n.deploymentPodEnvironments" . | nindent 12 }} + ports: + - name: http + containerPort: {{ get .Values.config "port" | default 5678 }} + protocol: TCP + resources: + {{- toYaml .Values.workerResources | nindent 12 }} + volumeMounts: + - name: data + mountPath: {{ if semverCompare ">=1.0" .Values.image.tag | default .Chart.AppVersion }}/home/node/.n8n{{ else }}/root/.n8n{{ end }} + {{- if .Values.config }} + - name: config-volume + mountPath: /n8n-config + {{- end }} + {{- if .Values.secret }} + - name: secret-volume + mountPath: /n8n-secret + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: "data" + {{ include "n8n.pvc" . }} + {{- if .Values.config }} + - name: config-volume + configMap: + name: {{ include "n8n.fullname" . }} + {{- end }} + {{- if or (.Values.secret) (.Values.existingSecret) }} + - name: secret-volume + secret: + secretName: {{ if .Values.existingSecret }}{{ .Values.existingSecret }}{{ else }}{{ include "n8n.fullname" . }}{{ end }} + items: + - key: "secret.json" + path: "secret.json" + {{- end }} + {{- end }} diff --git a/charts/n8n/templates/deployment.yaml b/charts/n8n/templates/deployment.yaml new file mode 100644 index 0000000..f955536 --- /dev/null +++ b/charts/n8n/templates/deployment.yaml @@ -0,0 +1,109 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "n8n.fullname" . }} + labels: + {{- include "n8n.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + strategy: + type: {{ .Values.deploymentStrategy.type }} + selector: + matchLabels: + {{- include "n8n.selectorLabels" . | nindent 6 }} + app.kubernetes.io/type: master + template: + metadata: + annotations: + checksum/config: {{ print .Values | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "n8n.selectorLabels" . | nindent 8 }} + app.kubernetes.io/type: master + {{- if .Values.podLabels }} + {{ toYaml .Values.podLabels | nindent 8 }} + {{- end }} + + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "n8n.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- if .Values.initContainers }} + initContainers: + {{ tpl (toYaml .Values.initContainers) . | nindent 8 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{- with .Values.command }} + command: + {{- toYaml . | nindent 12 }} + {{- end }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + {{- include "n8n.deploymentPodEnvironments" . | nindent 12 }} + lifecycle: + {{- toYaml .Values.lifecycle | nindent 12 }} + ports: + - name: http + containerPort: {{ get .Values.config "port" | default 5678 }} + protocol: TCP + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: data + mountPath: {{ if semverCompare ">=1.0" .Values.image.tag | default .Chart.AppVersion }}/home/node/.n8n{{ else }}/root/.n8n{{ end }} + {{- if .Values.config }} + - name: config-volume + mountPath: /n8n-config + {{- end }} + {{- if .Values.secret }} + - name: secret-volume + mountPath: /n8n-secret + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: "data" + {{ include "n8n.pvc" . }} + {{- if .Values.config }} + - name: config-volume + configMap: + name: {{ include "n8n.fullname" . }} + {{- end }} + {{- if or (.Values.secret) (.Values.existingSecret) }} + - name: secret-volume + secret: + secretName: {{ if .Values.existingSecret }}{{ .Values.existingSecret }}{{ else }}{{ include "n8n.fullname" . }}{{ end }} + items: + - key: "secret.json" + path: "secret.json" + {{- end }} diff --git a/charts/n8n/templates/hpa.yaml b/charts/n8n/templates/hpa.yaml new file mode 100644 index 0000000..df58416 --- /dev/null +++ b/charts/n8n/templates/hpa.yaml @@ -0,0 +1,51 @@ +{{- if .Values.autoscaling.enabled }} +{{- if semverCompare ">=1.25-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: autoscaling/v2 +{{- else -}} +apiVersion: autoscaling/v2beta1 +{{- end }} +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "n8n.fullname" . }} + labels: + {{- include "n8n.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "n8n.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: +{{- if semverCompare ">=1.25-0" .Capabilities.KubeVersion.GitVersion -}} + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- else -}} + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/n8n/templates/ingress.yaml b/charts/n8n/templates/ingress.yaml new file mode 100644 index 0000000..883b1ca --- /dev/null +++ b/charts/n8n/templates/ingress.yaml @@ -0,0 +1,66 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "n8n.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} + +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "n8n.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + {{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }} + pathType: Prefix + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- if $.Values.scaling.webhook.enabled }} + - path: {{ . }}webhook/ + pathType: Prefix + backend: + service: + name: {{ $fullName }}-webhooks + port: + number: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} diff --git a/charts/n8n/templates/pvc.yaml b/charts/n8n/templates/pvc.yaml new file mode 100644 index 0000000..aec7bbc --- /dev/null +++ b/charts/n8n/templates/pvc.yaml @@ -0,0 +1,29 @@ +{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "n8n.fullname" . }} + {{- with .Values.persistence.annotations }} + annotations: + {{- range $key, $value := . }} + {{ $key }}: {{ $value }} + {{- end }} + {{- end }} + labels: + {{- include "n8n.labels" . | nindent 4 }} +spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size }} + {{- if .Values.persistence.storageClass }} + {{- if eq "-" .Values.persistence.storageClass }} + storageClassName: "" + {{- else }} + storageClassName: {{ .Values.persistence.storageClass }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/n8n/templates/secret.yaml b/charts/n8n/templates/secret.yaml new file mode 100644 index 0000000..1a5520e --- /dev/null +++ b/charts/n8n/templates/secret.yaml @@ -0,0 +1,14 @@ +{{- if or .Values.secret .Values.n8n.encryption_key }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "n8n.fullname" . }} + labels: + {{- include "n8n.labels" . | nindent 4 }} +data: + secret.json: {{ .Values.secret | toPrettyJson | b64enc }} + {{- if .Values.n8n.encryption_key }} + N8N_ENCRYPTION_KEY: {{ .Values.n8n.encryption_key | b64enc }} + {{- end }} + +{{- end }} diff --git a/charts/n8n/templates/service.webhooks.yaml b/charts/n8n/templates/service.webhooks.yaml new file mode 100644 index 0000000..8579651 --- /dev/null +++ b/charts/n8n/templates/service.webhooks.yaml @@ -0,0 +1,22 @@ +{{- if .Values.scaling.webhook.enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "n8n.fullname" . }}-webhooks + labels: + {{- include "n8n.labels" . | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "n8n.selectorLabels" . | nindent 4 }} + app.kubernetes.io/type: webhooks +{{- end }} diff --git a/charts/n8n/templates/service.yaml b/charts/n8n/templates/service.yaml new file mode 100644 index 0000000..239642d --- /dev/null +++ b/charts/n8n/templates/service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "n8n.fullname" . }} + labels: + {{- include "n8n.labels" . | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "n8n.selectorLabels" . | nindent 4 }} + app.kubernetes.io/type: master diff --git a/charts/n8n/templates/serviceaccount.yaml b/charts/n8n/templates/serviceaccount.yaml new file mode 100644 index 0000000..5c629a4 --- /dev/null +++ b/charts/n8n/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "n8n.serviceAccountName" . }} + labels: + {{- include "n8n.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/n8n/templates/tests/test-connection.yaml b/charts/n8n/templates/tests/test-connection.yaml new file mode 100644 index 0000000..5dbe7df --- /dev/null +++ b/charts/n8n/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "n8n.fullname" . }}-test-connection" + labels: + {{- include "n8n.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "n8n.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/charts/n8n/values.yaml b/charts/n8n/values.yaml new file mode 100644 index 0000000..e01a5e6 --- /dev/null +++ b/charts/n8n/values.yaml @@ -0,0 +1,326 @@ +# Default helm values for n8n. +# Default values within the n8n application can be found under https://github.com/n8n-io/n8n/blob/master/packages/cli/config/index.ts +n8n: + encryption_key: # n8n creates a random encryption key automatically on the first launch and saves it in the ~/.n8n folder. That key is used to encrypt the credentials before they get saved to the database. +defaults: + +config: + executions: + pruneData: "true" # prune executions by default + pruneDataMaxAge: 3760 # Per defaut we store 1 year of history + +# existingSecret and secret are exclusive, with existingSecret taking priority. +# existingSecret: "" # Use an existing Kubernetes secret, e.g created by hand or Vault operator. +secret: # Dict with all n8n json config options, unlike config the values here will end up in a secret. + +# Typical Example of a config in combination with a secret. +# config: +# database: +# type: postgresdb +# postgresdb: +# host: 192.168.0.52 +# secret: +# database: +# postgresdb: +# password: 'big secret' + +## ALL possible n8n Values + +# +#database: +# type: # Type of database to use - Other possible types ['sqlite', 'mariadb', 'mysqldb', 'postgresdb'] - default: sqlite +# tablePrefix: # Prefix for table names - default: '' +# postgresdb: +# database: # PostgresDB Database - default: n8n +# host: # PostgresDB Host - default: localhost +# password: # PostgresDB Password - default: '' +# port: # PostgresDB Port - default: 5432 +# user: # PostgresDB User - default: root +# schema: # PostgresDB Schema - default: public +# ssl: +# ca: # SSL certificate authority - default: '' +# cert: # SSL certificate - default: '' +# key: # SSL key - default: '' +# rejectUnauthorized: # If unauthorized SSL connections should be rejected - default: true +# mysqldb: +# database: # MySQL Database - default: n8n +# host: # MySQL Host - default: localhost +# password: # MySQL Password - default: '' +# port: # MySQL Port - default: 3306 +# user: # MySQL User - default: root +#credentials: +# overwrite: +# data: # Overwrites for credentials - default: "{}" +# endpoint: # Fetch credentials from API - default: '' +# +#executions: +# process: # In what process workflows should be executed - possible values [main, own] - default: own +# timeout: # Max run time (seconds) before stopping the workflow execution - default: -1 +# maxTimeout: # Max execution time (seconds) that can be set for a workflow individually - default: 3600 +# saveDataOnError: # What workflow execution data to save on error - possible values [all , none] - default: all +# saveDataOnSuccess: # What workflow execution data to save on success - possible values [all , none] - default: all +# saveDataManualExecutions: # Save data of executions when started manually via editor - default: false +# pruneData: # Delete data of past executions on a rolling basis - default: false +# pruneDataMaxAge: # How old (hours) the execution data has to be to get deleted - default: 336 +# pruneDataTimeout: # Timeout (seconds) after execution data has been pruned - default: 3600 +#generic: +# timezone: # The timezone to use - default: America/New_York +#path: # Path n8n is deployed to - default: "/" +#host: # Host name n8n can be reached - default: localhost +#port: # HTTP port n8n can be reached - default: 5678 +#listen_address: # IP address n8n should listen on - default: 0.0.0.0 +#protocol: # HTTP Protocol via which n8n can be reached - possible values [http , https] - default: http +#ssl_key: # SSL Key for HTTPS Protocol - default: '' +#ssl_cert: # SSL Cert for HTTPS Protocol - default: '' +#security: +# excludeEndpoints: # Additional endpoints to exclude auth checks. Multiple endpoints can be separated by colon - default: '' +# basicAuth: +# active: # If basic auth should be activated for editor and REST-API - default: false +# user: # The name of the basic auth user - default: '' +# password: # The password of the basic auth user - default: '' +# hash: # If password for basic auth is hashed - default: false +# jwtAuth: +# active: # If JWT auth should be activated for editor and REST-API - default: false +# jwtHeader: # The request header containing a signed JWT - default: '' +# jwtHeaderValuePrefix: # The request header value prefix to strip (optional) default: '' +# jwksUri: # The URI to fetch JWK Set for JWT authentication - default: '' +# jwtIssuer: # JWT issuer to expect (optional) - default: '' +# jwtNamespace: # JWT namespace to expect (optional) - default: '' +# jwtAllowedTenantKey: # JWT tenant key name to inspect within JWT namespace (optional) - default: '' +# jwtAllowedTenant: # JWT tenant to allow (optional) - default: '' +#endpoints: +# rest: # Path for rest endpoint default: rest +# webhook: # Path for webhook endpoint default: webhook +# webhookTest: # Path for test-webhook endpoint default: webhook-test +#externalHookFiles: # Files containing external hooks. Multiple files can be separated by colon - default: '' +#nodes: +# exclude: # Nodes not to load - default: "[]" +# errorTriggerType: # Node Type to use as Error Trigger - default: n8n-nodes-base.errorTrigger + +# Set additional environment variables on the Deployment +extraEnv: {} +# Set this if running behind a reverse proxy and the external port is different from the port n8n runs on +# WEBHOOK_TUNNEL_URL: "https://n8n.myhost.com/ + +# Set additional environment from existing secrets +extraEnvSecrets: {} +# for example, to reuse existing postgres authentication secrets: +# DB_POSTGRESDB_USER: +# name: postgres-user-auth +# key: username +# DB_POSTGRESDB_PASSWORD: +# name: postgres-user-auth +# key: password + +## +## +## +## +## Common Kubernetes Config Settings +persistence: + ## If true, use a Persistent Volume Claim, If false, use emptyDir + ## + enabled: false + type: emptyDir # what type volume, possible options are [existing, emptyDir, dynamic] dynamic for Dynamic Volume Provisioning, existing for using an existing Claim + ## Persistent Volume Storage Class + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is + ## set, choosing the default provisioner. (gp2 on AWS, standard on + ## GKE, AWS & OpenStack) + ## + # storageClass: "-" + ## PVC annotations + # + # If you need this annotation include it under values.yml file and pvc.yml template will add it. + # This is not maintained at Helm v3 anymore. + # https://github.com/8gears/n8n-helm-chart/issues/8 + # + # annotations: + # helm.sh/resource-policy: keep + ## Persistent Volume Access Mode + ## + accessModes: + - ReadWriteOnce + ## Persistent Volume size + ## + size: 1Gi + ## Use an existing PVC + ## + # existingClaim: + +replicaCount: 1 + +deploymentStrategy: + type: "Recreate" + +image: + repository: n8nio/n8n + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podLabels: {} + +podSecurityContext: {} +# fsGroup: 2000 + +securityContext: + {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true +# runAsNonRoot: true +# runAsUser: 1000 + +# here you can specify lifecycle hooks - it can be used e.g to easily add packages to the container without building +# your own docker image +# see https://github.com/8gears/n8n-helm-chart/pull/30 +lifecycle: + {} + +# here's the sample configuration to add mysql-client to the container +#lifecycle: +# postStart: +# exec: +# command: ["/bin/sh", "-c", "apk add mysql-client"] + +# here you can override a command for main container +# it may be used to override starting script (e.g. to resolve issues like https://github.com/n8n-io/n8n/issues/6412) or +# run additional preparation steps (e.g. installing additional software) +command: [] + +# sample configuration that overrides starting script and solves above issue (also it runs n8n as root, so be careful): +#command: +# - tini +# - -- +# - /bin/sh +# - -c +# - chmod o+rx /root; chown -R node /root/.n8n || true; chown -R node /root/.n8n; ln -s /root/.n8n /home/node; chown -R node /home/node || true; node /usr/local/bin/n8n + +# here you can override the livenessProbe for the main container +# it may be used to increase the timeout for the livenessProbe (e.g. to resolve issues like + +livenessProbe: + httpGet: + path: /healthz + port: http + # initialDelaySeconds: 30 + # periodSeconds: 10 + # timeoutSeconds: 5 + # failureThreshold: 6 + # successThreshold: 1 + +# here you can override the readinessProbe for the main container +# it may be used to increase the timeout for the readinessProbe (e.g. to resolve issues like + +readinessProbe: + httpGet: + path: /healthz + port: http + # initialDelaySeconds: 30 + # periodSeconds: 10 + # timeoutSeconds: 5 + # failureThreshold: 6 + # successThreshold: 1 + +# here you can add init containers to the various deployments +initContainers: [] + +service: + type: ClusterIP + port: 80 + annotations: {} + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: [] + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + + # define a custom incressClassName, like "traefik" or "nginx" + className: "" + +workerResources: + {} + +webhookResources: + {} + +resources: + {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: +# cpu: 100m +# memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +scaling: + enabled: false + + worker: + count: 2 + concurrency: 2 + # With .Values.scaling.webhook.enabled=true you disable Webhooks from the main process but you enable the processing on a different Webhook instance. + # See https://github.com/8gears/n8n-helm-chart/issues/39#issuecomment-1579991754 for the full explanation. + webhook: + enabled: false + count: 1 + + redis: + host: + password: + + +## Bitnami Redis configuration +## https://github.com/bitnami/charts/tree/master/bitnami/redis +redis: + enabled: false + architecture: standalone + + master: + persistence: + enabled: true + existingClaim: "" + size: 2Gi