Chapter 5
Section titled “Chapter 5”Let’s dive into our final chapter for this series. This topic is one of the most powerful in Kubernetes and is essential for running complex applications. So far, we have a clear distinction:
Deploymentsare for stateless applications (a web server where any Pod is identical to any other).Jobsare for batch tasks (run-to-completion).
But what about the most complex category: stateful applications like databases (e.g., MySQL, PostgreSQL), message queues (e.g., Kafka, RabbitMQ), or any clustered software where each member has a unique identity and state?
Using a
Deploymentfor a database is problematic. Pods get random hostnames, and when one is replaced, the new Pod has a completely new identity and a different IP address. It can’t easily rejoin the database cluster because the other members don’t recognize it. For these applications, we need stability and predictability.
Managing Stateful Applications with StatefulSets
Section titled “Managing Stateful Applications with StatefulSets”A StatefulSet is a Kubernetes workload object, like a Deployment, but it’s specifically designed to manage stateful applications. It provides strong guarantees about the identity and ordering of its Pods, which Deployments do not.
Here are the key features that make a StatefulSet unique:
- Stable, Unique Network Identifiers: Each Pod in a StatefulSet gets a predictable, persistent hostname. The pattern is always
(<statefulset-name>)-<ordinal-index>. For example, if your StatefulSet is namedweb, its Pods will be namedweb-0,web-1,web-2, and so on. This name sticks to the Pod, even if it’s restarted or rescheduled to a different Node. - Stable, Persistent Storage: Each Pod gets its own unique
PersistentVolumeClaimbased on a template. The PVC forweb-0is not the same as the PVC forweb-1. When a Pod is rescheduled, it always re-attaches to its original storage volume, ensuring it retains its unique state. - Ordered, Graceful Deployment and Scaling:
- Deployment: When you scale up a StatefulSet from 0 to 3 replicas, it happens in strict order.
web-0will be created and must become “Ready” beforeweb-1is even created.web-1must be ready beforeweb-2is created. - Deletion: When you scale down from 3 to 0, the deletion happens in the reverse order:
web-2is terminated first, thenweb-1, thenweb-0. This ordered orchestration is critical for clustered applications that need to rebalance data gracefully.
- Deployment: When you scale up a StatefulSet from 0 to 3 replicas, it happens in strict order.
Headless Services: The Prerequisite
Section titled “Headless Services: The Prerequisite”A StatefulSet requires a Headless Service to control the network domain for its Pods.
A normal Service gets a single, stable IP (ClusterIP) and load-balances traffic among all its backing Pods.
A Headless Service is created by setting clusterIP: None in the Service definition. It does not get a ClusterIP and does not perform load balancing. Instead, it creates DNS records that point directly to the IP addresses of each individual Pod in the StatefulSet. This is what allows you to connect directly to web-0.my-service or web-1.my-service.
-
Create the Headless Service This service will define the network identity for our Pods. Create a file named
headless-service.yaml:headless-service.yaml apiVersion: v1kind: Servicemetadata:name: my-stateful-app-svcspec:# Setting clusterIP to None makes this a "headless" service.clusterIP: Noneselector:app: my-stateful-appports:- protocol: TCPport: 80targetPort: 80Apply it:
Terminal window kubectl apply -f headless-service.yaml -
Create the StatefulSet This StatefulSet will run Nginx, but we’ll use a small command to make each Pod display its own unique hostname.
Create a file named
statefulset.yaml:statefulset.yaml apiVersion: apps/v1kind: StatefulSetmetadata:name: my-stateful-appspec:# The selector must match the labels of the pod template.selector:matchLabels:app: my-stateful-app# This must match the name of our Headless Service.serviceName: "my-stateful-app-svc"replicas: 3template:metadata:labels:app: my-stateful-appspec:containers:- name: nginximage: nginx:1.21.6# This command replaces the default nginx page with one that shows the pod's hostnamecommand: ["/bin/sh", "-c", "echo \"My hostname is $(hostname)\" > /usr/share/nginx/html/index.html && nginx -g 'daemon off;'"]ports:- containerPort: 80Apply it and immediately watch the Pods being created:
Terminal window kubectl apply -f statefulset.yamlkubectl get pods -wYou will see
my-stateful-app-0being created first. Only after it becomesRunningandReadywillmy-stateful-app-1start creating. The process repeats formy-stateful-app-2. This is the ordered deployment in action. -
Test the Stable Network Identities Let’s verify that each Pod has a unique and resolvable DNS name. We’ll launch a temporary pod to act as our client.
Terminal window kubectl run client-pod --image=busybox:1.36 --rm -it -- /bin/shOnce you are inside the client pod’s shell, use
wgetto query each of the stateful pods by their unique DNS name. The DNS name is<pod-name>.<service-name>:Terminal window # Inside the client-pod shell# Query the first podwget -q -O - my-stateful-app-0.my-stateful-app-svc# You will see the output: My hostname is my-stateful-app-0# Query the second podwget -q -O - my-stateful-app-1.my-stateful-app-svc# You will see the output: My hostname is my-stateful-app-1exitThis proves that each Pod is individually addressable via the Headless Service.
-
Observe Ordered Scaling Let’s scale the StatefulSet down from 3 replicas to 1.
Terminal window kubectl scale statefulset my-stateful-app --replicas=1Watch the pods with
kubectl get pods -w. You will seemy-stateful-app-2terminate first. Once it’s gone,my-stateful-app-1will terminate, leaving onlymy-stateful-app-0running. This reverse-order termination is critical for gracefully shutting down clustered applications. -
Clean Up
Terminal window kubectl delete statefulset my-stateful-appkubectl delete service my-stateful-app-svc
Key Takeaways for Chapter 5:
Section titled “Key Takeaways for Chapter 5:”- Use a Deployment for stateless applications where identity doesn’t matter.
- Use a StatefulSet for stateful applications like databases, message queues, and other clustered services that require stable identity and ordered operations.
- StatefulSets provide stable hostnames, stable storage, and ordered deployment/scaling.
- A StatefulSet always needs a corresponding Headless Service to provide the network DNS entries for its Pods.
This concludes our advanced-core concepts series! You now have a much more robust and production-oriented understanding of how to manage a wide variety of application types on Kubernetes.