|
| 1 | +# Helm Chart E2E Testing |
| 2 | + |
| 3 | +Test n8n Helm chart deployments using K3s (lightweight Kubernetes) inside Docker, powered by `@testcontainers/k3s`. |
| 4 | + |
| 5 | +## Prerequisites |
| 6 | + |
| 7 | +### Required |
| 8 | + |
| 9 | +- **Docker Desktop** (macOS/Windows) or **Docker Engine** (Linux) |
| 10 | +- **Privileged container support** — K3s runs as a privileged container |
| 11 | +- **helm** CLI — runs on your host machine ([install](https://helm.sh/docs/intro/install/)) |
| 12 | +- **kubectl** CLI — runs on your host machine ([install](https://kubernetes.io/docs/tasks/tools/)) |
| 13 | +- **n8n Docker image** — built locally (`pnpm build:docker`) or pulled from Docker Hub |
| 14 | + |
| 15 | +### Not Required |
| 16 | + |
| 17 | +- Kind, Minikube, or any other K8s distribution |
| 18 | +- Kubernetes cluster access |
| 19 | +- Any K8s tooling beyond helm + kubectl |
| 20 | + |
| 21 | +### Privileged Container Compatibility |
| 22 | + |
| 23 | +| Environment | Supported | Notes | |
| 24 | +|---|---|---| |
| 25 | +| Docker Desktop (macOS/Windows) | Yes | Privileged enabled by default | |
| 26 | +| Docker Engine (Linux) | Yes | Standard daemon supports it | |
| 27 | +| GitHub Actions (ubuntu runners) | Yes | Docker socket available | |
| 28 | +| Blacksmith runners | Yes | Standard Docker-capable VMs | |
| 29 | +| Rootless Docker | **No** | K3s requires privileged mode | |
| 30 | +| Docker-in-Docker | Depends | Outer container needs `--privileged` | |
| 31 | +| Podman | **No** | K3s requires Docker-compatible runtime | |
| 32 | + |
| 33 | +## How It Works |
| 34 | + |
| 35 | +``` |
| 36 | +Host Machine (helm, kubectl) |
| 37 | +├── KUBECONFIG=/tmp/helm-kubeconfig-*.yaml |
| 38 | +└── Docker |
| 39 | + └── K3s Container (privileged, NodePort 30080 → host random port) |
| 40 | + ├── containerd (K3s runtime) |
| 41 | + │ └── n8n image (preloaded from host Docker) |
| 42 | + └── Kubernetes control plane |
| 43 | + ├── n8n Pod (Helm-deployed) |
| 44 | + └── Service (NodePort 30080 → Pod 5678) |
| 45 | +
|
| 46 | +Playwright ──── http://localhost:<host-port> ──→ NodePort ──→ n8n Pod |
| 47 | +``` |
| 48 | + |
| 49 | +1. `@testcontainers/k3s` starts K3s inside a Docker container with NodePort 30080 exposed |
| 50 | +2. The n8n Docker image is exported from host Docker and imported into K3s's containerd |
| 51 | +3. Host `helm` installs the n8n chart using a kubeconfig pointing at the K3s API |
| 52 | +4. The n8n service is patched to NodePort, routing traffic through K3s's exposed port |
| 53 | +5. Playwright tests connect via `N8N_BASE_URL=http://localhost:<host-port>` |
| 54 | + |
| 55 | +## Local Usage |
| 56 | + |
| 57 | +```bash |
| 58 | +# 1. Build the n8n Docker image (or use a Docker Hub image) |
| 59 | +pnpm build:docker |
| 60 | + |
| 61 | +# 2. Start the Helm stack (takes ~60-120s) |
| 62 | +cd packages/testing/containers |
| 63 | +pnpm stack:helm |
| 64 | + |
| 65 | +# 3. In another terminal, use the printed KUBECONFIG for debugging |
| 66 | +export KUBECONFIG=/tmp/helm-kubeconfig-*.yaml |
| 67 | +kubectl get pods |
| 68 | +kubectl logs -l app.kubernetes.io/name=n8n |
| 69 | + |
| 70 | +# 4. Run tests |
| 71 | +N8N_BASE_URL=http://localhost:<port> RESET_E2E_DB=true \ |
| 72 | + npx playwright test tests/e2e/building-blocks/ --workers=1 |
| 73 | + |
| 74 | +# 5. Cleanup |
| 75 | +pnpm stack:helm:clean |
| 76 | +``` |
| 77 | + |
| 78 | +### Test a Specific Version Matrix |
| 79 | + |
| 80 | +```bash |
| 81 | +# Test n8n 1.80.0 against chart version v1.2.0 |
| 82 | +pnpm stack:helm --image n8nio/n8n:1.80.0 --chart-ref v1.2.0 |
| 83 | + |
| 84 | +# Test latest n8n against a chart PR branch |
| 85 | +pnpm stack:helm --chart-ref fix/pvc-permissions |
| 86 | + |
| 87 | +# Test a GHCR image (e.g., from CI) |
| 88 | +pnpm stack:helm --image ghcr.io/n8n-io/n8n:ci-12345 |
| 89 | +``` |
| 90 | + |
| 91 | +### CLI Options |
| 92 | + |
| 93 | +``` |
| 94 | +--mode <mode> standalone (SQLite, default) or queue (PostgreSQL + Redis + workers) |
| 95 | +--image <image> n8n Docker image (default: n8nio/n8n:local) |
| 96 | +--chart-ref <ref> Git branch/tag for n8n-hosting (default: main) |
| 97 | +--chart-repo <url> Git repo URL (default: https://github.com/n8n-io/n8n-hosting.git) |
| 98 | +--k3s-image <image> K3s image (default: rancher/k3s:v1.32.2-k3s1) |
| 99 | +--url-file <path> Write URL to file when ready (for CI automation) |
| 100 | +--help Show help |
| 101 | +``` |
| 102 | + |
| 103 | +## CI Usage |
| 104 | + |
| 105 | +The `test-e2e-helm.yml` workflow handles everything: |
| 106 | + |
| 107 | +- **Trigger:** Push to `helm-container-test` branch, or manual dispatch |
| 108 | +- **Build:** Creates n8n Docker image, pushes to GHCR |
| 109 | +- **Test:** Starts K3s, installs Helm chart, runs building-blocks E2E tests |
| 110 | +- **Cleanup:** Removes ephemeral GHCR image |
| 111 | + |
| 112 | +Manual dispatch also accepts `helm-chart-ref` to test a specific chart version. |
| 113 | + |
| 114 | +## Troubleshooting |
| 115 | + |
| 116 | +### K3s won't start |
| 117 | + |
| 118 | +Check that Docker supports privileged containers: |
| 119 | +```bash |
| 120 | +docker run --rm --privileged alpine echo "privileged works" |
| 121 | +``` |
| 122 | + |
| 123 | +### Image not found in K3s |
| 124 | + |
| 125 | +Ensure the n8n Docker image exists locally: |
| 126 | +```bash |
| 127 | +docker images | grep n8nio/n8n |
| 128 | +``` |
| 129 | + |
| 130 | +If empty, run `pnpm build:docker` first. |
| 131 | + |
| 132 | +### Helm install times out |
| 133 | + |
| 134 | +Use kubectl to inspect the cluster: |
| 135 | +```bash |
| 136 | +export KUBECONFIG=/tmp/helm-kubeconfig-*.yaml |
| 137 | +kubectl get pods -o wide |
| 138 | +kubectl describe pod -l app.kubernetes.io/name=n8n |
| 139 | +kubectl get events --sort-by=.lastTimestamp |
| 140 | +``` |
| 141 | + |
| 142 | +### Port not accessible |
| 143 | + |
| 144 | +NodePort routing is stateless (kube-proxy), so connectivity issues typically indicate the pod is unhealthy. Check pod status: |
| 145 | +```bash |
| 146 | +export KUBECONFIG=/tmp/helm-kubeconfig-*.yaml |
| 147 | +kubectl get pods -o wide |
| 148 | +kubectl describe pod -l app.kubernetes.io/name=n8n |
| 149 | +kubectl version --client |
| 150 | +helm version |
| 151 | +``` |
| 152 | + |
| 153 | +### Slow startup |
| 154 | + |
| 155 | +First run is slower due to K3s image pull. Typical timings: |
| 156 | + |
| 157 | +| Phase | First Run | Subsequent | |
| 158 | +|---|---|---| |
| 159 | +| K3s start | ~15-30s | ~5s (reuse) | |
| 160 | +| Image preload | ~10-20s | ~10-20s | |
| 161 | +| Helm install | ~5-10s | ~5-10s | |
| 162 | +| n8n boot | ~15-30s | ~15-30s | |
| 163 | +| **Total** | **~60-120s** | **~40-80s** | |
| 164 | + |
| 165 | +## Comparison: Testcontainers vs K3s + Helm |
| 166 | + |
| 167 | +| | Testcontainers (Stream 1) | K3s + Helm (Stream 2) | |
| 168 | +|---|---|---| |
| 169 | +| **Purpose** | Feature testing | Deployment validation | |
| 170 | +| **Speed** | 5-15s startup | 60-120s startup | |
| 171 | +| **K8s features** | None | PVC, RBAC, securityContext, NetworkPolicy | |
| 172 | +| **Custom services** | Kafka, Mailpit, OIDC, etc. | Only what the Helm chart defines | |
| 173 | +| **What it proves** | "n8n works with X" | "this chart config deploys correctly" | |
| 174 | +| **When to run** | Every PR | On demand, nightly, pre-release | |
| 175 | +| **Prerequisites** | Docker | Docker + helm + kubectl | |
0 commit comments