Prerequisites
Skew protection supports Kubernetes and ECS, with different routing prerequisites. Kubernetes requires a Gateway API controller. ECS requires a configured ALB listener and supports query pinning only.
Enable Skew Protection
Section titled “Enable Skew Protection”Skew protection is disabled by default. Enable it via the PLT_FEATURE_SKEW_PROTECTION environment variable or the Helm value services.icc.features.skew_protection.enable:
PLT_FEATURE_SKEW_PROTECTION=trueWhen disabled, ICC creates no version-aware HTTPRoute or ALB listener rules. A Gateway controller is required only for Kubernetes skew protection.
Kubernetes Gateway API
Section titled “Kubernetes Gateway API”Gateway API CRDs
Section titled “Gateway API CRDs”The Gateway API is not built into Kubernetes. The Custom Resource Definitions (CRDs) must be installed separately:
kubectl apply --server-side=true -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yamlThis installs the CRDs only (GatewayClass, Gateway, HTTPRoute) — no controller is deployed.
Gateway API Controller
Section titled “Gateway API Controller”A Gateway API-compliant controller must be deployed in the cluster to process Gateway and HTTPRoute resources.
What the controller must support depends on which pinning mode you use. ICC defaults to query (see Configuration).
Required in both modes:
| Feature | Conformance Level | Required For |
|---|---|---|
HTTPRoute with backendRefs | Core | Routing to versioned Services |
headers match with Exact type | Core | x-deployment-id header matching |
Required by query pinning (PLT_SKEW_DEFAULT_ROUTING_MODE=query, the default):
| Feature | Conformance Level | Required For |
|---|---|---|
queryParams match with Exact type | Extended | Matching ?dpl=<version> on the request |
Required by cookie pinning (PLT_SKEW_DEFAULT_ROUTING_MODE=cookie):
| Feature | Conformance Level | Required For |
|---|---|---|
ResponseHeaderModifier filter | Extended | Setting Set-Cookie on responses |
headers match with RegularExpression type | Implementation-specific | Reading the __plt_dpl cookie back off the request |
Compatible Controllers
Section titled “Compatible Controllers”This table covers Kubernetes Gateway API controllers only. On AWS it therefore describes EKS, where a controller reconciles HTTPRoute resources; it says nothing about ECS, which does not use the Gateway API at all.
This table is a dated snapshot of the
Gateway API v1.3.0 conformance reports,
in which each project declares the features it implements. Query mode is
reported as HTTPRouteQueryParamMatching; the cookie column reports
HTTPRouteResponseHeaderModification, which is the Set-Cookie half of cookie
pinning. Check the
current conformance reports
before choosing a controller because versions and feature support can change.
| Controller | Version in report | Query | Cookie |
|---|---|---|---|
| Envoy Gateway | v1.5.0 | Yes | Yes |
| Istio | 1.26.1 | Yes | Yes |
| Contour | v1.33.0 | Yes | Yes |
| Cilium | main | Yes | Yes |
| Traefik | v3.5 | Yes | Yes |
| kgateway | v2.1.0 | Yes | Yes |
| Gloo Gateway | v1.20.13 | Yes | Yes |
| NGINX Gateway Fabric | 2.0.0, 2.1.0, 2.2.0 | Yes | Yes |
| Linkerd | 2.18 | Yes | Yes |
| Airlock Microgateway | 4.6.0 - 5.1.0 | Yes | Yes |
| Alibaba Cloud Service Mesh | 1.27 | Yes | Yes |
Kong Operator (expressions router) | v2.0.6 | Yes | Yes |
Kong Operator (traditional_compatible router) | v2.0.6 | No | Yes |
| GKE Gateway | 1.33.4-gke.1134000 | No | Yes |
| AWS Load Balancer Controller | v2.17.0, v3.0.0 | No | No |
| Gravitee | 4.8.5 | Not reported | Not reported |
Platformatic verifies both modes against Envoy Gateway v1.4.2, which is the controller used by the reference EKS deployment.
A “Yes” in the Cookie column confirms the controller can set the cookie. Cookie mode also needs a RegularExpression header match to read it back, which has no conformance feature name, so confirm that from your controller’s documentation. This only decides the outcome for controllers whose Query column is No, since anywhere both are available query mode is the recommended default.
ECS Prerequisites
Section titled “ECS Prerequisites”ECS does not use the Gateway API. ICC sends a provider-neutral route plan to Machinist, which creates host-scoped rules on an ALB listener.
Before enabling skew protection on ECS:
- Set ICC’s
PLT_MACHINIST_PROVIDER=ecs, set Machinist’sPLT_PROVIDER=ecs, and configure Machinist withPLT_ECS_LISTENER_ARN. - Give Machinist permission to describe the listener and load balancer and to describe, create, tag, and delete listener rules and target groups.
- Use hostname-based routing. ECS route application rejects an application without a hostname because ALB cannot remove an external path prefix.
- Use query routing. ALB cannot add the response cookie required by cookie mode.
- Give every version its own ECS service and target group. An externally created service must be attached to its target group when the service is created. ICC-managed deployments create both through Machinist.
- For ICC-managed deployments, configure
PLT_ECS_CLOUD_MAP_NAMESPACE_IDand the ECS, Cloud Map,iam:PassRole, registry-secret, and load-balancer permissions required by the workload actuator. - Ensure Prometheus discovers and scrapes every version. ECS per-version
expiry requires
@platformatic/watt-extra1.16.0 or later so metrics carry thedeploymentVersionlabel. - Configure each target group’s health check against Watt’s dedicated health
endpoint on port 9090, normally
HTTP:9090/ready. Do not health-check the application listener on port 3042: those requests are application ingress metrics, so ALB probes would appear as permanent traffic and prevent both HTTP and workflow versions from expiring early. ICC-managed ECS deployments created by Machinist use the dedicated health port automatically.
ALB listener-rule and target-group quotas bound the number of applications and simultaneously live versions. Check those quotas for the selected listener and region before setting a high per-application version limit.
Version labels are matched differently on ALB
Section titled “Version labels are matched differently on ALB”The Gateway API and ALB do not agree on what counts as a match for the pinning parameter, so the same version labels behave differently on EKS and ECS.
| Kubernetes Gateway API | ALB (ECS) | |
|---|---|---|
| Case | Exact: ?dpl=V1 does not match version v1 | Case insensitive: ?dpl=V1 matches v1 |
* and ? in a label | Literal characters | Wildcards: * matches any run of characters, ? matches one |
The ICC deploy API rejects these ambiguous values, but a customer-managed
reactive registration can still present two live labels that differ only in
case. On EKS each is pinned separately; on ECS their pinning rules are
indistinguishable and the lower priority wins, so a request pinned to one can
be served by the other. The same applies to a manually supplied label containing
* or ?, which ALB can match against several versions.
Use version labels that differ by more than case, and avoid * and ? in them. Labels produced by a deploy pipeline normally satisfy this already; it is worth checking if you set them by hand.
Application Metrics
Section titled “Application Metrics”Traffic-based expiry reads per-version request rates from Prometheus, and how a version is identified depends on the platform.
On Kubernetes, a version is a distinct workload, and ICC selects its
instances by joining kube_pod_labels on app.kubernetes.io/instance. This
needs nothing from the application beyond exposing its metrics, but it does
require that label to be set — see
Deploying Versioned Applications.
On ECS, there is no such join. The application reports its own version as a
deploymentVersion label on its metrics, which
@platformatic/watt-extra 1.16.0 or later emits from the version ICC assigns
at registration.
In both cases the metrics read are the application’s own Node.js metrics; the Kubernetes join only decides which instances belong to the version.
Infrastructure probes must not enter those application metrics. On ECS, point the ALB target-group health check at Watt’s readiness endpoint on port 9090, not at an application route on port 3042. A target group is checked by every enabled ALB node, so even an unused version otherwise reports non-zero RPS. Kubernetes readiness and liveness probes should use the same dedicated health port rather than the application port.
Kubernetes Gateway and GatewayClass Resources
Section titled “Kubernetes Gateway and GatewayClass Resources”The cluster operator must create a GatewayClass and Gateway resource before ICC can manage HTTPRoute resources. This is standard Gateway API setup:
apiVersion: gateway.networking.k8s.io/v1kind: GatewayClassmetadata: name: platformaticspec: # controllerName varies by controller — this example uses Envoy Gateway controllerName: gateway.envoyproxy.io/gatewayclass-controller---apiVersion: gateway.networking.k8s.io/v1kind: Gatewaymetadata: name: platform-gateway namespace: platformaticspec: gatewayClassName: platformatic listeners: - name: https protocol: HTTPS port: 443 tls: mode: Terminate certificateRefs: - name: platform-tls - name: http protocol: HTTP port: 80ICC references this Gateway in the parentRefs of each managed HTTPRoute. The Gateway resource is auto-discovered — no additional configuration is needed unless your cluster has multiple Gateways.
Kubernetes Machinist RBAC
Section titled “Kubernetes Machinist RBAC”Machinist’s Kubernetes service account must have permissions to manage HTTPRoute resources. If you are using the Platformatic Helm chart, these permissions are included automatically. For manual installations, add the following to Machinist’s ClusterRole:
apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: machinist-gateway-apirules: - apiGroups: ["gateway.networking.k8s.io"] resources: ["httproutes"] verbs: ["get", "list", "create", "update", "patch", "delete"] - apiGroups: ["gateway.networking.k8s.io"] resources: ["gateways"] verbs: ["get", "list"]Kubernetes Version
Section titled “Kubernetes Version”Gateway API v1.5.1 is the current supported release at the time of writing. Use the Gateway API project’s compatibility policy to select a release supported by your Kubernetes version and controller.
Note that the ICC Helm chart requires Kubernetes 1.30 or newer regardless (enforced by its kubeVersion constraint), so 1.30 is the effective floor for any ICC installation.