Ingress Controller Migration

This guide should not be treated as a one-size-fits-all solution. Consider it as a blueprint and adapt it to your specific Kubernetes cluster setup. Test the migration in a testing/staging environment before applying it to production.

If you have any questions about the migration, please contact support@flowfuse.com.

This document describes how to migrate a FlowFuse Platform Kubernetes deployment from the NGINX Ingress Controller to Traefik.

The main reason for this migration is the retirement of Ingress NGINX by the Kubernetes project due to long-term maintenance and security sustainability challenges. Best-effort maintenance continues only until March 2026, after which there will be no further releases, bug fixes, or security updates.

It describes a DNS-based migration approach where the actual traffic switch happens at the domain level by changing DNS records to point to the new ingress controller. It is based on the FlowFuse Ingress Migration Tool and using the ingress classes separation capability provided by the FlowFuse Helm chart:

  • Hosted Instances (project ingresses) via forge.projectIngressClassName
  • Core application components via ingress.className

That separation allows you to migrate project traffic and core application traffic in stages.

Prerequisites

Before you begin, ensure you have the following:

  1. A working FlowFuse deployment installed with the flowfuse/flowfuse Helm chart
    • note down the FlowFuse Platform Helm release name and namespace, guide uses <flowfuse-release-name> and <flowfuse-release-namespace> placeholders for these values.
  2. Access to the Helm values file used for your deployment
    • note down the path to the values file, guide uses <flowfuse-values-file> placeholder as a reference
  3. kubectl and helm configured for the target cluster
  4. A new Traefik ingress controller installed alongside the existing NGINX ingress controller. Check our ingress installation guide for instructions on how to do this.
  5. Access to the DNS records for:
    • the FlowFuse application domain
    • the wildcard domain used by Hosted Instances
  6. A maintenance window

We also recommend the following before starting the migration:

  • Reduce DNS TTL values in advance to minimize propagation delay
  • Do not create new Hosted Instances during the migration window
  • Test the procedure in a non-production cluster first

Important notes

The FlowFuse Helm chart provides an ingress migration job controlled by the ingressMigration values block.

The migration job operates on:

  • the project namespace (forge.projectNamespace)
  • the release namespace, but only in copy mode

This guide therefore separates the process into two phases:

  1. Copy existing ingress resources to the new ingress class
  2. Clean up old ingress resources after traffic has moved

Step 1: Install Traefik alongside NGINX

Install Traefik without removing the existing NGINX ingress controller. Check our ingress installation guide for instructions on how to do this.

Before continuing, verify that both ingress controllers are running. Also, write down the ingress class name used by Traefik, as you will need it for the migration configuration:

kubectl get ingressclass

Step 2: Record the Traefik LoadBalancer address

You will need the public address of the new ingress controller before changing DNS.

For example, list services in the Traefik namespace:

kubectl get svc -n traefik

Record the external hostname or IP address of the Traefik LoadBalancer service.

Step 3: Run the migration job in dry-run mode

Start by enabling the migration tool in copy mode with dryRun: true.

Update your values file:

ingressMigration:
enabled: true
mode: copy
dryRun: true
newIngressClassName: traefik
nameSuffix: -tfk

Then run the Helm upgrade:

helm upgrade --install <flowfuse-release-name> flowfuse/flowfuse -n <flowfuse-release-namespace> -f <flowfuse-values-file>

After the upgrade completes, inspect the Job created by the chart in the release namespace. The Job name is generated by Helm, so first list the Jobs:

kubectl get jobs -n <flowfuse-release-namespace>

Then inspect the logs of the migration job:

kubectl logs -n <flowfuse-release-namespace> job/<migration-job-name>

Verify that the dry run identifies all Ingress resources.

Step 4: Optionally scale down Traefik before copying resources

If your environment allows it, and especially if you have many ingress resources, you can temporarily scale Traefik down before executing the ingress resources copy step.

This is optional, but it can reduce repeated Traefik configuration reloads during the migration.

Example:

kubectl -n traefik scale deployment traefik --replicas 0

Only do this if your Kubernetes cluster hosts the FlowFuse Platform and stopping Traefik will not cause a downtime for other applications.

Step 5: Copy ingress resources to the new ingress class

Once the dry run has been validated, disable dry-run mode and run the actual ingress resources copy.

Update your values file:

ingressMigration:
enabled: true
mode: copy
dryRun: false
newIngressClassName: traefik
nameSuffix: -tfk

Run the Helm upgrade again:

helm upgrade --install <flowfuse-release-name> flowfuse/flowfuse -n <flowfuse-release-namespace> -f <flowfuse-values-file>

This creates new Ingress resources that point to the new ingress class and use the configured suffix.

Step 6: Scale Traefik back up

If you scaled Traefik down in step 4, scale it back up now.

Example:

kubectl -n traefik scale deployment traefik --replicas 2

Use the replica count that matches your environment.

Step 7: Change DNS to point to Traefik

Update the DNS records used by the FlowFuse Platform so that incoming traffic is sent to the Traefik LoadBalancer address recorded earlier.

This includes:

  • the FlowFuse application hostname (e.g. forge.example.com)
  • the wildcard DNS record used by Hosted Instances (e.g. *.example.com)

Do not proceed to cleanup until you have confirmed that DNS is resolving to the new ingress controller.

Step 8: Make new Hosted Instances use Traefik

After the copied ingress resources are in place, update the project ingress class so that newly created Hosted Instances use Traefik.

Add or update the following value in the FlowFuse Helm values file:

forge:
projectIngressClassName: traefik

Apply the change:

helm upgrade --install <flowfuse-release-name> flowfuse/flowfuse -n <flowfuse-release-namespace> -f <flowfuse-values-file>

Step 9: Wait for DNS propagation and validate traffic

Allow time for DNS propagation according to your TTL settings.

During this period, validate the migration by checking:

  • the FlowFuse Platform is reachable
  • Hosted Instances are reachable
  • TLS certificates are served correctly
  • Traefik logs and metrics do not show routing errors
  • Ingress NGINX logs do not show incoming traffic

Do not continue to cleanup until traffic is consistently served by Traefik. Otherwise, you risk potential downtime of the FlowFuse Platform and Hosted Instances.

Step 10: Move core application components to Traefik

Once you are confident that the Traefik ingress controller is handling all the incoming traffic, update the ingress class used by the core application components.

Add or update the following value in the FlowFuse Helm values file:

ingress:
className: traefik

Apply the change:

helm upgrade --install <flowfuse-release-name> flowfuse/flowfuse -n <flowfuse-release-namespace> -f <flowfuse-values-file>

Step 11: Optionally scale down NGINX

If the NGINX ingress controller is still used for resources outside FlowFuse, leave it in place.

If it is no longer needed, you can scale it down after you have confirmed that FlowFuse Platform traffic is fully handled by Traefik.

Example:

kubectl -n <nginx-namespace> scale deployment <nginx-deployment> --replicas 0

If your Ingress-Nginx installation created admission webhooks and you are about to retire that controller entirely soon, remove those webhook resources.

Examples:

kubectl delete validatingwebhookconfiguration <nginx-validating-webhook-name>
kubectl delete mutatingwebhookconfiguration <nginx-mutating-webhook-name> --ignore-not-found

Step 12: Clean up old ingress resources

After traffic has fully moved to Traefik, switch the migration tool to cleanup mode.

In this mode, the tool removes old ingress resources and renames the migrated ones back to their original names. This step can cause a short interruption while Kubernetes updates the resources.

Update your values file:

ingressMigration:
enabled: true
mode: cleanup
dryRun: false
oldIngressClassName: nginx
newIngressClassName: traefik
nameSuffix: -tfk

Run the Helm upgrade again:

helm upgrade --install <flowfuse-release-name> flowfuse/flowfuse -n <flowfuse-release-namespace> -f <flowfuse-values-file>

If you want to validate the cleanup plan first, run the same configuration with dryRun: true before applying it.

Step 13: Remove any remaining suffixed ingress resources from the release namespace

The migration job in copy mode creates new ingress resources with a suffix in the release namespace. In cleanup mode, the job deletes old ingress resources and renames the new ones to match the original names, but it does not remove the suffixed copies from the release namespace. This is to avoid any potential issues with the release namespace if it contains non-ingress resources or custom configurations. Because of that, after cleanup you should inspect the release namespace and remove any remaining suffixed ingress resources that were copied there.

List ingress resources in the release namespace:

kubectl get ingress -n <flowfuse-release-namespace>

If any copied ingress resources with the migration suffix still exist (-tfk), delete them manually:

kubectl delete ingress <ingress-name> -n <flowfuse-release-namespace>

Step 14: Disable the migration job

After the migration and cleanup are complete, disable the migration tool:

ingressMigration:
enabled: false

Apply the change one final time:

helm upgrade --install <flowfuse-release-name> flowfuse/flowfuse -n <flowfuse-release-namespace> -f <flowfuse-values-file>

This guide uses the following FlowFuse Helm chart values:

  • ingress.className
  • forge.projectIngressClassName
  • ingressMigration.enabled
  • ingressMigration.mode
  • ingressMigration.dryRun
  • ingressMigration.newIngressClassName
  • ingressMigration.oldIngressClassName
  • ingressMigration.nameSuffix

For the full list of ingress migration options, refer to the FlowFuse Helm chart README.

Need help?

If you would like guidance on planning this migration, we can provide migration consultation. To discuss this option, contact support@flowfuse.com.

Resources