Top Tags

Port forward and external IP to Pods Kubernetes service

Port forward and external IP to Pods Kubernetes service

Understanding Kubernetes Service Types

Kubernetes Services provide an abstract way to expose an application running on a set of Pods. Services enable network access to Pods through a stable endpoint, abstracting away the dynamic nature of Pod IPs. There are four primary Service types in Kubernetes:

Service TypeUse CaseAccessibilityPort Range
ClusterIPInternal cluster communicationWithin cluster onlyAny valid port
NodePortExternal access via node IPExternal via <NodeIP>:<NodePort>30000-32767
LoadBalancerProduction external accessExternal via cloud/MetalLB IPAny valid port
ExternalNameMap to external DNSDNS CNAME recordN/A

How Service Networking Works

When you create a Service, Kubernetes assigns it a cluster-scoped virtual IP address (ClusterIP). The kube-proxy component running on each node programs iptables or IPVS rules to redirect traffic destined for the Service's ClusterIP to one of the backing Pods. This provides:

  • Load balancing across multiple Pod replicas
  • Service discovery via DNS (<service-name>.<namespace>.svc.cluster.local)
  • Stable endpoints even when Pods are rescheduled

ClusterIP Service (Default)

ClusterIP is the default Service type. It exposes the Service on an internal IP address accessible only within the cluster. This is ideal for internal microservices communication.

yaml
1apiVersion: v1
2kind: Service
3metadata:
4 name: backend-api
5 labels:
6 app: backend
7spec:
8 type: ClusterIP # Default, can be omitted
9 selector:
10 app: backend
11 ports:
12 - name: http
13 protocol: TCP
14 port: 8080 # Port the Service listens on
15 targetPort: 3000 # Port on the Pod

Key ClusterIP Concepts

  • port: The port the Service exposes within the cluster
  • targetPort: The actual port your container listens on (can be a named port)
  • selector: Label selector to identify backing Pods

Accessing ClusterIP Services

From within the cluster, you can access the service via:

bash
1# Using service DNS name
2curl http://backend-api.default.svc.cluster.local:8080
3
4# Using cluster IP directly
5curl http://10.96.45.123:8080

NodePort Example - Expose Port to Kubernetes API

NodePort extends ClusterIP by additionally exposing the Service on a static port on each Node's IP. When you set type: NodePort, Kubernetes allocates a port from the configured range (default: 30000-32767) and every node proxies that port into your Service.

NodePort Architecture

External Client

http://NodeIP:30080

Node 1

:30080

Node 2

:30080

Node 3

:30080

Service (ClusterIP)

:80

Pod 1

:80

Pod 2

:80

Pod 3

:80

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

NodePort Port Configuration

Port FieldDescriptionRequired
portPort exposed on the ClusterIP (internal)Yes
targetPortPort on the Pod containerYes
nodePortStatic port on all nodes (30000-32767)Optional (auto-assigned if omitted)

Accessing NodePort Services

You can access the service from outside the cluster using any node's IP:

bash
1# Access via any node IP address
2curl http://192.168.1.100:30080
3curl http://192.168.1.101:30080
4curl http://192.168.1.102:30080
5
6# Check allocated NodePort
7kubectl get svc nginx-service -o jsonpath='{.spec.ports[0].nodePort}'

NodePort Use Cases

  • Development and testing environments
  • On-premises clusters without LoadBalancer support
  • Custom load balancing solutions (HAProxy, Nginx, Traefik)
  • Bare-metal deployments with external load balancers

LoadBalancer Example - Expose Pod to External LAN IP with MetalLB

LoadBalancer is the standard way to expose a Service externally in production. When you create a LoadBalancer Service, Kubernetes first provisions a NodePort, then requests an external load balancer from the cloud provider (or MetalLB for bare-metal/on-premises clusters).

LoadBalancer Architecture

LoadBalancer

External IP

192.168.1.240

Node 1

Node 2

Node 3

Service (ClusterIP)

Pod 1

Pod 2

Pod 3

yaml
1apiVersion: v1
2kind: Service
3metadata:
4 name: mongodb-service
5spec:
6 selector:
7 app: mongodb
8 ports:
9 - protocol: TCP
10 port: 27017
11 targetPort: 27017
12 type: LoadBalancer

MetalLB for Bare-Metal Clusters

For on-premises or bare-metal Kubernetes clusters (like MicroK8s, K3s, or kubeadm), there's no cloud provider to provision load balancers. MetalLB fills this gap by providing a network load balancer implementation.

MetalLB operates in two modes:

ModeProtocolUse Case
Layer 2 (ARP/NDP)ARP/IPv6 NDPSimple setup, single node handles traffic
BGPBorder Gateway ProtocolProduction, true load distribution

LoadBalancer with Specific IP (MetalLB)

You can request a specific IP from your MetalLB address pool:

yaml
1apiVersion: v1
2kind: Service
3metadata:
4 name: webapp-service
5 annotations:
6 metallb.universe.tf/loadBalancerIPs: 192.168.1.240
7spec:
8 selector:
9 app: webapp
10 ports:
11 - protocol: TCP
12 port: 80
13 targetPort: 8080
14 type: LoadBalancer

Checking LoadBalancer Status

bash
1# Get external IP assigned to service
2kubectl get svc mongodb-service
3
4# Example output:
5# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
6# mongodb-service LoadBalancer 10.96.142.89 192.168.1.241 27017:31456/TCP 5m
7
8# Describe service for detailed info
9kubectl describe svc mongodb-service

Disabling NodePort Allocation (Kubernetes v1.24+)

For load balancers that route directly to Pods (bypassing NodePorts), you can disable NodePort allocation:

yaml
1apiVersion: v1
2kind: Service
3metadata:
4 name: direct-lb-service
5spec:
6 type: LoadBalancer
7 allocateLoadBalancerNodePorts: false # No NodePort allocated
8 selector:
9 app: myapp
10 ports:
11 - port: 80
12 targetPort: 8080

ExternalName Service

ExternalName Services map a Service to an external DNS name. Instead of proxying traffic, Kubernetes DNS returns a CNAME record pointing to the external hostname. This is useful for:

  • Accessing external databases or APIs
  • Migrating services gradually to Kubernetes
  • Creating consistent internal DNS names for external services
yaml
1apiVersion: v1
2kind: Service
3metadata:
4 name: external-database
5 namespace: production
6spec:
7 type: ExternalName
8 externalName: database.external-provider.com

How ExternalName Works

When a Pod queries external-database.production.svc.cluster.local, the cluster DNS returns a CNAME record pointing to database.external-provider.com. The client then resolves and connects to the external hostname directly.


Headless Services (clusterIP: None)

Headless Services disable the ClusterIP mechanism, allowing direct Pod discovery via DNS. Instead of a single virtual IP, DNS queries return the IP addresses of all backing Pods.

Use Cases for Headless Services

  • StatefulSets requiring stable network identities
  • Databases (Cassandra, MongoDB, MySQL clusters) with client-side load balancing
  • Custom service discovery mechanisms
yaml
1apiVersion: v1
2kind: Service
3metadata:
4 name: cassandra
5 labels:
6 app: cassandra
7spec:
8 clusterIP: None # Makes this a headless service
9 selector:
10 app: cassandra
11 ports:
12 - port: 9042
13 targetPort: 9042

DNS Behavior for Headless Services

bash
1# Standard Service DNS query returns ClusterIP
2nslookup my-service.default.svc.cluster.local
3# Returns: 10.96.0.100
4
5# Headless Service DNS query returns Pod IPs
6nslookup cassandra.default.svc.cluster.local
7# Returns:
8# 10.244.1.5
9# 10.244.2.8
10# 10.244.3.12

Port Forwarding with kubectl

kubectl port-forward creates a secure tunnel from your local machine to a Pod, Service, or Deployment in the cluster. This is essential for debugging and development without exposing services externally.

Port Forward Syntax

bash
1# Forward to a Pod
2kubectl port-forward pod/<pod-name> <local-port>:<pod-port>
3
4# Forward to a Service
5kubectl port-forward svc/<service-name> <local-port>:<service-port>
6
7# Forward to a Deployment
8kubectl port-forward deployment/<deployment-name> <local-port>:<container-port>

Practical Examples

bash
1# Forward local port 8080 to service port 80
2kubectl port-forward svc/frontend 8080:80
3
4# Forward with auto-selected local port
5kubectl port-forward deployment/mongo :27017
6
7# Forward multiple ports
8kubectl port-forward pod/my-pod 8080:80 8443:443
9
10# Run in background
11kubectl port-forward svc/api-gateway 8080:80 &
12
13# Forward from specific address (not just localhost)
14kubectl port-forward --address 0.0.0.0 svc/webapp 8080:80

Port Forward vs NodePort vs LoadBalancer

MethodScopePersistenceUse Case
port-forwardSingle user, localTemporary (session)Development, debugging
NodePortAll nodesPersistentTesting, simple external access
LoadBalancerExternal IPPersistentProduction external access

External IPs

You can expose Services on specific external IPs that route to cluster nodes, regardless of Service type:

yaml
1apiVersion: v1
2kind: Service
3metadata:
4 name: my-service
5spec:
6 selector:
7 app: myapp
8 ports:
9 - protocol: TCP
10 port: 80
11 targetPort: 8080
12 externalIPs:
13 - 198.51.100.32
14 - 198.51.100.33

When traffic arrives at 198.51.100.32:80, Kubernetes routes it to the Service's endpoints.


Multi-Port Services

Services can expose multiple ports, useful for applications that listen on different ports for different protocols:

yaml
1apiVersion: v1
2kind: Service
3metadata:
4 name: multi-port-service
5spec:
6 selector:
7 app: myapp
8 ports:
9 - name: http # Name required for multi-port services
10 protocol: TCP
11 port: 80
12 targetPort: 8080
13 - name: https
14 protocol: TCP
15 port: 443
16 targetPort: 8443
17 - name: metrics
18 protocol: TCP
19 port: 9090
20 targetPort: 9090

Troubleshooting Services

Common Diagnostic Commands

bash
1# List all services
2kubectl get svc -A
3
4# Describe service for events and endpoints
5kubectl describe svc <service-name>
6
7# Check endpoints (should list Pod IPs if selector matches)
8kubectl get endpoints <service-name>
9
10# Check if Pods match the Service selector
11kubectl get pods -l app=nginx
12
13# Test service DNS resolution from a Pod
14kubectl run -it --rm debug --image=busybox -- nslookup nginx-service
15
16# Test connectivity from within cluster
17kubectl run -it --rm debug --image=curlimages/curl -- curl http://nginx-service:80

Common Issues and Solutions

IssueCauseSolution
No endpointsSelector doesn't match Pod labelsVerify labels with kubectl get pods --show-labels
External IP pendingNo LoadBalancer controllerInstall MetalLB or use NodePort
Connection refusedtargetPort incorrectCheck Pod's container port
DNS not resolvingCoreDNS issuesCheck kubectl get pods -n kube-system -l k8s-app=kube-dns