Google Kubernetes Engine (GKE) applications are often exposed to the outside world using a combination of GKE services, Google Compute Engine (GCE) Ingress, and Cloud Load Balancing. This setup allows for robust, scalable, and feature-rich external access to your containerized workloads.

Let’s see this in action. Imagine you have a simple web application deployed in GKE.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-webapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-webapp
  template:
    metadata:
      labels:
        app: my-webapp
    spec:
      containers:
      - name: web
        image: gcr.io/google-samples/hello-app:1.0
        ports:
        - containerPort: 8080

This deployment creates three replicas of a basic "hello world" application, listening on port 8080 inside the containers. To make this accessible externally, we first need a Kubernetes Service.

apiVersion: v1
kind: Service
metadata:
  name: my-webapp-service
spec:
  selector:
    app: my-webapp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: NodePort

This Service of type NodePort exposes the my-webapp pods on a static port on each GKE node. The port: 80 means clients will connect to port 80 on the service, and targetPort: 8080 directs that traffic to the container’s port.

Now, to get this NodePort service onto the public internet with a proper load balancer, we create an Ingress resource.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-webapp-ingress
  annotations:
    kubernetes.io/ingress.class: "gce"
spec:
  rules:
  - http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-webapp-service
            port:
              number: 80

The crucial annotation here is kubernetes.io/ingress.class: "gce". This tells GKE to provision a Google Cloud Load Balancer (specifically, a Global External HTTP(S) Load Balancer) to front this Ingress. GKE then creates a forwarding rule, a backend service, and health checks that point to the NodePort service. The load balancer gets a public IP address, and traffic hitting that IP on port 80 (or 443 for HTTPS) will be routed to your application pods.

The mental model is that the GKE Ingress controller acts as a bridge. It watches Kubernetes Ingress resources and, based on the kubernetes.io/ingress.class: "gce" annotation, configures the corresponding Google Cloud Load Balancer. The load balancer itself is the public-facing entity, distributing traffic across the nodes in your GKE cluster. Each node, in turn, forwards traffic to the specific pods managed by the NodePort service.

You control routing logic, SSL termination, and health checking primarily through the Ingress resource’s rules, annotations, and the underlying Cloud Load Balancer configuration. For instance, you can specify multiple hostnames and paths, route to different services, and configure TLS certificates.

The one thing that often trips people up is how GKE manages the lifecycle of the Cloud Load Balancer. When you create an Ingress with kubernetes.io/ingress.class: "gce", GKE provisions all the necessary GCP resources (forwarding rules, backend services, URL maps, target proxies, health checks, and even a Google-managed SSL certificate if you configure it). When you delete the Ingress resource, GKE cleans up these GCP resources. This declarative approach means you manage your external access through Kubernetes objects, and the GKE control plane handles the underlying cloud infrastructure provisioning and management.

The next step is usually to configure HTTPS for your exposed application, which involves managing TLS certificates within the Ingress resource.

Want structured learning?

Take the full Gke course →