Migrate to Envoy Gateway

  • Tier: Free, Premium, Ultimate
  • Offering: GitLab Self-Managed

Starting with GitLab 19.0, GitLab chart disables the bundled NGINX Ingress and defaults to Gateway API and the bundled Envoy Gateway. All bundled Ingress controllers, including HAProxy and Traefik, are deprecated and will be removed in 20.0. Ingresses are not deprecated and will remain available after 20.0, but will need an external Ingress controller.

You can migrate from the bundled NGINX Ingress to Gateway API with either:

If you do not want to migrate, you can continue using an Ingress controller.

Migrate in one step

Expect approximately 5 minutes of downtime during migration. The actual time may differ depending on your deployment, infrastructure, and configuration. For a zero-downtime approach, see zero downtime migration.

To migrate from (NGINX) Ingress to Gateway API and Envoy Gateway:

  1. Install Envoy and Gateway API CRDs:

    helm template eg-crds oci://docker.io/envoyproxy/gateway-crds-helm \
      --version v1.9.0 \
      --set crds.gatewayAPI.enabled=true \
      --set crds.envoyGateway.enabled=true \
      | kubectl apply --server-side -f -
  2. If not, install the Gateway API CRDs through your cloud provider or manually apply to your cluster.

  3. Disable NGINX Ingress and Ingress resources:

    # Disable bundled NGINX Ingress controller.
    nginx-ingress:
      enabled: false
    
    global:
      # Disable rendering of Ingress resources.
      ingress:
        enabled: false
  4. Configure Certmanager for Gateway API:

    # Configure bundled certmanager for Gateway API support.
    certmanager:
      config:
        apiVersion: controller.config.cert-manager.io/v1alpha1
        kind: ControllerConfiguration
        enableGatewayAPI: true
    
    global:
      gatewayApi:
        configureCertmanager: true
  5. Enable Envoy and Gateway API resources:

    global:
      # Disable rendering of Ingress resources.
      gatewayApi:
        # Install a Gateway and Routes for each component.
        enabled: true
        # Install the bundled Envoy Gateway chart, a GatewayClass, a EnvoyPatchPolicy, and the EnvoyProxy resources.
        installEnvoy: true
  6. Configure the Gateway to bind a static IP address. By default the IP configured via global.hosts.externalIP is reused.

    # Depending on your cloud provider you might to migrate additional annotations.
    global:
      hosts:
        # Only used by Envoy if bundled NGINX Ingress is disabled and no custom
        # gateway addresses are defined.
        externalIP: "10.10.0.1"
    gatewayApiResources:
      gateway:
        addresses:
        - type: IPAddress
          value: "10.10.0.2"
        infrastructure:
          annotations: {}

    Instead of using global.hosts.externalIP or gatewayApiResources.gateway.addresses, configure the annotations for the provisioned LoadBalancer:

    gatewayApiResources:
      gateway:
        infrastructure:
          annotations:
            networking.gke.io/load-balancer-type: External
            networking.gke.io/load-balancer-ip-addresses: gitlab-ip-address
            cloud.google.com/l4-rbs: enabled

    To migrate a EKS LoadBalancer, migrate your annotations from the NGINX controller service to the Envoy Gateway configuration:

    gatewayApiResources:
      gateway:
        infrastructure:
          annotations:
            service.beta.kubernetes.io/aws-load-balancer-type: nlb
            service.beta.kubernetes.io/aws-load-balancer-eip-allocations: "gitlab-allocation-id"
            service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
  7. Upgrade your GitLab chart release with the updated values.

Migrate with zero downtime

To perform a zero-downtime migration, you can run NGINX Ingress and Envoy Gateway side by side, allowing two LoadBalancers to operate simultaneously. Once Envoy Gateway is fully configured to handle GitLab traffic, update the GitLab DNS records to point to the Envoy Gateway-managed LoadBalancer.

  1. Enable Envoy Gateway and Gateway API resources without disabling NGINX Ingress:

    nginx-ingress:
      enabled: true
    
    global:
      hosts:
        # External LoadBalancer IP bound by NGINX Ingress
        externalIp: "10.10.0.1"
      # Enable Gateway API and configure another
      gatewayApi:
        enabled: true
        installEnvoy: true
    gatewayApiResources:
      gateway:
        addresses:
         - type: IPAddress
           value: "10.10.0.2"
        infrastructure:
          annotations: {}
  2. Configure your TLS certificates or a certmanager issuer for the managed Gateway:

    You can’t use the Issuer provided by GitLab chart for this purpose. The issuer uses HTTP01 which won’t be able to retrieve certificates until your DNS records have been updated.

    1. Configure a DNS01 Issuer or customize the listeners to use already existing certificates.

    2. If you created a custom Issuer, enable certmanager’s Gateway API support and annotate the managed Gateway:

      # Enable Gateway API support for bundled certmanager.
      certmanager:
        config:
          apiVersion: controller.config.cert-manager.io/v1alpha1
          kind: ControllerConfiguration
          enableGatewayAPI: true
      
      global:
        gatewayApi:
          # Do not configure HTTP01 issues.
          configureCertmanager: false
      gatewayApiResources:
        gateway:
          # Annotate Gateway to use custom DNS01 issuer.
          annotations:
            cert-manager.io/issuer: gitlab-dns01
  3. Ensure GitLab is reachable if the domain would resolve to the IP of the Envoy Gateway LoadBalancer:

    $ curl -Lso /dev/null \
      --write-out 'Status: %{http_code} TLS: %{ssl_verify_result} (0=OK)' \
      --resolve gitlab.example.com:443:10.10.0.2 \
      "https://gitlab.example.com"
    Status: 200 TLS: 0 (0=OK)
  4. Update your DNS entries to resolve to the Envoy Gateway LoadBalancer.

  5. Wait for the DNS entries to propagate to all clients.

  6. Disable NGINX Ingress and Ingress objects:

    nginx-ingress:
      enabled: false
    
    global:
      ingress:
        enabled: false

Continue using an Ingress controller

If you have not yet migrated to Gateway API and Envoy Gateway, you can disable all Gateway API components and continue using an Ingress controller.

If you have already migrated to Gateway API and are reverting to an Ingress controller, expect approximately 5 minutes of downtime during the switch, similar to the one step migration. The actual time may differ depending on your deployment, infrastructure, and configuration.

  1. Disable all Gateway API components in your values file:

    global:
      gatewayApi:
        enabled: false
        installEnvoy: false
  2. Enable Ingress resources and configure your Ingress controller:

    If you manage your own Ingress controller outside of the GitLab chart, you only need to ensure Ingress resources are rendered. Do not enable the bundled NGINX Ingress controller.

    nginx-ingress:
      enabled: false
    
    global:
      ingress:
        enabled: true
        configureCertmanager: true

    For more details, see external Ingress controller.

    Re-enabling the bundled NGINX Ingress controller is the least preferred option. It is deprecated and will be removed in 20.0. The upstream NGINX Ingress project is also archived. Consider using an external Ingress controller or migrating to Envoy Gateway instead.

    Enable the bundled NGINX Ingress controller and Ingress resources:

    nginx-ingress:
      enabled: true
    
    global:
      ingress:
        enabled: true
        configureCertmanager: true
  3. Upgrade your GitLab chart release with the updated values.

Timeout settings

NGINX Ingress and Envoy Gateway express proxy timeouts differently. If you customized the NGINX Ingress timeout settings, the following table shows how they map to the Gateway API configuration for Webservice traffic and the defaults the chart ships with Envoy Gateway:

NGINX Ingress setting Previous chart default Gateway API equivalent Chart default
ingress.proxyConnectTimeout (proxy-connect-timeout) 15 gitlab.webservice.backendTrafficPolicy.spec.timeout.tcp.connectTimeout 300s
ingress.proxyReadTimeout (proxy-read-timeout) 600 gitlab.webservice.backendTrafficPolicy.spec.timeout.http.streamIdleTimeout 3600s
ingress.proxyBodySize (proxy-body-size) 512m None — Envoy streams request bodies without a size cap; limits are enforced by GitLab itself Not applicable
None — NGINX applied no absolute request deadline Not applicable gitlab.webservice.deployments.<name>.gatewayRoute.rules[].timeouts 0s (disabled)

Like proxy-read-timeout, streamIdleTimeout is an inactivity timeout: it resets while data flows in either direction, so long-running transfers are not interrupted. The absolute HTTPRoute rule timeouts have no NGINX equivalent and stay disabled by default. For configuration examples, see the Webservice Gateway timeouts documentation.

Host headers with a trailing dot

NGINX removes a trailing dot from the Host header before matching a server name. Envoy Gateway matches the Host or :authority header against route hostnames literally, and Gateway API hostnames cannot contain a trailing dot.

As a result, clients that request an absolute fully qualified domain name with a trailing dot, for example https://gitlab.example.com./, receive 404 Not Found responses after the migration. The Envoy access log records these requests with response_code_details: route_not_found. A common example is a GitLab Runner configured with a trailing dot in the url setting to avoid DNS search domain lookups. Affected runners fail to verify or register with status=404.

The chart enables the stripTrailingHostDot setting on the Webservice listeners by default, which restores the NGINX behavior. This setting requires the bundled Envoy Gateway 1.9 or later.

The setting also requires the ClientTrafficPolicy CRD from Envoy Gateway 1.9. The Envoy Gateway 1.8 CRD does not define this field, so the API server prunes it without an error and trailing-dot requests keep returning 404. Apply the current CRDs before you upgrade the chart. For more information, see Upgrade the Envoy Gateway CRDs.

On chart versions that bundle Envoy Gateway 1.8 or earlier, the setting is not available. Remove the trailing dot from the client configuration instead. For example, update the url setting in the GitLab Runner config.toml, or remove the trailing dot from /etc/hosts entries on the client host.