Kubernetes
service exposure
internet access
cloud infrastructure
networking

How do I expose Kubernetes service to the internet?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Exposing a Kubernetes workload to the public internet usually means turning an internal ClusterIP service into an entry point that external clients can reach. The right mechanism depends on whether you want quick access for testing, a managed cloud load balancer, or host-based routing for multiple apps.

Start with the Service Type

Pods are ephemeral, so you normally expose them through a Service. By default, a service is ClusterIP, which is only reachable from inside the cluster.

yaml
1apiVersion: v1
2kind: Service
3metadata:
4  name: web
5spec:
6  selector:
7    app: web
8  ports:
9    - port: 80
10      targetPort: 8080
11  type: ClusterIP

This is correct for internal traffic, but not enough for internet users.

Option 1: Use NodePort for Simple External Access

NodePort opens the same port on every cluster node. Traffic sent to any node IP on that port is forwarded to the service.

yaml
1apiVersion: v1
2kind: Service
3metadata:
4  name: web
5spec:
6  type: NodePort
7  selector:
8    app: web
9  ports:
10    - port: 80
11      targetPort: 8080
12      nodePort: 30080

You can then reach the app at http://node-ip:30080.

NodePort is useful for labs and quick debugging, but it has tradeoffs:

  • You manage the external address yourself.
  • The port is high and not user-friendly.
  • TLS, host routing, and production traffic management are mostly your problem.

Option 2: Use LoadBalancer in Cloud Environments

On managed Kubernetes platforms, the most common public entry point is a LoadBalancer service. The cloud provider provisions an external load balancer and routes traffic to the service automatically.

yaml
1apiVersion: v1
2kind: Service
3metadata:
4  name: web
5spec:
6  type: LoadBalancer
7  selector:
8    app: web
9  ports:
10    - port: 80
11      targetPort: 8080

After applying the manifest, run:

bash
kubectl get svc web

Wait until the EXTERNAL-IP field is populated. That address becomes your public endpoint.

This is often the fastest production-ready option for a single app because the provider handles health checks and external routing. The downside is cost and reduced flexibility if you later need many domains and path rules.

Option 3: Use Ingress for HTTP and HTTPS Routing

If you need multiple public routes, use an Ingress controller plus an Ingress resource. The controller, such as NGINX Ingress, watches Ingress objects and configures reverse-proxy behavior for you.

First, keep your app behind a normal internal service:

yaml
1apiVersion: v1
2kind: Service
3metadata:
4  name: web
5spec:
6  selector:
7    app: web
8  ports:
9    - port: 80
10      targetPort: 8080
11  type: ClusterIP

Then define the public routing rules:

yaml
1apiVersion: networking.k8s.io/v1
2kind: Ingress
3metadata:
4  name: web-ingress
5spec:
6  rules:
7    - host: app.example.com
8      http:
9        paths:
10          - path: /
11            pathType: Prefix
12            backend:
13              service:
14                name: web
15                port:
16                  number: 80

Ingress is a strong choice when you want:

  • Host-based routing such as api.example.com and app.example.com
  • Path-based routing such as /api and /admin
  • TLS termination with a certificate manager
  • One public edge for many services

Security and Operational Concerns

Public exposure is not only a networking step. You also need to think about security boundaries.

  • Restrict what is public. Keep databases and internal APIs behind ClusterIP.
  • Use TLS for public traffic.
  • Apply authentication at the application or gateway layer.
  • Consider NetworkPolicy to limit pod-to-pod access inside the cluster.
  • Add readiness probes so the load balancer only sends traffic to healthy pods.

You should also verify DNS. If you use an Ingress or a cloud load balancer, point your domain name to the external IP or hostname rather than hard-coding node addresses.

A Practical Decision Guide

Use NodePort when you need a simple, temporary external endpoint and are comfortable handling the node address yourself.

Use LoadBalancer when your cluster runs in a cloud environment and you want a straightforward public service with minimal manual networking.

Use Ingress when you need standard web routing features and expect more than one public application.

Common Pitfalls

One frequent mistake is exposing a ClusterIP service and expecting it to be reachable from outside the cluster. ClusterIP is internal only.

Another mistake is creating an Ingress resource without installing an Ingress controller. The YAML object alone does nothing unless a controller is present to act on it.

A third mistake is using NodePort in production without considering firewall rules, TLS, and stable DNS. It works, but it is rarely the cleanest long-term design.

Summary

  • Kubernetes exposes workloads externally through NodePort, LoadBalancer, or Ingress-based routing.
  • 'NodePort is simple but mostly suited for testing and small deployments.'
  • 'LoadBalancer is the usual cloud-native way to publish a single service.'
  • Ingress is best for HTTP and HTTPS routing across multiple services or domains.
  • Public exposure should include TLS, health checks, and clear security boundaries.

Course illustration
Course illustration

All Rights Reserved.