Certified Kubernetes Administrator Exam Series (Part-4): Application Lifecycle Management
Introduction to Lifecycle Management
When deploying a Kubernetes application into production, there are several strategies to stage and update cluster resources. Users expect the application to be constantly available, while developers also need to be performing constant changes and updates to the application. The most popular strategy involves Rolling Updates- a strategy that ensures High Availability by incrementally replacing POD instances. On the other hand, a Recreate is the older strategy where all PODs of the old version are terminated to give way to newer updated ones.
This section introduces various strategies used to manage the lifecycle of Kubernetes applications, ensuring high availability and continuously improving performance.
Rolling Updates & Rollback
Rollouts and Versioning
When a deployment is created, it triggers a rollout. Every new rollout in turn creates a deployment version, let’s call the first Revision1 (for our reference). When an application is upgraded by updating containers, a new rollout is triggered, creating a newer deployment revision, Revision2. This makes it easy to keep track of changes in the deployment and roll them back whenever necessary.
To create a new rollout, the definition file
myapp-deployment is created with the following configurations:
--- apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deployment labels: app: web spec: replicas: 2 selector: matchLabels: app: web template: metadata: labels: app: web spec: containers: - name: front-end image: nginx ports: - containerPort: 80 - name: rss-reader image: nickchase/rss-php-nginx:v1 ports: - containerPort: 88
To display running deployments, use the command:
$ kubectl get deployment
To check the status of a rollout, the
kubectl rollout status command is used:
$ kubectl rollout status deployment/myapp-deployment
To update the image of the application to nginx:1.17
$ kubectl set image deploy myapp-deployment front-end=nginx:1.17
To view the current image version of the app, run the
describe pods command:
$ kubectl describe pods
In the Image field of the output, verify that you are running the latest image nginx:1.17
To roll back the deployment to your last working version, use the rollout undo command:
$ kubectl rollout undo deployment myapp-deployment
For rollout history:
$ kubectl rollout history deployment/myapp-deployment
There are two kinds of deployment strategies in Kubernetes: The Recreate and Rolling Update Strategies. In the Recreate strategy, all old POD instances are brought down before newer instances are brought up. This introduces a problem of application unavailability during an update.
The recreate strategy can be desirable for a number of reasons:
- When updated applications require prerequisite data and configuration settings
- The POD is mounted with a ReadWriteOnce volume that cannot be shared with other replicas
- The application doesn’t support multiple versions
In a rolling update strategy, POD instances are taken down and replaced one-by-one. This makes the update seamless. Kubernetes assumes rolling updates to be the default rollout strategy and performs such updates when the strategy is not specified.
.spec.strategy specifies the strategy used to replace old Pods by new ones. .spec.strategy.type can be “Recreate” or “RollingUpdate”.
Docker Commands and Arguments
When we run a docker container built on the Ubuntu OS image:
$ docker run ubuntu
This initiates the container run and then exits immediately.
To check the number of running containers using the command:
$ docker ps
The above command will not list stopped containers. For checking all, including stopped containers:
$ docker ps -a
shows it in
Exited state as follows:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f4a947ab4d03 ubuntu "/bin/bash" 58 seconds ago Exited (0) 53 seconds ago pedantic_chaum
This is because containers are made to run specific tasks/processes and not Operating Systems. Once the task is complete, the container exits. A container, therefore, only lives for as long as the task running inside it is alive.
Commands and arguments define the processes that run in a container once it starts. This can be seen in the configuration files for popular Docker images. The
CMD argument for the
nginx image is
[“nginx”]. For the
mysql official image, this argument is
The Ubuntu container that ran earlier is a plain OS image. It uses
[“bash”] as its default
bash is not a process, but it listens for commands from the CLI terminal. If there are no commands from the terminal, the container exits.
One way to override a container’s default commands is to append the
docker run command when initiating the container:
$ docker run ubuntu sleep 5
In the case above, the container will start, run the sleep program, wait for 5 seconds then exit. It is also possible to use the OS as the base image and specify a command in a new Dockerfile. This way, the container will always run this command when it starts. For instance, it is possible to create a Dockerfile named
ubuntu-sleeper with the following specs:
FROM ubuntu CMD sleep 5
CMD arguments can be specified in both
exec forms as:
CMD command param1 for instance
CMD sleep 5.
CMD [“command”, “param”] for instance
CMD [“sleep”, “5”].
The new image can be built using the
docker build command:
$ docker build -t ubuntu-sleeper .
The container is then run using the command:
$ docker run ubuntu-sleeper
By default, a container will always start, run the sleep program, wait for 5 seconds then exit. To change the number of seconds it sleeps, this can be appended to the
docker run command:
$ docker run ubuntu-sleeper sleep 10
In this case, the command that runs at startup is
sleep 10 so the container starts, runs the sleep program, waits for 10 seconds then exits.
If one wants to specify the number of seconds in the command line while the
sleep program executes automatically, it is best to use the
ENTRYPOINT instruction. This instruction specifies the program that executes when the container is running, but the number of seconds can be specified on the command-Line. The Dockerfile for this container would be:
FROM ubuntu ENTRYPOINT ["sleep"]
Running the command
docker run ubuntu-sleeper 10 means that the instruction executed at container runtime is
sleep 10. Running this container without a command-line argument returns a
‘missing operand’ error. To configure the application with a default argument value (number of seconds), it is best to combine
CMD instructions, as in:
FROM Ubuntu ENTRYPOINT ["sleep"] CMD ["5"]
In this case, if no command-line arguments are specified, the
sleep 5 program is executed when the container is running. If an argument is specified on the command line, the
CMD instruction is ignored, for instance:
$ docker run ubuntu-sleeper 10 will run the container with the
sleep 10 program. When it is necessary to modify the
ENTRYPOINT, this can be achieved by appending the
docker run command with the newer
--entrypoint specified as a flag:
$ docker run --entrypoint echo ubuntu-sleeper 10
Kubernetes Commands and Arguments
The previous section explored the configuration of commands and arguments in Dockerfiles using
CMD instructions. In Kubernetes, these instructions can be specified in the definition files for the PODs running these docker containers. Let’s consider the YAML definition file for the
apiVersion: v1 kind: Pod metadata: name: ubuntu-sleeper-pod spec: containers: - name: ubuntu-sleeper image: ubuntu-sleeper args: ["10"]
args field in the POD definition file is the Kubernetes equivalent of the
CMD instruction in a Dockerfile. To represent an
ENTRYPOINT in a POD definition file, the
command field is used:
apiVersion: v1 kind: Pod metadata: name: ubuntu-sleeper-pod spec: containers: - name: ubuntu-sleeper image: ubuntu command: ["sleep"] args: ["10"]
Configuring Environment Variables
Environment variables in Kubernetes are configured using the
env property. This property is an array, and a number of items can be specified under the property. Each item has a
name and a
value property, as shown in the simple POD definition file below:
apiVersion: v1 kind: Pod metadata: name: simple-webapp-color spec: containers: - name: simple-webapp-color image: kodekloud/simple-webapp ports: - containerPort: 8080 env: - name: APP_COLOR value: pink
To list the Pod’s container environment variables:
$ kubectl exec simple-webapp-color -- env
This is known as the
plain key-value of setting environment variables. The variables can also be set using
secrets, which are explored in the coming sections.
In a cluster that uses numerous POD instances, it gets difficult to manage the environment data stored across multiple YAML definition files. Environment variable information can be taken out of individual POD definition files and managed centrally using objects known as configMaps.
These objects store environment data in the form of key-value pairs and pass them to applications when injected into the POD definition files.
ConfigMaps can be created in two ways: imperatively and declaratively.
With the imperative method, the configMap is created by stating the key-value pairs directly in the command line, i.e:
kubectl create configmap \
For instance, we could create the configMap
app-config by running the command:
kubectl create configmap \ <config-name> --from-literal=APP_COLOR=blue \ --from-literal=APP_MOD=prod
If there are many environment variables, the command may get too complex, and the variables can be managed by writing them onto a file imperatively:
kubectl create configmap \ <config-name> --from-file= file-path
Data is read from this file and stored as environment data in the
config-name file. In the declarative method, a YAML file is used to store the configuration data. The configMap specifications for the sample app
simple-webapp-color will be:
apiVersion: v1 kind: ConfigMap metadata: name: app-config data: APP_COLOR: blue APP_MOD: prod
The configMap data is then injected into the POD by specifying it in a YAML definition file as follows:
apiVersion: v1 kind: Pod metadata: name: simple-webapp-color spec: containers: - name: simple-webapp-color image: kodekloud/simple-webapp ports: - containerPort: 8080 envFrom: - configMapRef: name: app-config
To list the Pod’s container environment variables which managed by configMaps:
$ kubectl exec simple-webapp-color -- env
To list the configMaps:
$ kubectl get configmaps
To get the data of the app-config configMap:
$ kubectl describe configmaps app-config
ConfigMaps are great for storing environment data to be used by resources within the Kubernetes cluster. They are, however, not suitable for sensitive data that requires high security. Secrets store information in an encoded format, making them suitable for highly sensitive data.
Just like configMaps, secrets can be created imperative or declaratively.
Let’s assume we are trying to create a secret as follows:
Using the imperative method, a secret is created directly on the command line without the need for a definition file, i.e:
$ kubectl create secret generic \ <secret-name> --from-literal=<key>=<value> \ --from-literal=<key2>=<value2>
To encode the values, the following command is used on a Linux host:
echo -n '<value>' | base64
Since we are trying to encode:
paswrd, our secret values will be
So the imperative command will be:
$ kubectl create secret generic \ app-secret --from-literal=DB_Host=bXlzcWw= \ --from-literal=DB_User=cm9vdA== \ --from-literal=DB_Passowrd=cGFzd3Jk
This command also gets complicated when there are numerous environment variables to specify. The secrets can also be written onto files, as follows:
$ kubectl create secret \ <secret-name> --from-file= file-path
Using the declarative method, the secret is first created in a YAML definition file:
apiVersion: v1 kind: Secret metadata: name: app-secret data: DB_Host: bXlzcWw= DB_User: cm9vdA== DB-Password: cGFzd3Jk
The secret is then created by running the command:
$ kubectl create -f secret-data.yaml
To view secrets, use the command:
$ kubectl get secrets
The newly created secret can be inspected using the command:
$ kubectl describe secrets
To get the secrets as presented in YAML format:
$ kubectl get secret app-secret -o yaml
The secrets can be decoded back to plain text format by running the following command on a Linux host:
$ echo -n '<value>' | base64 --decode
To inject a secret into a POD, it is specified as
envFrom in the POD definition file:
apiVersion: v1 kind: Pod metadata: name: simple-webapp-color spec: containers: - name: simple-webapp-color image: kodekloud/simple-webapp ports: - containerPort: 8080 envFrom: - secretRef: name: app-secret
To list the Pod’s container environment variables:
$ kubectl exec simple-webapp-color -- env
Microservices architecture allows for the creation of light, agile and reusable code. This makes it easy to scale the application up and down, and easily manage deployments by updating only those services requiring an upgrade. In some cases, services may need to work together without having to be merged. While they operate with the same number of replicas, they are developed and deployed independently. Deploying these services in Multi-Container PODs will result in them sharing resources and a lifecycle, making it easier to communicate since they can refer to each other as
To create a multi-container POD, the new container’s information is added to the
containers section under
spec in the POD definition file, as shown:
apiVersion: v1 kind: pod metadata: name: simple-webapp-color spec: containers: - name: simple-webapp-color image: kodekloud/simple-webapp ports: - containerPort: 8080 - name: log-agent image: log-agent
Research Questions & Conclusion
This concludes the Application Lifecycle Management section of the CKA certification exam. To test your knowledge, it is strongly recommended that you access research questions of all core concepts covered in the coursework and a test to prepare you for the exam. You can also send your feedback to the course developers, whether you have feedback or would like something changed within the course.
Here is a quick quiz to help you assess your knowledge. Leave your answers in the comments below and tag us back.
Quick Tip – Questions below may include a mix of DOMC and MCQ types.
1. Which command can be used to inspect the deployment and identify the number of PODs deployed by it?
[A] kubectl inspect pod
[B] kubectl inspect deploy
[C] kubectl describe deployment
[D] kubectl describe pod
2. There are two kinds of deployment strategies in Kubernetes: The Recreate and Rolling Update Strategies.
3. Upgrade the application by setting the image on the deployment to kodekloud/webapp-color:v3
Deployment Name: frontend
Deployment Image: kodekloud/webapp-color:v3
$ kubectl set image deploy/frontend
4. Create a pod with the ubuntu image to run a container to sleep for 5000 seconds.
Pod Name: ubuntu-sleeper-2
Command: sleep 5000
apiVersion: v1 kind: Pod metadata: name: ubuntu-sleeper-2 spec: containers: - name: ubuntu image: ubuntu command: - "sleep" - "5000"
5. Create a pod with the given specifications. By default, it displays a
blue background. Set the given command-line arguments to change it to
Pod Name: webapp-green
Command line arguments: --color=green
apiVersion: v1 kind: Pod metadata: name: webapp-green labels: name: webapp-green spec: containers: - name: simple-webapp image: kodekloud/webapp-color args: ["--color", "green"]
6. The Recreate strategy is the default rollout strategy.
7. Add the environment variable on the POD to display a
Pod Name: webapp-color
Image Name: kodekloud/webapp-color
apiVersion: v1 kind: Pod metadata: name: webapp-color spec: containers: - env: - name: APP_COLOR value: pink image: kodekloud/webapp-color name: webapp-color
8. Create a new ConfigMap for the
webapp-color POD. Use the spec given below.
ConfigName Name: webapp-config-map
$ kubectl create configmap webapp-config-map --from-literal=APP_COLOR=darkblue
9. Create a multi-container pod with 2 containers. Use the spec given below.
If the pod goes into the
crashloopbackoff then add
sleep 1000 in the
Container 1 Name: lemon
Container 1 Image: busybox
Container 2 Name: gold
Container 2 Image: redis
apiVersion: v1 kind: Pod metadata: name: yellow spec: containers: - name: lemon image: busybox command: - sleep - "1000" - name: gold image: redis
This part of the course offers an in-depth introduction to how application deployments behave in the production environment. By exploring the different rollout strategies, this section outlines information with guidance on choosing the right deployment strategy for different kinds of applications. KodeKloud’s curriculum also includes practicals on how to perform rollbacks when the updates result in undesired changes in the application.
This section is crucial for prospective Kubernetes administrators since it is a guide on how to manage applications from inception to retirement. With the knowledge explored in this section, the candidate can easily create running applications based on
ENTRYPOINT instructions, and manage application environments using Environment Variables, ConfigMaps and Secrets.
More details about KodeKloud’s CKA course with access to the lessons, labs, mock exams and demo can be found here – https://kodekloud.com/courses/certified-kubernetes-administrator-cka/.