Weaveworks 2022.03 release featuring Magalix PaC | Learn more
Balance innovation and agility with security and compliance
risks using a 3-step process across all cloud infrastructure.
Step up business agility without compromising
security or compliance
Everything you need to become a Kubernetes expert.
Always for free!
Everything you need to know about Magalix
culture and much more
In this article, we’ll be exploring various Kubernetes objects in order to understand what they’re used for and the different options they give you. This article doesn’t go into every detail of objects, that would be way too much to cover in one article. However, after reading the article, you’ll have a clear understanding of objects, know when to use each, and their respective perks.
We’ll also look at some examples of how to create these objects. Even though there are several ways to create objects, we’ll be using YAML manifests so that we can have a clear understanding of the different object options and their use cases.
To practice with some examples that you’ll see in this article, you’ll need to have Kubernetes setup on your computer or use an online Kubernetes tool. We recommend you use the Kubernetes environment from www.katacoda.com. It’s a free interactive environment for practicing with different technologies.
Because Kubernetes uses similar commands for creating and getting objects, we’ll provide the various commands that you can use to create and get the objects we’ll be discussing.
kubectl apply -f ./application-pod.yaml
kubectl describe pod application-pod
kubectl get deployment production
Kubectl get-pods --all-namespaces
Even though we used pods here as our examples, you can use these commands to get and describe the various objects we’re discussing.
So, to test an object we’ve discussed, just create a YAML file for it, then use the command for creating the object above, then you can use any of the gets or describe commands to see the object you’ve created.
Kubernetes objects are entities provided by Kubernetes for deploying, maintaining, and scaling applications either on cloud or on-premise infrastructure. In this section, we’ll be discussing the most common Kubernetes objects that you’ll use in your deployments.
A pod is the most basic unit of the Kubernetes cluster. It usually contains one or more running containers. Pods are designed to be ephemeral in nature which means that they can be destroyed at any time. Containers in a pod share the same network, storage, and lifecycle. What this means is that they can communicate with each other directly, and will both be stopped and started at the same time.
Pod Definition:
apiVersion: v1
kind: Pod
metadata:
name: first-pod
labels:
name: first-pod
app: hello-world-app
spec:
containers:
- image: hello-world
name: first-pod
ports:
- containerPort: 8080
protocol: TCP
Let’s break down and try to understand the pod definition we just created.
- apiVersion: This refers to the version of Kubernetes. There are several versions, and several objects are introduced with each version. Some common ones are v1, apps/v1, and extensions/v1beta1. You can check out the official Kubernetes documentation for the list of versions.
- Kind: This is the type of Kubernetes object. In this case (the example above), we’re creating a pod.
- Metadata: The metadata houses information that describes the object briefly. The information in the metadata usually contains the name you want to give the object (pod in our case), the labels, and the annotation. For the labels, you can define as many labels as you want, and you aren’t restricted to words to use as labels.
- Spec: The spec section is where you define the desired state of your object. In the case of a pod, it’s where you describe the state of your container. Some options you can specify in the spec section are:
Now, let’s create a pod with the pod definition:
kubectl apply -f first-pod.yaml
kubectl get pods
kubectl describe first-pod
A pod passes through several phases in its lifetime. These phases are unknown, pending, running, succeeded, and failed.
If the pod is in the unknown state, it means the pod’s status could not be obtained.
To check the state of a pod, use the kubectl describe pod <pod name> and check for phase under the status section.
The Replication Controller is used to create multiple copies of the same pod in a Kubernetes cluster. It helps ensure that at any given time, the desired number of pods specified are in the running state. If a pod stops or dies, the ReplicationController creates another one to replace it.
apiVersion: v1
kind: ReplicationController
metadata:
name: myapp
spec:
replicas: 2
selector:
app: myapp
template:
metadata:
name: first-pod
labels:
name: first-pod
app: hello-world-app
spec:
containers:
- image: hello-world
name: first-pod
ports:
- containerPort: 8080
protocol: TCP
As you can see in our definition for the replication controller, the kind is ReplicationController, and under the spec, it says replicas: 2. This means that at any given time, if the application is healthy, 2 pods running your application container will be up. If any of the pods fail, the replication controller will immediately create another one to replace it.
The template section provides the characteristics of your pod. If you look at the spec section of our first pod definition, you’ll see that it looks just like the template section for the Replication Controller.
The Replicaset is the replacement for the Replication controller. They both perform the same functions. However, the Replicaset is much more powerful than the replication controller.
One of the major differences between a replicaset and replication controller is labels. Replication controllers use labels specified under the selector section while replicasets use matchLabels specified under the selector option. The implication of this is that replication controllers can only references pods whose key and value pair match. For example, if you specify environment: production under selector, any pod with that label will be matched but any other pod whose key is not environment, or value is not production, will not be matched. The replicaset on the other hand will match all pods with the same key, regardless of the value. For example, a replicaset with the key environment and value production will match any other pod with the key environment and those pods will be grouped. The selector is not required for replication controllers, but it is compulsory for replicasets.
Another difference between replication controllers and replicasets is the method used to update them. The replication controllers use the rolling update mechanism which means that the pod templates are changed for each pod, one at a time, until all the pods have been updated. Replicasets on the other hand, use the rollout approach. They are meant to serve as the backends for Deployments and implement the rolling update. Replicasets are not meant to be created on their own, but automatically when deployments are created.
Replication Controllers also belong to the V1 API version of Kubernetes while replicasets belong to the apps/V1 API version.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google_samples/gb-frontend:v3
Deployments are Kubernetes objects that are used for managing pods. The first thing a Deployment does when it’s created is to create a replicaset. The replicaset creates pods according to the number specified in the replica option. If you look at the YAML definition for the Deployment below, you’ll notice that the spec section of the deployment looks just like the definition for a replicaset.
Deployments can be used to scale your application by increasing the number of running pods, or update the running application.
A Kubernetes Deployment can be in either of 3 states during its lifecycle.
The progressing state indicates that the deployment is still working on creating or scaling the pods. The completed state indicates that the deployment has finished its task successfully, while the failed state indicates that an error occurred with the deployment.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
DaemonSet is another Kubernetes object that’s used for managing pods. DaemonSets are used when you want to make sure that a particular pod runs on all nodes that belong to a cluster. This is helpful in situations where you want to run a monitoring or logging application on the nodes in the cluster.
As soon as a node is added, to the cluster, DaemonSet spins up the pod in the node and destroys the pod as soon as the node exits.
In his article Kubernetes DaemonSets 101, Mohamed Ahmed provides a detailed explanation of DaemonSets and how to work with them.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
In the YAML above that describes the DaemonSet, we see that it has a namespace and we’ll be sure to talk more in-depth about namespaces later. We also see that it has two spec attributes: the first spec is for the DaemonSet, the second describes the pod.
Now, let’s take a look at the attributes that are in the pod spec:
- Tolerations: To understand tolerations, we have to look at another Kubernetes concept - taints. Taints are a way of indicating to the Kubernetes Scheduler that pods shouldn’t be scheduled on a particular node. The Kubernetes Scheduler is responsible for placing created pods in different nodes. When you put a taint on a node, you’re putting a mark on the node that tells the Kubernetes Scheduler to ignore that node. Only pods that have tolerance for that taint will be scheduled on that node. So toleration is just a way of ignoring the taints on a node in order to allow the pod to be scheduled on that node. You can taint a node by running the following command:
kubectl taint nodes my_node tainted=true:NoSchedule
To tolerate this taint, you have to add a toleration option to your pod.
toleration:
Key: "tainted"
Value: "true"
Effect: "NoSchedule"
- Resources: The resource section is used to define specifications for the amount of resources the pod should consume in terms of the CPU and RAM of the node. This is important because containers need enough resources to be able to run without errors. On the other hand, some containers can take so many resources that they starve other containers of needed resources.
In his article Influencing Kubernetes Scheduler Decisions, Mohamed Ahmed talks extensively on managing resources in Kubernetes.
- VolumeMounts: Containers are ephemeral in nature - this means that once a container is terminated, all the data generated while the container was running will be lost. Sometimes, we may want to preserve the data generated by the container, that is where Volumes come in handy. A volume is just a location (directory) in your pod where all of your container’s data is being stored. It’s important to know that some volumes share the same lifecycle as the pod - an example is emptyDir. This means that the volumes are created and terminated with the pods. If you want to store your data permanently, you would have to look for an alternative storage solution. There are other volumes that are not terminated with the pods; an example is the awsElasticBlockStore which is merely mounted and will be unmounted once the pod is destroyed thus preserving its content.
You can find all the types of the Kubernetes volumes in the official Kubernetes documentation. You’ll also find this article Kubernetes Storage 101, by Mohamed Ahmed enlightening and very helpful.
A volume mount is a way of associating a particular volume with a container.
Volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
In the above snippet from our original DaemonSet definition, you’ll notice that two volumes are defined. The first is a hostPath type of volume named varlog, and the second is also a hostPath volume, named varlibdockercontainers.
The hostPath volume uses the storage of your host computer, or node, to store the data associated with the volume. You can use a directory on your computer as the volume and mount it on the container. One of the use cases of the hostPath is when we need our containers to access data from docker internals as you see in the volume definition above.
- terminationGracePeriodSeconds: Kubernetes offers us a grace period before our pods are terminated. The default grace period is 30 seconds. The process for terminating a pod follows this order:
The terminationGracePeriodSeconds option specified in the pod template of the DaemonSet is used for extending or decreasing that grace period.
Namespaces are used to organize objects in a Kubernetes cluster. They enable you to group resources together and perform actions on those resources. One of the use cases can be the creation of different environments (staging and development) for your deployed application. For example, you can create a deployment called backend-application with the staging namespace and deploy the same application in another namespace called production. While both deployments have the same name, there are no conflicts because of the difference in their namespaces.
apiVersion: v1
kind: Namespace
metadata:
name: production
_ _ _
apiVersion: v1
kind: Namespace
metadata:
name: staging
To use a namespace, create it and then reference it in the metadata section of your Kubernetes objects:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
Spec:
ConfigMaps are used to separate configuration data from containers in your Kubernetes application. They offer you the ability to dynamically change data for containers at runtime. It’s important to note that ConfigMaps are meant to be used for storing sensitive information. If the data you want to pass to your application is sensitive, then it is recommended you use Secrets instead.
You can create ConfigMaps from literals (key-value pairs), files, or even directories.
- Create ConfigMaps from a directory: To properly understand this, we’ll look at an example. Follow these steps:
kubectl create configmap people-config --from-file=people_config/
After running the above command, run:
Kubectl describe configmap people-config
The above command will provide a verbose description of the ConfigMaps you just created.
- Create ConfigMaps from files: The approach is the same as the one for creating ConfigMaps from a directory. But in this case, we specify the file path instead of a folder.
Kubectl create configmap boys-config --from-file=people_config/boys.txt
Create ConfigMaps from literals: To create a ConfigMap from a literal, you can use the following commands:
Kubectl create configmap boy-config --from-literal=name=Samuel --from-literal=gender=male --from-literal=age=13
To consume a ConfigMap in a pod, you simply reference it using the configMapRef option:
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- configMapRef:
name: people-config
restartPolicy: Never
To inject the ConfigMap values into the command line, you have to specify the keys you want to be consumed using the configMapKeyRef.
apiVersion: v1
kind: Pod
metadata:
name: dapi-test-pod
spec:
containers:
- name: test-container
image: k8s.gcr.io/busybox
command: [ "/bin/sh", "-c", "env" ]
env:
- name: MALE_AGE
valueFrom:
configMapKeyRef:
name: people-config
Key: age
restartPolicy: Never
You can also generate ConfigMaps using a generator, but we’ll discuss that in another segment. You can also look at the official Kubernetes documentation for more information.
David Essien is a part of the Magalix Write For Cloud-Native Community Expert Program, and Can be Found On Social Media at Linkedin, Twitter, and Github
Empower developers to delivery secure and compliant software with trusted application delivery and policy as code. Learn more.
Automate your deployments with continuous application delivery and GitOps. Read this blog to learn more.
This article explains the differences between hybrid and multi-cloud model and how GitOps is an effective way of managing these approaches. Learn more.
Implement the proper governance and operational excellence in your Kubernetes clusters.
Comments and Responses