All Blog Posts

How to K8s: Pods, ReplicaSets, and Deployments

Diagram depicting Kubernetes deployment, replica sets and pods
Looking for more of our How to K8s series? Join us on September 23rd at 12 PM EDT/9 AM PDT for our How to K8s: Shipping macOS Logs in Kubernetes.  

In the upcoming webinar, MacStadium's iOS DevOps Coach, John Cabaniss, will walk us through, step-by-step how to get and ship basic macOS build metrics, then log and ship platform-level metrics in Kubernetes using the Orka system, all with fluentD. Reserve your spot now!

There are a fair few abstractions in Kubernetes and today, we’ll run through an overview of three flavors of compute resources available in Kubernetes – Pods, ReplicaSets, and Deployments. We’ll break them out in terms of relative complexity and why you might choose one over the others for a given use case.

Pods

Pods are the most fundamental compute resource that you can stand up in Kubernetes. Put simply, if you use Kubernetes, you will be using pods. Contrary to popular belief among those just starting out with Kubernetes, pods are not the Kubernetes equivalent to Docker containers. Instead, pods are responsible for running a container engine that can then, in turn, run one or more containers inside of the pod. It is worth noting that Docker isn’t the only compatible container engine, but it is by far the most popular choice.  

Pods are defined in YAML files, which are called from the command line with the kubectl CLI, like so:

kubectl apply -f pod_example.yml

A sample pod definition would look something like this:

apiVersion: v1
kind: Pod
metadata:
name: chef-server
spec:
containers:
  - name: chef-server
    image: chef/chefdk
    command: ["/bin/sh"]
    args: ["-c", "echo Hello from the Ubuntu container; sleep 1000"]

Key pieces in the above YAML file include the name of our container and the Docker hub image that we want Kubernetes to pull when the pod starts up.

When to use pods

Using standalone pods is generally frowned upon except for quick testing, as there is nothing in place to monitor the health of the pod. This means that if a pod (or its host node) should fail for some reason, there won’t be any mechanism in place to stand it back up, which is really where the power of Kubernetes lies.

ReplicaSets

ReplicaSets are higher-level abstractions that are responsible for ensuring that a specified number of exact copies of a given pod are running. This system of parallelization is the foundation of Kubernetes' power. If for some reason, one or more copies of chef-server that we mentioned above should fail, our server will still be available for two reasons: (1) there are multiple, identical pods running, and (2) the ReplicaSet will create a new pod in place of the one that failed. Moreover, we can be guaranteed that we will end up with the exact number of pods we’ve requested, as any extras will be torn down.

Like pods, ReplicaSets are defined in a YAML file that can be executed from the command line, like so:

kubectl apply -f replica_set_example.yml

And, an example of that YAML file might look like the following:

apiVersion: apps/v1
kind: ReplicaSet
metadata:
 name: chef-server
 labels:
   app: chef-server
   tier: chef-server
spec:
 replicas: 3 # We'll get three identical pods
 selector:
   matchLabels:
     tier: chef-server
 template:
   metadata:
     labels:
       tier: chef-server
   spec:
     containers:
     - name: chef-server
       image: chef/chefdk
       command: ["/bin/sh"]
       args: ["-c", "echo Hello from the Ubuntu container; sleep 1000"]

A couple of critical points in the above YAML file include our replicas count – i.e., the number of copies of this pod that we want it to maintain, as well as the alignment of our labels, which will allow the Kubernetes controller to keep track of the pods in the ReplicaSet.

When to use ReplicaSets

Interestingly, ReplicaSets are considered more of a building block in Kubernetes than an end unto themselves. The Kubernetes docs are pretty explicit about this – “you may never need to manipulate ReplicaSet objects: use a Deployment instead, and define your application in the spec section.” ← Add link to this page in the Kubernetes docs

Deployments

One step higher in the abstraction hierarchy, deployments control both ReplicaSets and pods in a declarative manner. This means that you define what you want your collection of pods to be, and the deployment makes use of several other Kubernetes objects to ensure that things are as you’ve declared in your YAML file.

This is different than a ReplicaSet in that you can roll out changes to the desired state of the system by changing the pod template in your deployment YAML, and the deployment will take care of the rest. You can also revert to a previous state if things go awry. This contrasts with a ReplicaSet in that if you were to change the ReplicaSet’s YAML, and then run kubectl apply -f <ReplicaSet.yml> your original ReplicaSet will persist. And with that, you’ll be creating a second ReplicaSet.

In the sample file below, you’ll see that we’ve essentially “layered in” pods and a ReplicaSet, as deployments are working with these objects, so you don’t have to.

kubectl apply -f deployment_example.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: chef-server
spec:
replicas: 3
selector:
  matchLabels:
    app: chef-server
template:
  metadata:
    labels:
      app: chef-server
  spec:
    containers:
    - name: chef-server
      image: chef/chefdk
      ports:
      - containerPort: 8080
      command: ["/bin/sh"]
      args: ["-c", "echo Hello from the Chef container; sleep 1000"]
    - name: ubuntu
      image: ubuntu:18.04
      ports:
      - containerPort: 8080
      command: ["/bin/sh"]
      args: ["-c", "echo Hello from the Ubuntu container; sleep 1000"]
    securityContext:
      runAsUser: 1

When to use Deployments

The Kubernetes docs explicitly suggest using a deployment rather than a ReplicaSet directly. As such, a deployment is generally the best option for any service that needs to maintain high availability, as it intelligently tears down services in the event of a change to the desired state of the system so that it doesn’t interrupt any service running therein.  

TL;DR

We’ve discussed three “tiers” of complexity above – namely Pods, ReplicaSets, and Deployments. The first building block is a pod, which is, in turn, used in ReplicaSets. Further, both pods and ReplicaSets are used by deployments. Pods are best used for testing only. ReplicaSets are generally considered a “bridge” to deployments – the use of which is generally considered a best practice when using Kubernetes.

You May Also Like

Was this article helpful?

Vote Submitted
Oops! Something went wrong while submitting the form.
Vote Submitted
Oops! Something went wrong while submitting the form.
Return to Blog Home