Note:

Use Stateless Deployments with Oracle Cloud Native Environment

Introduction

There are two primary approaches to managing applications on Kubernetes - StatefulSets and Deployments. StatefulSets, which require persistent storage, manage stateful workloads such as a MySQL deployment on Kubernetes. Deployments provide a way to manage stateless applications such as websites, which often do not need to maintain their internal state.

Note: A DaemonSets is a third available Kubernetes controller. Daemonsets ensure a replica of Pod will always run on all or some other cluster’s Nodes and are typically used for logging agents, monitoring systems, etc.

Objectives

In this tutorial, you will learn:

Prerequisites

Additional Information

Before proceeding: This tutorial follows from these tutorials:

These tutorials will help you learn to use Affinity, Kubernetes Labels, nodeSelector, or Taints & Tolerations if you are unfamiliar with them.

Deploy Oracle Cloud Native Environment

Note: If running in your own tenancy, read the linux-virt-labs GitHub project README.md and complete the prerequisites before deploying the lab environment.

  1. Open a terminal on the Luna Desktop.

  2. Clone the linux-virt-labs GitHub project.

    git clone https://github.com/oracle-devrel/linux-virt-labs.git
    
  3. Change into the working directory.

    cd linux-virt-labs/ocne
    
  4. Install the required collections.

    ansible-galaxy collection install -r requirements.yml
    
  5. Deploy the lab environment.

    ansible-playbook create_instance.yml -e localhost_python_interpreter="/usr/bin/python3.6"
    

    The free lab environment requires the extra variable local_python_interpreter, which sets ansible_python_interpreter for plays running on localhost. This variable is needed because the environment installs the RPM package for the Oracle Cloud Infrastructure SDK for Python, located under the python3.6 modules.

    Important: Wait for the playbook to run successfully and reach the pause task. At this stage of the playbook, the installation of Oracle Cloud Native Environment is complete, and the instances are ready. Take note of the previous play, which prints the public and private IP addresses of the nodes it deploys and any other deployment information needed while running the lab.

Confirm the Number of Nodes

It helps to know the number and names of nodes in your Kubernetes cluster.

  1. Open a terminal and connect via ssh to the ocne-control-01 node.

    ssh oracle@<ip_address_of_node>
    
  2. List the nodes in the cluster.

    kubectl get nodes
    

    The output shows the control plane and worker nodes in a Ready state along with their current Kubernetes version.

Create a Deployment

Kubernetes uses Deployment and ReplicaSets API objects to manage the Pods used as part of a stateless application. These API objects allow administrators to control your applications’ configuration, rollout, and rollback. They also allow you to automate the rollout of Pod updates without incurring downtime. Using a Deployment provides more resilience for your application than scheduling individual Pods on a cluster because Kubernetes handles the orchestration task and will allocate each Pod automatically to an available Node. Additionally, Kubernetes ensures the ‘desired’ number of Pods are active by rescheduling them if a Node fails. Conversely, Pods can’t be directly scaled or replicated automatically across your cluster’s Nodes.

While it is possible to run individual Pods, this approach does not scale. For example, it does not scale if the workload increases. Neither does it provide failure tolerance if, for example, a Node fails (because individual Pods don’t reschedule) if this occurs. Using a Kubernetes Deployment provides both application scalability and failure tolerance. A Deployment allows Kubernetes to perform actions such as rolling updates or scaling the number of Pods used (Replicas).

  1. Create a Deployment.

    kubectl create deployment mytest --image=ghcr.io/oracle/oraclelinux8-nginx:1.20 --replicas=6
    
  2. Get a list of Deployments.

    kubectl get deployments
    

    Example Output:

    NAME    READY   UP-TO-DATE   AVAILABLE   AGE
    mytest  6/6     6            6           9s
    

    Note: If the output shows the Deployment partially complete, re-query a few more times. Eventually, the READY and AVAILABLE columns will confirm the Replicas are running.

    Where the columns displayed represent the following information:

    • READY: The number of replicas ready compared to the desired. This corresponds to the spec.replicas value.
    • UP-TO-DATE: The number of replicas updated to meet the desired state.
    • AVAILABLE: The number of replicas available.
  3. Show the Deployments, Pods, and ReplicaSets.

    Deployments are used to control the creation and deletion of the Pod objects it manages by using an associated ReplicaSet object. The purpose of the ReplicaSet is to ensure the number of replica Pods requested is maintained. The ReplicaSet uses the Deployment name as its prefix with a hash value as the suffix to identify the Pods it manages. So a Deployment uses both Pods and ReplicaSets to control a Deployment.

    kubectl get deployments,pods,replicasets
    

    Note: Include the Namespace (-n <your-namespace>) if you want to return details of a specific namespace.

    Example Output:

    NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/mytest   6/6     6            6           3m17s
    
    NAME                          READY   STATUS    RESTARTS   AGE
    pod/mytest-76688bc4c4-2b5jd   1/1     Running   0          3m17s
    pod/mytest-76688bc4c4-68gtg   1/1     Running   0          3m17s
    pod/mytest-76688bc4c4-7w9jq   1/1     Running   0          3m17s
    pod/mytest-76688bc4c4-8stwt   1/1     Running   0          3m17s
    pod/mytest-76688bc4c4-cbfdz   1/1     Running   0          3m17s
    pod/mytest-76688bc4c4-v4nm6   1/1     Running   0          3m17s
    
    NAME                                DESIRED   CURRENT   READY   AGE
    replicaset.apps/mytest-76688bc4c4   6         6         6       3m17s
    

List the Pods In a Deployment

Next, you will learn how to view the details of a specific Deployment. In a production environment, the kubectl get pods command usually returns many other Pods. You could filter by namespace (e.g.: kubectl get pods -n <namespace), but that is also likely to return other Pods. So, is there a way to list the Pods for a specific deployment? Yes, but you need to confirm the label created by Kubernetes to manage the Deployment.

  1. Query the Deployment details.

    This query helps by showing the configuration applied by Kubernetes.

    kubectl describe deployment mytest
    

    Example Output:

    Name:                   mytest
    Namespace:              default
    CreationTimestamp:      Fri, 26 Apr 2024 16:06:13 +0000
    Labels:                 app=mytest
    Annotations:            deployment.kubernetes.io/revision: 1
    Selector:               app=mytest
    Replicas:               6 desired | 6 updated | 6 total | 6 available | 0 unavailable
    StrategyType:           RollingUpdate
    MinReadySeconds:        0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=mytest
      Containers:
       oraclelinux8-nginx:
        Image:        ghcr.io/oracle/oraclelinux8-nginx:1.20
        Port:         <none>
        Host Port:    <none>
        Environment:  <none>
        Mounts:       <none>
      Volumes:        <none>
    Conditions:
      Type           Status  Reason
      ----           ------  ------
      Available      True    MinimumReplicasAvailable
      Progressing    True    NewReplicaSetAvailable
    OldReplicaSets:  <none>
    NewReplicaSet:   mytest-76688bc4c4 (6/6 replicas created)
    Events:
      Type    Reason             Age   From                   Message
      ----    ------             ----  ----                   -------
      Normal  ScalingReplicaSet  5m7s  deployment-controller  Scaled up replica set mytest-76688bc4c4 to 6
    

    Take note of the Labels: and Selector: fields listed in the output. In this example, they are:

    • Labels: app=mytest
    • Selector: app=mytest
  2. Create another deployment to prove this works.

    kubectl create deployment apache --image httpd --replicas=3
    
  3. List the Pods deployed.

    kubectl get pods
    

    Example Output:

    NAME                      READY   STATUS    RESTARTS   AGE
    apache-f9489c7dc-7rplz    1/1     Running   0          9s
    apache-f9489c7dc-x6fr6    1/1     Running   0          9s
    apache-f9489c7dc-zxgm8    1/1     Running   0          9s
    mytest-76688bc4c4-2b5jd   1/1     Running   0          8m51s
    mytest-76688bc4c4-68gtg   1/1     Running   0          8m51s
    mytest-76688bc4c4-7w9jq   1/1     Running   0          8m51s
    mytest-76688bc4c4-8stwt   1/1     Running   0          8m51s
    mytest-76688bc4c4-cbfdz   1/1     Running   0          8m51s
    mytest-76688bc4c4-v4nm6   1/1     Running   0          8m51s
    

    If the STATUS column shows the Deployment as ContainerCreating, don’t worry; it is normal. Re-query a few times. The STATUS should change to Running.

  4. Using the label, Query the Pods for the mytest Deployment.

    kubectl get pods -l=app=mytest
    

    Example Output:

    NAME                      READY   STATUS    RESTARTS   AGE
    mytest-76688bc4c4-2b5jd   1/1     Running   0          11m
    mytest-76688bc4c4-68gtg   1/1     Running   0          11m
    mytest-76688bc4c4-7w9jq   1/1     Running   0          11m
    mytest-76688bc4c4-8stwt   1/1     Running   0          11m
    mytest-76688bc4c4-cbfdz   1/1     Running   0          11m
    mytest-76688bc4c4-v4nm6   1/1     Running   0          11m
    
  5. Re-query the Pods using the selector value.

    kubectl get pods --selector=app=mytest
    

    Example Output:

    NAME                      READY   STATUS    RESTARTS   AGE
    mytest-76688bc4c4-2b5jd   1/1     Running   0          12m
    mytest-76688bc4c4-68gtg   1/1     Running   0          12m
    mytest-76688bc4c4-7w9jq   1/1     Running   0          12m
    mytest-76688bc4c4-8stwt   1/1     Running   0          12m
    mytest-76688bc4c4-cbfdz   1/1     Running   0          12m
    mytest-76688bc4c4-v4nm6   1/1     Running   0          12m
    
  6. Delete the Apache deployment because it is no longer required.

    kubectl delete deployment apache
    

Perform a Rolling Update and Rollback

Using Deployments allows you to utilize the rollout and rollback functionality built into the Kubernetes API. Because Kubernetes uses the Deployment object to manage an application, deployments can also manage applications. Next, you will deploy a new version of the ‘nginx’ application and revert (rollback) to the original version.

Confirm the Rollout History

  1. Review the rollout history for the ‘mytest’ application.

    kubectl rollout history deployment mytest
    

    Example Output:

    deployment.apps/mytest 
    REVISION  CHANGE-CAUSE
    1         <none>
    
    

    The application has no recorded change because only one revision is listed.

  2. Add a note to the history.

    If the CHANGE-CAUSE column is empty, you can add an annotation to this column.

    kubectl annotate deployment mytest kubernetes.io/change-cause="Initial Deployment of Nginx 1.20"
    
  3. Review the rollout history again.

    kubectl rollout history deployment mytest
    

    Example Output:

    deployment.apps/mytest 
    REVISION  CHANGE-CAUSE
    1         Initial deployment of Nginx 1.20
    
    

    The CHANGE-CAUSE column has recorded the annotation you added.

    Note: Annotating is not mandatory but will help you identify changes to the application deployments on your cluster.

Deploy a New Version of the ‘mytest’ application

Changing the Pod image causes Kubernetes to replace the Pods in the Deployment’s ReplicaSet. Kubernetes only terminates the existing Pods in a ReplicaSet once the new Pods are up and running. This process is known as a rollout strategy and ensures no downtime occurs or lost connections and that the application continues running during the change.

Kubernetes provides two rollout strategies:

You can view the current rollout strategy by reviewing the deployment YAML file (if used) or by the kubectl describe command. See this excerpt from the previously run command.

...
Replicas:               6 desired | 6 updated | 6 total | 6 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
...

Where:

Both maxSurge and maxUnavailable can be defined as either a percentage or a number.

  1. Update the Nginx image version.

    kubectl set image deployment mytest oraclelinux8-nginx=ghcr.io/oracle/oraclelinux8-nginx:1.22
    kubectl rollout status deployment mytest
    
    

    Where:

    • The first command updates the Nginx image from version 1.20 to 1.22,
    • The second command outputs the status of the rollout.

    Note: The commands are submitted together because they complete quickly in this scenario (due to a lack of live site traffic).

    Example Output

    ...
    Waiting for deployment "mytest" rollout to finish: 3 out of 6 new replicas have been updated...
    Waiting for deployment "mytest" rollout to finish: 3 out of 6 new replicas have been updated...
    Waiting for deployment "mytest" rollout to finish: 3 out of 6 new replicas have been updated...
    Waiting for deployment "mytest" rollout to finish: 3 out of 6 new replicas have been updated...
    Waiting for deployment "mytest" rollout to finish: 4 out of 6 new replicas have been updated...
    Waiting for deployment "mytest" rollout to finish: 4 out of 6 new replicas have been updated...
    Waiting for deployment "mytest" rollout to finish: 4 out of 6 new replicas have been updated...
    Waiting for deployment "mytest" rollout to finish: 5 out of 6 new replicas have been updated...
    Waiting for deployment "mytest" rollout to finish: 5 out of 6 new replicas have been updated...
    Waiting for deployment "mytest" rollout to finish: 5 out of 6 new replicas have been updated...
    Waiting for deployment "mytest" rollout to finish: 5 out of 6 new replicas have been updated...
    Waiting for deployment "mytest" rollout to finish: 2 old replicas are pending termination...
    Waiting for deployment "mytest" rollout to finish: 1 old replicas are pending termination...
    Waiting for deployment "mytest" rollout to finish: 1 old replicas are pending termination...
    Waiting for deployment "mytest" rollout to finish: 1 old replicas are pending termination...
    Waiting for deployment "mytest" rollout to finish: 5 of 6 updated replicas are available...
    deployment "mytest" successfully rolled out
    
  2. Annotate the Deployment.

    kubectl annotate deployment/mytest kubernetes.io/change-cause="Update Nginx image to 1.22"
    
  3. Review more details of this revision.

    kubectl rollout history deployment/mytest --revision=2
    

    Example Output:

    deployment.apps/mytest with revision #2
    Pod Template:
      Labels:	app=mytest
    	pod-template-hash=6f9d84b8cb
      Annotations:	kubernetes.io/change-cause: Update Nginx image to 1.22
      Containers:
       oraclelinux8-nginx:
        Image:	ghcr.io/oracle/oraclelinux8-nginx:1.22
        Port:	<none>
        Host Port:	<none>
        Environment:	<none>
        Mounts:	<none>
      Volumes:	<none>
    
    

    Confirming that the Nginx image has been updated from 1.20 to 1.22

Rollback to a Previous Version

Occasionally, users experience bugs when administrators move a new version to production. Kubernetes Deployments make the rollback process easy.

  1. Rollback to the previous version.

    kubectl rollout undo deploy mytest
    

    Information: It is possible to roll back to a specific previous revision by appending a --revision flag to the rollout undo command. In this example, you could have used this flag to undo the rollout as in the following: kubectl rollout undo deploy mytest --revision=1. Since the rollout history only contains two revisions in this example, adding the --revision option makes no difference. However, if you need to revert several versions, this flag makes the process easier to achieve.

  2. Confirm tracking of the Deployment changes.

    kubectl rollout history deployment mytest
    

    Example Output:

    deployment.apps/mytest 
    REVISION  CHANGE-CAUSE
    2         Update Nginx image to 1.22
    3         Initial Deployment of Nginx 1.20
    
  3. Confirm the Nginx image version changed to 1.20

    kubectl describe deployment mytest
    

    Example Output (excerpt):

    Name:                   mytest
    Namespace:              default
    CreationTimestamp:      Fri, 26 Apr 2024 19:03:10 +0000
    Labels:                 app=mytest
    Annotations:            deployment.kubernetes.io/revision: 3
    ..
    ..
    Pod Template:
      Labels:  app=mytest
      Containers:
       oraclelinux8-nginx:
        Image:        ghcr.io/oracle/oraclelinux8-nginx:1.20
        Port:         <none>
        Host Port:    <none>
        Environment:  <none>
        Mounts:       <none>
      Volumes:        <none>
    Conditions:
      Type           Status  Reason
    ..
    ..
      Normal  ScalingReplicaSet  2m34s                 deployment-controller  Scaled up replica set mytest-76688bc4c4 to 6 from 5
      Normal  ScalingReplicaSet  2m33s (x5 over 103m)  deployment-controller  (combined from similar events): Scaled down replica set mytest-6f9d84b8cb to 0 from 1
    

    The line showing Image: ghcr.io/oracle/oraclelinux8-nginx:1.20 confirms the Nginx Pod version is now 1.20.

Summary

Kubernetes allows you to orchestrate and manage application workloads to deliver optimum service. Hopefully, you now understand how Deployments work and can manage your application deployments, including their ability to be rolled out or rolled back.

For More Information

More Learning Resources

Explore other labs on docs.oracle.com/learn or access more free learning content on the Oracle Learning YouTube channel. Additionally, visit education.oracle.com/learning-explorer to become an Oracle Learning Explorer.

For product documentation, visit Oracle Help Center.