Mastering Kubernetes Services: From Creation to External Exposure
This article explains Kubernetes services in depth, covering how to create services, configure session affinity, expose multiple ports, use named ports, discover services via environment variables and DNS, expose services externally with NodePort, LoadBalancer, and Ingress, and set up readiness probes for pods.
Preface
Previously we introduced the Kubernetes replica mechanism, which keeps deployments running and healthy automatically. This article continues with another powerful Kubernetes feature: services, which provide a stable access point between clients and pods.
Service
A Kubernetes Service offers a single, immutable access point for a set of identical pods. Its IP address and port remain constant, and client connections are load‑balanced across the pods selected by the service’s label selector.
1. Create a Service
Service connections are load‑balanced across all backend pods. The selector in the Service definition determines which pods belong to the service.
[d:\k8s]$ kubectl create -f kubia-rc.yaml
replicationcontroller/kubia created
[d:\k8s]$ kubectl get pod
NAME READY STATUS RESTARTS AGE
kubia-6dxn7 0/1 ContainerCreating 0 4s
kubia-fhxht 0/1 ContainerCreating 0 4s
kubia-fpvc7 0/1 ContainerCreating 0 4sUsing the previous pod YAML (label app: kubia), the Service YAML must specify the same label:
apiVersion: v1
kind: Service
metadata:
name: kubia
spec:
ports:
- port: 80
targetPort: 8080
selector:
app: kubiaThe Service defines two ports: port (exposed by the Service) and targetPort (the pod’s listening port). Pods are selected by matching labels.
[d:\k8s]$ kubectl create -f kubia-svc.yaml
service/kubia created
[d:\k8s]$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d15h
kubia ClusterIP 10.96.191.193 <none> 80/TCP 4s
[d:\k8s]$ kubectl exec kubia-6dxn7 -- curl -s http://10.96.191.193
You've hit kubia-fhxhtAfter creating the Service, a stable internal CLUSTER‑IP is assigned. Requests are routed to any pod; to force sticky sessions, set sessionAffinity: ClientIP.
1.1 Configure Session Affinity
apiVersion: v1
kind: Service
metadata:
name: kubia
spec:
sessionAffinity: ClientIP
ports:
- port: 80
targetPort: 8080
selector:
app: kubiaOnly the sessionAffinity field changes.
[d:\k8s]$ kubectl delete svc kubia
service "kubia" deleted
[d:\k8s]$ kubectl create -f kubia-svc-client-ip-session-affinity.yaml
service/kubia created
[d:\k8s]$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d15h
kubia ClusterIP 10.96.51.99 <none> 80/TCP 25s1.2 Expose Multiple Ports
If a pod listens on multiple ports, a Service can expose them all:
apiVersion: v1
kind: Service
metadata:
name: kubia
spec:
ports:
- name: http
port: 80
targetPort: 8080
- name: https
port: 443
targetPort: 8080
selector:
app: kubiaBoth ports map to the same target port (8080) in this example.
[d:\k8s]$ kubectl create -f kubia-svc-named-ports.yaml
service/kubia created
[d:\k8s]$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6d18h
kubia ClusterIP 10.96.13.178 <none> 80/TCP,443/TCP 7sBoth ports are reachable.
1.3 Use Named Ports
Define a named port in the pod template and refer to it in the Service:
apiVersion: v1
kind: ReplicationController
metadata:
name: kubia
spec:
replicas: 3
selector:
app: kubia
template:
metadata:
labels:
app: kubia
spec:
containers:
- name: kubia
image: ksfzhaohui/kubia
ports:
- name: http
containerPort: 8080 apiVersion: v1
kind: Service
metadata:
name: kubia
spec:
ports:
- port: 80
targetPort: http
selector:
app: kubia2. Service Discovery
2.1 Environment Variables
When a pod starts, Kubernetes injects environment variables for existing services. If the Service is created before the pod, the pod can read KUBERNETES_SERVICE_HOST and KUBERNETES_SERVICE_PORT to obtain the Service IP and port.
[d:\k8s]$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 7d14h
kubia ClusterIP 10.96.106.37 <none> 80/TCP 14h
[d:\k8s]$ kubectl exec kubia-4m9nv env
HOSTNAME=kubia-4m9nv
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
...If the pod is recreated after the Service, additional variables such as KUBIA_SERVICE_HOST and KUBIA_SERVICE_PORT appear.
2.2 DNS
Kubernetes runs a DNS service (coredns) that resolves Service names to their Cluster IPs. Pods can reach a Service via its fully qualified domain name, e.g., kubia.default.svc.cluster.local.
[d:\k8s]$ kubectl exec kubia-599v9 -- curl -s http://kubia.default.svc.cluster.local
You've hit kubia-8s8j4Within the same namespace, the short name kubia also works.
2.3 Run Shell Inside a Pod
d:\k8s> winpty kubectl exec -it kubia-599v9 -- sh
# curl -s http://kubia
You've hit kubia-dm6kr
# exitConnecting to External Services
Kubernetes Services can also proxy to external endpoints via the Endpoint resource or ExternalName.
1. Endpoint Resource
Endpoints sit between Services and Pods, listing the IPs and ports of the actual backends.
apiVersion: v1
kind: Service
metadata:
name: external-service
spec:
ports:
- port: 80Because no selector is defined, the Service has no Endpoints initially.
[d:\k8s]$ kubectl create -f external-service.yaml
service/external-service created
[d:\k8s]$ kubectl describe svc external-service
Endpoints: <none>Manually create matching Endpoints:
apiVersion: v1
kind: Endpoints
metadata:
name: external-service
subsets:
- addresses:
- ip: 172.17.0.9
- ip: 172.17.0.10
ports:
- port: 8080 [d:\k8s]$ kubectl create -f external-service-endpoints.yaml
endpoints/external-service created
[d:\k8s]$ kubectl describe svc external-service
Endpoints: 172.17.0.10:8080,172.17.0.9:80802. External Endpoint (External IP)
Endpoints can also point to an external IP, e.g., a Tomcat server at 10.13.82.21:8080.
apiVersion: v1
kind: Endpoints
metadata:
name: external-service
subsets:
- addresses:
- ip: 10.13.82.21
ports:
- port: 8080 [d:\k8s]$ kubectl create -f external-service-endpoints2.yaml
endpoints/external-service created
[d:\k8s]$ kubectl create -f external-service.yaml
service/external-service created
[d:\k8s]$ kubectl exec kubia-599v9 -- curl -s http://external-service
ok3. ExternalName Service
Define a Service of type ExternalName that maps a DNS name to an external service.
apiVersion: v1
kind: Service
metadata:
name: external-service
spec:
type: ExternalName
externalName: api.ksfzhaohui.com
ports:
- port: 80 [d:\k8s]$ kubectl create -f external-service-externalname.yaml
service/external-service created
[d:\k8s]$ kubectl exec kubia-599v9 -- curl -s http://external-service:8080
okExposing Services to External Clients
1. NodePort
Expose a Service on a static port on every node.
apiVersion: v1
kind: Service
metadata:
name: kubia-nodeport
spec:
type: NodePort
ports:
- port: 80
targetPort: 8080
nodePort: 30123
selector:
app: kubia [d:\k8s]$ kubectl create -f kubia-svc-nodeport.yaml
service/kubia-nodeport created
[d:\k8s]$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubia-nodeport NodePort 10.96.59.16 <none> 80:30123/TCP 3sAccess the Service via the node’s IP (e.g., Minikube’s 192.168.99.108) and the NodePort.
2. LoadBalancer
Creates an external load balancer (cloud provider) and a NodePort.
apiVersion: v1
kind: Service
metadata:
name: kubia-loadbalancer
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 8080
selector:
app: kubia [d:\k8s]$ kubectl create -f kubia-svc-loadbalancer.yaml
service/kubia-loadbalancer created
[d:\k8s]$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubia-loadbalancer LoadBalancer 10.96.207.113 <pending> 80:30038/TCP 7sIn Minikube the EXTERNAL‑IP stays pending.
3. Reduce Unnecessary Network Hops
Set externalTrafficPolicy: Local so that external traffic is only forwarded to pods on the same node.
apiVersion: v1
kind: Service
metadata:
name: kubia-nodeport-onlylocal
spec:
type: NodePort
externalTrafficPolicy: Local
ports:
- port: 80
targetPort: 8080
nodePort: 30124
selector:
app: kubia4. Ingress
Ingress provides HTTP routing based on host and path, using a single external IP.
4.1 Ingress Controller
Enable the Ingress addon in Minikube and verify the controller pod is running.
minikube addons enable ingress
kubectl get pods -n kube-system
... nginx-ingress-controller ... Running ...4.2 Ingress Resource
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: kubia
spec:
rules:
- host: kubia.example.com
http:
paths:
- path: /
backend:
serviceName: kubia-nodeport
servicePort: 80 [d:\k8s]$ kubectl create -f kubia-ingress.yaml
ingress.extensions/kubia created
[d:\k8s]$ kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
kubia kubia.example.com 192.168.99.108 80 6m4sMap kubia.example.com to the node IP in /etc/hosts to test.
4.3 Expose Multiple Services
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: kubia2
spec:
rules:
- host: kubia.example.com
http:
paths:
- path: /v1
backend:
serviceName: kubia-nodeport
servicePort: 80
- path: /v2
backend:
serviceName: kubia-nodeport
servicePort: 80
- host: kubia2.example.com
http:
paths:
- path: /
backend:
serviceName: kubia-nodeport
servicePort: 80 [d:\k8s]$ kubectl create -f kubia-ingress2.yaml
ingress.extensions/kubia2 created
[d:\k8s]$ kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
kubia2 kubia.example.com,kubia2.example.com 192.168.99.108 80 15m4.4 TLS Termination
Generate a TLS secret and reference it in the Ingress.
# openssl genrsa -out tls.key 2048
# openssl req -new -x509 -key tls.key -out tls.cert -days 360 -subj /CN=kubia.example.com
kubectl create secret tls tls-secret --cert=tls.cert --key=tls.key apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: kubia
spec:
tls:
- hosts:
- kubia.example.com
secretName: tls-secret
rules:
- host: kubia.example.com
http:
paths:
- path: /
backend:
serviceName: kubia-nodeport
servicePort: 80 [d:\k8s]$ kubectl apply -f kubia-ingress-tls.yaml
ingress.extensions/kubia configuredAccess via https://kubia.example.com to see the TLS‑secured endpoint.
Pod Readiness Probes
Readiness probes determine whether a pod can receive traffic. Types include exec, httpGet, and tcpSocket. Pods failing the probe are removed from Service endpoints until they become ready.
1. Types of Readiness Probes
Exec probe – runs a command inside the container; success is indicated by exit code 0.
HTTP GET probe – sends an HTTP request; success is indicated by a 2xx/3xx status code.
TCP socket probe – attempts a TCP connection; success if the connection is established.
2. Adding a Readiness Probe
Edit the ReplicationController to include an exec probe that checks for the file /var/ready:
apiVersion: v1
kind: ReplicationController
metadata:
name: kubia
spec:
replicas: 3
selector:
app: kubia
template:
metadata:
labels:
app: kubia
spec:
containers:
- name: kubia
image: ksfzhaohui/kubia
ports:
- containerPort: 8080
readinessProbe:
exec:
command:
- ls
- /var/readyWhen a new pod is created, it will stay in READY 0/1 until the probe succeeds.
Summary
The article introduced the fundamentals of Kubernetes Services, how to create and discover them, how to link Services to internal and external endpoints, and three primary ways to expose Services to external clients (NodePort, LoadBalancer, Ingress). It also covered configuring session affinity, multiple ports, named ports, and readiness probes to ensure only ready pods receive traffic.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
MaGe Linux Operations
Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
