EKS Cluster: Part 13 – Gateway API (Part 1)

Series of blog posts show progress of updating/adding to EKS Cluster, this post covers adding Gateway API. See part 2 below:

Gateway API:

  • Kubernetes positions Gateway API as the next generation of service networking for L4/L7 routing.

Flow & Steps Forward:

  • We’ll use the stable Envoy Gateway v1.9.2 Helm chart.
    • Its chart supplies compatible Gateway API and Envoy CRDs.
  • No ALB/NLB hourly charges.
  • No new Terraform, IAM, or Pod Identity initially.
  • Managed completely through Argo CD.
  • Teaches the portable Gateway API objects.
  • Test locally through kubectl port-forward.
  • Later, repeat the exercise with AWS Load Balancer Controller to create real ALBs/NLBs.

Implementation Phases:

  • Start with Envoy Gateway using an internal ClusterIP:
  • Install Envoy Gateway and Gateway API CRDs.
  • Update the lab-platform and workload AppProjects.
  • Deploy a small ARM64-compatible demonstration application.
  • Add GatewayClass, Gateway, and HTTPRoute.
  • Port-forward Envoy and test routing with curl.
  • Test path matching, redirects, header matching, and traffic splitting.
  • Optionally add AWS Load Balancer Controller for public ALB/NLB routing.
PhasePurposeResources
Phase 1Install the controller and CRDsEnvoy Gateway Helm chart
Phase 2A Prepare platform ownershipAppProject, Application, Namespace
Phase 2BSelect and configure EnvoyGatewayClass, EnvoyProxy
Phase 2CCreate the listenerGateway
Phase 3ADeploy the test applicationDeployment, Service
Phase 3BConnect traffic to the applicationHTTPRoute
Phase 4Test routingPort-forward, curl, status checks
Phase 5Advanced routingHeaders, paths, traffic splitting, TLS

Planned Gitops Structure:

applications/lab/
├── platform/
│ ├── envoy-gateway.yaml
│ └── envoy-gateway-config.yaml
└── workloads/
└── gateway-demo.yaml
apps/
├── envoy-gateway/
│ └── values.yaml
├── envoy-gateway-config/
│ ├── namespace.yaml
│ ├── gatewayclass.yaml
│ ├── envoy-proxy.yaml
│ └── gateway.yaml
└── gateway-demo/
├── deployment.yaml
├── service.yaml
└── httproute.yaml
ResourceResponsibility
GatewayClassSelects Envoy Gateway as the implementation
EnvoyProxyForces the generated Envoy service to ClusterIP
GatewayDefines the HTTP listener
HTTPRouteRoutes requests to the application
ServiceProvides the route backend
DeploymentRuns the demonstration application

Phase 1: Install the controller and CRDs & Envoy Gateway Helm Chart

apps/envoy-gateway/values.yaml

  • Sources
  • This configures the Envoy Gateway control plane.
  • The service.type here applies to the controller service—not yet to the Envoy data-plane proxy we will create later.
  • Envoy Gateway’s chart installs compatible Gateway API and Envoy Gateway CRDs by default.

applications/lab/platform/envoy-gateway.yaml

===========
metadata:
annotations:
argocd.argoproj.io/sync-wave: "-2"
spec:
sources:
# Install only the standard Gateway API CRDs and the
# Envoy Gateway extension CRDs.
- repoURL: docker.io/envoyproxy
chart: gateway-crds-helm
targetRevision: v1.6.7
helm:
releaseName: envoy-gateway-crds
valuesObject:
crds:
gatewayAPI:
enabled: true
channel: standard
envoyGateway:
enabled: true
===========

lab-platform.yaml:

  • Update the file above w/the following code below
===========
spec:
sourceRepos:
- docker.io/envoyproxy
===========
destinations:
- namespace: envoy-gateway-system
server: https://kubernetes.default.svc
===========
clusterResourceWhitelist:
- group: admissionregistration.k8s.io
kind: ValidatingAdmissionPolicy
- group: admissionregistration.k8s.io
kind: ValidatingAdmissionPolicyBinding
- group: admissionregistration.k8s.io
kind: ValidatingWebhookConfiguration
- group: admissionregistration.k8s.io
kind: MutatingWebhookConfiguration
- group: gateway.networking.k8s.io
kind: GatewayClass
- group: karpenter.k8s.aws
kind: EC2NodeClass
- group: karpenter.sh
kind: NodePool
===========
namespaceResourceWhitelist:
- group: ""
kind: ConfigMap
- group: ""
kind: Secret
- group: batch
kind: Job

Phase 2a: Prepare platform ownership & AppProject, Application, Namespace

lab-platform.yaml:

  • Update the file above w/the following code below
===========
- namespace: gateway-demo
server: https://kubernetes.default.svc
===========

applications/lab/platform/envoy-gateway-config.yaml

apps/envoy-gateway-config/namespace.yaml

  • We explicitly track the namespace in Git instead of relying only on CreateNamespace=true because this lets us manage its labels declaratively.
===========
apiVersion: v1
kind: Namespace
metadata:
name: gateway-demo
labels:
app.kubernetes.io/name: gateway-demo
app.kubernetes.io/part-of: gateway-api-lab
app.kubernetes.io/managed-by: argocd
environment: lab
# Report restricted Pod Security Standard violations.
# These are warnings rather than deployment-blocking enforcement.
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
===========

Phase 2b: Select and configure Envoy for GatewayClass, EnvoyProxy

  • Nothing will receive traffic yet, and no AWS load balancer should be created. Phase 2B adds only two resources:
    • GatewayClass — selects Envoy Gateway as the controller.
    • EnvoyProxy — defines how the future Envoy data plane should run.

lab-platform.yaml:

===========
# GatewayClass is cluster-scoped and selects the controller.
- group: gateway.networking.k8s.io
kind: GatewayClass
===========
# EnvoyProxy is an Envoy Gateway configuration resource.
- group: gateway.envoyproxy.io
kind: EnvoyProxy
===========

apps/envoy-gateway-config/gatewayclass.yaml

  • GatewayClass is similar to how a StorageClass selects a storage implementation.
    • It describes the type of Gateway infrastructure available to the cluster.
===========
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: envoy
annotations:
argocd.argoproj.io/sync-wave: "-1"
===========
  • Tells Kubernetes that Envoy Gateway is responsible for reconciling the resource.
===========
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
===========

apps/envoy-gateway-config/envoy-proxy.yaml

ComponentPurposeNamespace
Envoy Gateway controllerWatches Gateway API objectsenvoy-gateway-system
Envoy proxy data planeEventually receives application trafficGenerated after Phase 2C
  • At this point, EnvoyProxy is only configuration. Because no Gateway references it yet, Envoy Gateway should not create the proxy Deployment or Service.

Phase 2c: Create the listener for Gateway

  • This phase adds one file and one AppProject permission. The Gateway will reference the EnvoyProxy from Phase 2B, causing Envoy Gateway to generate:
    • One internal Envoy Deployment.
    • One internal ClusterIP Service.
    • One HTTP listener on port 80.
  • There is still no application or route behind it yet.

lab-platform.yaml:

===========
# Gateway defines the platform-owned network listener.
- group: gateway.networking.k8s.io
kind: Gateway
===========

apps/envoy-gateway-config/gateway.yaml

===========
gatewayClassName: envoy
===========
  • Selects the envoy gateway controller
===========
infrastructure:
parametersRef:
===========
  • Links this Gateway to the gateway-demo-proxy configuration, which specifies ClusterIP.
  • Creates an HTTP listener with:
    • Port: 80
    • Hostname: gateway-demo.local
    • Allowed route type: HTTPRoute
    • Allowed namespace: only gateway-demo
===========
listeners:
===========
  • The Same restriction prevents routes in unrelated namespaces from attaching themselves to this Gateway. Gateway API supports Same, All, or label-selected namespaces; Same is the narrowest starting point.

One thought on “EKS Cluster: Part 13 – Gateway API (Part 1)”

Leave a Reply