Kubernetes Guide - Kuldeepjakhi/kubernetes GitHub Wiki

What is Kubernetes?

Kubernetes, often abbreviated as K8s, is an open-source container orchestration platform developed by Google. It automates the deployment, scaling, and management of containerized applications, providing a robust framework for running distributed systems resiliently.

Kubernetes vs. Docker

Kubernetes and Docker are the leading container orchestration tools that are often considered one above the other to run applications. But what makes them different? Kubernetes architecture helps in container orchestration and can manage several containers across multiple machines. Docker helps in develop and deploy software containers.

Architecture Overview

Kubernetes follows a master-slave architecture, comprising a control plane (master) and one or more worker nodes. The control plane consists of several components:

Kubernetes Master Maintains the desired state for the cluster.
Kubernetes Node Runs the applications.
API Server Exposes the Kubernetes API, which clients like kubectl interact with to manage the cluster.
Scheduler Assigns pods to nodes based on resource availability and scheduling constraints.
Controller Manager Watches for changes to cluster state and ensures that desired state is maintained.
etcd Consistent and highly available key-value store used as Kubernetes’ backing store for all cluster data.

On worker nodes, the following components are typically running.

Kubelet: Agent that runs on each node and communicates with the control plane. It manages the pod lifecycle and reports node status.
Kube Proxy: Handles network routing and load balancing for services running on the node.
Container Runtime: Software responsible for running containers, such as Docker or containerd.

Features:

Kubernetes features grouped in six categories.

Service Discovery and Load Balancing: Kubernetes assigns each set of pods a single DNS name and an IP address. If traffic is high, K8s automatically balances the load across a service which may include multiple pods.
Automated Rollouts and Rollbacks: K8s can roll out new pods and swap them with existing pods. It can also change configurations without impacting end-users. Additionally, Kubernetes has an automated rollback feature. This rollback functionality can revert changes if not completed successfully.
Secret and Configuration Management: Configuration and secrets information can be securely stored and updated without rebuilding images. Stack configuration does not require the unveiling of secrets, which limits the risk of data compromise.
Storage Orchestration: Different storage systems such as local storage, network storage, and public cloud providers can be mounted using K8s.
Automatic Bin Packing: Kubernetes algorithms seek to allocate containers based upon configured CPU and RAM requirements efficiently. This feature helps enterprises optimize resource utilization.
Self-Healing: Kubernetes performs health checks on pods and restarts containers that fail. If a pod fails, K8s does not allow connections to them until the health checks have passed.

##Key Concepts and Terminology

1. Pods: Pods are the smallest deployable units in Kubernetes, encapsulating one or more containers that share networking and storage resources. They represent a logical application, such as a web server or a database.
2. Nodes: Nodes are the worker machines in a Kubernetes cluster. They can be physical or virtual machines and are responsible for running pods and other system services. Each node typically runs a Kubernetes runtime, like Docker or containerd.
3. Deployments: Deployments define the desired state of a set of pods and manage their lifecycle. They enable declarative updates to applications, handling rollout strategies, scaling, and rollback operations.
4. Services: Services provide stable endpoints for accessing pods, abstracting away the complexities of pod IP addresses and network routing. They enable load balancing and service discovery within the cluster.
5. ReplicaSets: ReplicaSets ensure that a specified number of pod replicas are running at any given time. They work in conjunction with deployments to maintain desired pod counts, automatically scaling up or down as needed.

Inside Kubernetes components, the following actions occur when you deploy a Deployment object with the provided YAML configuration:

  1. The API Server receives the YAML configuration file defining the Deployment object and validates the configuration against the Kubernetes API schema. Stores the validated configuration in etcd, the cluster’s distributed key-value store.
  2. The controller Manager detects the creation of the Deployment object, and creates the deployment based on the specified template and desired replica count sending the deployment requirements to the scheduler.
  3. From now the controller manager monitors the state of the deployment and ensures it matches the desired state defined.
  4. Once the scheduler recieves the deployment is in charge of assigning the Pods to suitable worker nodes based on resource availability and other scheduling constraints.
  5. Kubelet (on worker nodes) receives instructions from the Scheduler to create Pods on the node,pulls the specified container image (in this case, Nginx) from the container registry and creates and manages the lifecycle of Pods based on the specifications defined in the Deployment’s pod template.
  6. The container runtime instantiates and runs the Nginx container inside the Pods. Once deployed is in charge of managing the container’s lifecycle, including starting, stopping, and monitoring its health.
  7. Each Pod gets its own unique cluster-wide IP address.
  8. The next step is creating a Service to allow pods/ingresses accesing this deployment.
  9. In case we want to access it from outside the cluster, a ingress object should be created.

Kubernetes Cluster Setup using Kubeadm.

Run Below command on Master and all Nodes machine.

sudo swapoff -a

sudo apt-get update && sudo apt-get install -y apt-transport-https curl

sudo curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -

echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
sudo apt-get update && sudo apt-get install -y kubelet kubeadm kubectl docker.io

Initializing and setting up the kubernetes cluster only on Master node

sudo kubeadm init --pod-network-cidr=172.16.0.0/16

mkdir -p $HOME/.kube

sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

sudo chown $(id -u):$(id -g) $HOME/.kube/config

On All nodes(copy admin.conf content from master node)

export KUBECONFIG=/etc/kubernetes/admin.conf

echo $KUBECONFIG

kubectl cluster-info

Run Below Join command on Worker nodes

kubeadm join 192.168.56.129:6443 --token 2po4he.lt2qtullly1bsmbs  --discovery-token-ca-cert-hash sha256:038f3724feb33d42549ef3f72fd4effdf94b388e212d4e6b0014ca166493b2d6

Install Network add-on to enable the communication between the pods only on Master node

wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

Change Network CIDR in cube-flannel.yml file. It should be Network": "172.16.0.0/16"

kubectl apply -f kube-flannel.yml
kubectl get pods --all-namespaces
kubectl get nodes
kubectl describe node <nodename>
kubectl get nodes --show-labels
kubectl label nodes kubenode1 memorytyp=high

Pod

A Pod is the smallest deployable unit that can be deployed and managed by Kubernetes. In other words, if you need to run a single container in Kubernetes, then you need to create a Pod for that container. At the same time, a Pod can contain more than one container, if these containers are relatively tightly coupled. In a pre-container world, they would have executed on the same server.
A standard use case for a multi-container Pod with shared Volume is when one container writes to the shared directory (logs or other files), and the other container reads from the shared directory. Example:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  restartPolicy: OnFailure
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

Note: You need to install a container runtime into each node in the cluster so that Pods can run there.

Multi-Container Pods

The primary purpose of a multi-container Pod is to support co-located, co-managed helper processes for a main program. There are some general patterns of using helper processes in Pods:
Sidecar containers "help" the main container. For example, log or data change watchers, monitoring adapters, and so on. A log watcher, for example, can be built once by a different team and reused across different applications. Another example of a sidecar container is a file or data loader that generates data for the main container.

apiVersion: v1
kind: Pod
metadata:
  name: mc1
spec:
  volumes:
  - name: html
    emptyDir: {}
  containers:
  - name: 1st
    image: nginx
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
  - name: 2nd
    image: debian
    volumeMounts:
    - name: html
      mountPath: /html
    command: ["/bin/sh", "-c"]
    args:
      - while true; do
          date >> /html/index.html;
          sleep 1;
        done
$ kubectl get pod mc1 --output=yaml               # Check both container specs.

$ kubectl exec -it mc1 -c 1st -- /bin/bash        # connect first container

$ kubectl exec -it mc1 -c 1st -- curl localhost   # connect 1st container URL

Container probes

A probe is a diagnostic performed periodically by the kubelet on a container. To perform a diagnostic, the kubelet can invoke different actions: • ExecAction (performed with the help of the container runtime). • TCPSocketAction (checked directly by the kubelet). • HTTPGetAction (checked directly by the kubelet).

Check mechanisms There are four different ways to check a container using a probe. Each probe must define exactly one of these four mechanisms: exec Executes a specified command inside the container. The diagnostic is considered successful if the command exits with a status code of 0.

grpc Performs a remote procedure call using gRPC. The target should implement gRPC health checks. The diagnostic is considered successful if the status of the response is SERVING.
httpGet Performs an HTTP GET request against the Pod's IP address on a specified port and path. The diagnostic is considered successful if the response has a status code greater than or equal to 200 and less than 400.
tcpSocket Performs a TCP check against the Pod's IP address on a specified port. The diagnostic is considered successful if the port is open. If the remote system (the container) closes the connection immediately after it opens, this counts as healthy.

Each probe has one of three results:

Success The container passed the diagnostic.
Failure The container failed the diagnostic.
Unknown The diagnostic failed (no action should be taken, and the kubelet will make further checks).

Types of probe

The kubelet can optionally perform and react to three kinds of probes on running containers:

livenessProbe

  • Purpose: Checks if a container is still running. If the probe fails, Kubernetes restarts the container.
  • Use when: You need to manage containers that should be restarted if they fail or become unresponsive.
    Indicates whether the container is running. If the liveness probe fails, the kubelet kills the container, and the container is subjected to its restart policy. If a container does not provide a liveness probe, the default state is Success.

readinessProbe

  • Purpose: Determines if a container is ready to start accepting traffic. Kubernetes ensures traffic is not sent to the container until it passes the readiness probe.
  • Use when: Your application needs time to start up and you want to make sure it's fully ready before receiving traffic. Indicates whether the container is ready to respond to requests. If the readiness probe fails, the endpoints controller removes the Pod's IP address from the endpoints of all Services that match the Pod. The default state of readiness before the initial delay is Failure. If a container does not provide a readiness probe, the default state is Success.

startupProbe

  • Purpose: Checks if an application within a container has started. If the probe fails, Kubernetes will not apply liveness or readiness probes until it passes.
  • Use when: You have containers that take longer to start up and you want to prevent them from being killed by liveness probes before they are fully running.
    Indicates whether the application within the container is started. All other probes are disabled if a startup probe is provided, until it succeeds. If the startup probe fails, the kubelet kills the container, and the container is subjected to its restart policy. If a container does not provide a startup probe, the default state is Success.

Kubernetes Probes Example:

  1. Liveness HTTP GET probe
apiVersion: v1
kind: Pod
metadata:
  name: liveness-pod
spec:
  containers:
  - name: liveness-container
    image: grafana/grafana:10.3.7
    livenessProbe:
      httpGet:
        path: /api/health
        port: 3000
      initialDelaySeconds: 5
      periodSeconds: 5`
kubectl exec -it liveness-pod -- curl localhost:3000/api/health
  1. Liveness TCP probe
apiVersion: v1
kind: Pod
metadata:
  name: rabbitmq
  labels:
    app: rabbitmq
spec:
  containers:
  - name: rabbitmq
    image: arm64v8/rabbitmq:3-management
    ports:
    - containerPort: 15672
    livenessProbe:
      tcpSocket:
        port: 15672
      initialDelaySeconds: 15
      periodSeconds: 20

Service file to access above container.

apiVersion: v1
kind: Service
metadata:
  name: liveness-tcp-service
  labels:
    app: liveness-tcp-servicet
spec:
  ports:
    - name: http
      port: 8090
      targetPort: 15672
  selector:
    app: rabbitmq
  type: NodePort

Check liveness probe health api url

kubectl exec -it liveness-pod -- curl localhost:3000/api/health
  1. Liveness Command probe
---
apiVersion: v1
kind: Pod
metadata:
  name: pods-liveness-exec-pod
spec:
  containers:
    - args:
        - /bin/sh
        - -c
        - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
      image: busybox
      livenessProbe:
        exec:
          command:
            - cat
            - /tmp/healthy
        initialDelaySeconds: 5
        periodSeconds: 5
      name: pods-liveness-exec-container

Parameters:

initialDelaySeconds Number of seconds after the container has started before liveness or readiness probes are initiated.
periodSeconds How often (in seconds) to perform the probe. Default is 10 seconds. Minimum value is 1.
timeoutSeconds Number of seconds after which the probe times out. Defaults to 1 second. Minimum value is 1.
successThreshold Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness. Minimum value is 1.
failureThreshold When a pod starts and the probe fails, Kubernetes will try failureThreshold times before giving up. Giving up in case of a liveness probe means restarting the pod. In case of a readiness probe the pod will be marked Unready. Defaults to 3. Minimum value is 1.

And HTTP probes have additional parameters that can be set on httpGet:.

host The host name to connect to, which defaults to the pod IP. You probably want to set “Host” in httpHeaders instead.
scheme The scheme to use for connecting to the host (HTTP or HTTPS). Defaults to HTTP.
path Path to access on the HTTP server.
httpHeaders Custom headers to set in the request. HTTP allows repeated headers.
port Name or number of the port to access on the container. Number must be in the range 1 to 65535.

Pod Lifecycle

Pods follow a defined lifecycle, starting in the Pending phase, moving through Running if at least one of its primary containers starts OK, and then through either the Succeeded or Failed phases depending on whether any container in the Pod terminated in failure.

Pod phase

A Pod's status field is a PodStatus object, which has a phase field.
The phase of a Pod is a simple, high-level summary of where the Pod is in its lifecycle. The phase is not intended to be a comprehensive rollup of observations of container or Pod state, nor is it intended to be a comprehensive state machine.

Value Description
Pending The Pod has been accepted by the Kubernetes cluster, but one or more of the containers has not been set up and made ready to run. This includes time a Pod spends waiting to be scheduled as well as the time spent downloading container images over the network.
Running The Pod has been bound to a node, and all of the containers have been created. At least one container is still running, or is in the process of starting or restarting.
Succeeded All containers in the Pod have terminated in success, and will not be restarted.
Failed All containers in the Pod have terminated, and at least one container has terminated in failure. That is, the container either exited with non-zero status or was terminated by the system, and is not set for automatic restarting.
Unknown For some reason the state of the Pod could not be obtained. This phase typically occurs due to an error in communicating with the node where the Pod should be running.

Container states

As well as the phase of the Pod overall, Kubernetes tracks the state of each container inside a Pod. You can use container lifecycle hooks to trigger events to run at certain points in a container's lifecycle.
Once the scheduler assigns a Pod to a Node, the kubelet starts creating containers for that Pod using a container runtime. There are three possible container states: Waiting, Running, and Terminated.

Container restart policy

The spec of a Pod has a restartPolicy field with possible values Always, OnFailure, and Never. The default value is Always. The restartPolicy for a Pod applies to app containers in the Pod and to regular init containers. Sidecar containers ignore the Pod-level restartPolicy field: in Kubernetes, a sidecar is defined as an entry inside initContainers that has its container-level restartPolicy set to Always. For init containers that exit with an error, the kubelet restarts the init container if the Pod level restartPolicy is either OnFailure or Always:
Always Automatically restarts the container after any termination.
OnFailure Only restarts the container if it exits with an error (non-zero exit status).
Never Does not automatically restart the terminated container.

Setting the restart policy to Always doesn’t mean Kubernetes will keep trying to restart a failed Pod perpetually. Instead, it uses an exponential back-off delay that starts at 10 seconds and goes up to five minutes. In other words, let’s say you have a Pod with a critical error that prevents it from completing its startup process. Kubernetes will try to start it, see that it failed, wait 10 seconds, then restart it. The next time it fails, Kubernetes will wait 20 seconds, then 40 seconds, then 1 minute 20 seconds, etc, all the way up to five minutes. After this point, if the container still fails to start, Kubernetes will no longer try to start it. But if Kubernetes does manage to get the container running, this timer will reset after 10 minutes of continuous runtime.

DEPLOYMENTS

Deployment is a Kubernetes object that manages a set of identical pods, ensuring that a specified number of replicas of the pod are running at any given time. It provides a declarative approach to managing Kubernetes objects, allowing for automated rollouts and rollbacks of containerized applications.
Moreover, a Deployment manages the deployment of a new version of an application. It also helps us roll back to a previous version by creating a replica set and updating it with the new configuration. A ReplicaSet ensures that the specified number of replicas of the pods are always running. Hence, if any pod fails, it creates a new one to maintain the desired state.

Replicaset - A ReplicaSet is a Kubernetes object that ensures that a specified number of replicas of a pod are running at any given time. It manages the lifecycle of pods and provides a way to scale and maintain the desired state of the application. The ReplicaSet is also responsible for creating and managing pods based on a template specification. It creates new replicas of a pod when necessary and removes old ones when they’re no longer needed. It also provides a mechanism for rolling updates and rollbacks of the application by creating new replicas with updated configurations and terminating the old ones.

Deployment Vs Replicaset

Deployments ReplicaSet
High-level abstractions that manage replica sets.It provides additional features such as rolling updates, rollbacks, and versioning of the application. A lower-level abstraction that manages the desired number of replicas of a pod.Additionally, it provides basic scaling and self-healing mechanisms.
Deployment manages a template of pods and uses replica sets to ensure that the specified number of replicas of the pod is running. ReplicaSet only manages the desired number of replicas of a pod.
Deployment provides a mechanism for rolling updates and rollbacks of the application, enabling seamless updates and reducing downtime. Applications must be manually updated or rolled back.
It provides versioning of the application, allowing us to manage multiple versions of the same application. It also makes it easy to roll back to a previous version if necessary. ReplicaSet doesn’t provide this feature.

Deployment File Example:

Secrets file- secret.yml

apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
data:
  api-key: YWRtaW4=
  password: cGFzc3dvcmQ=

Deployment File - deployments.yml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment     # Name of deployment
spec:
  replicas: 3                # Number of Replicas
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: systyp
                operator: In
                values:
                - cpu-based       # You can add multiple values as well
      containers:
      - name: nginx-container
        image: nginx:latest
        ports:
        - containerPort: 80
        env:
        - name: DATABASE_HOST
          value: db.example.com
        - name: API_KEY
          valueFrom:
            secretKeyRef:
              name: my-secret
              key: api-key
        resources:
          limits:
            memory: "256Mi"  # Maximum memory allowed
            cpu: "200m"       # Maximum CPU allowed (200 milliCPU)
          requests:
            memory: "128Mi"  # Initial memory request
            cpu: "100m"       # Initial CPU request
        livenessProbe:
          httpGet:
            path: /                # The path to check for the liveness probe
            port: 80               # The port to check on
          initialDelaySeconds: 15  # Wait this many seconds before starting the probe
          periodSeconds: 10        # Check the probe every 10 seconds
        readinessProbe:
          httpGet:
            path: /                # The path to check for the readiness probe
            port: 80               # The port to check on
          initialDelaySeconds: 5   # Wait this many seconds before starting the probe
          periodSeconds: 5         # Check the probe every 5 seconds
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: my-pvc  # Name of the Persistent Volume Claim

PV File - pv.yml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  accessModes:
    - ReadWriteOnce
  capacity:
    storage: 1Gi
  storageClassName: standard
  hostPath:
    path: /tmp/demo-pv

PVC File - mypvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: standard
  volumeName: my-pv

Explanation:

apiVersion: Specifies the Kubernetes API version. In this case, it’s using the “apps/v1” API version, which is appropriate for Deployments.
kind: Specifies the type of Kubernetes resource. Here, it’s “Deployment,” indicating that this configuration file is defining a Deployment.
spec: This section defines the desired state of the Deployment.
replicas**: 3 Specifies that you want to run three replicas of your application.
selector: Describes the selector to match pods managed by this Deployment.
matchLabels: Specifies the labels that the Replica Set created by the Deployment should use to select the pods it manages. In this case, pods with the label app: example are selected.
template: Defines the pod template used for creating new pods.
metadata: Contains the labels to apply to the pods created from this template. In this case, the pods will have the label app: example.
spec: Describes the specification of the pods.
containers: This section specifies the containers to run in the pod.
name: example-container: Assigns a name to the container.
image: example-image: Specifies the Docker image to use for this container.
ports: Defines the ports to open in the container.
containerPort: 8080: Indicates that the container will listen on port 80.
resources: This section is used to define resource requests and limits for the container.
limits: Specifies the maximum amount of CPU and memory that the container is allowed to use. In this example, the container is limited to a maximum of 256 MiB of memory and 200 milliCPU (0.2 CPU cores).
requests: Specifies the initial amount of CPU and memory that the container requests when it starts. In this example, the container requests 128 MiB of memory and 100 milliCPU (0.1 CPU cores) initially.
livenessProbe: The liveness probe checks whether the container is still alive. It uses an HTTP GET request to the / path on port 80 of the container. If the probe fails, K8s will restart the container.
readinessProbe: The readiness probe checks whether the container is ready to serve traffic. It also uses an HTTP GET request to the / path on port 80 of the container. If the probe fails, the container is marked as not ready, and K8s won’t send traffic to it.
nodeAffinity is used to ensure that the Pods are scheduled only on nodes with a specific label. Pods will be required to be scheduled on nodes with the label node-type: nginx-node.
podAntiAffinity is used to ensure that no two NGINX Pods with the label app: nginx are scheduled on the same node. The topologyKey specifies that the scheduling is based on the hostname of the nodes.

apiVersion

→ This refers to the version of Kubernetes.
→ API version consists of two things group name and Version.
→ There are several versions, and several objects are introduced with each version.
→ Some common ones are v1, apps/v1, and extensions/v1beta1.
→ On the right-hand side, you can see the different types of values.

You can check out the below command for the list of versions.
$ kubectl api-versions

Kind

→ This is the type of Kubernetes object. In this case (the example above), we’re creating a deployment.
→ You can see the other types of objects that we create commonly on the right side here.
→ You can check out the below command for the list of kinds.

$ kubectl api-resources | awk '{print $5}'

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 (deployment in our case), the labels, and the annotation. → name the object is the only mandatory field and the remaining are optional. → You can check out the official Kubernetes documentation for the metadata field.

Spec:

**In the spec section, ** → First, the replicas that define the number pod of instances that deploy and should keep alive.
→ Next, we use a label selector to tell the deployment which pods are part of the deployment.
→ This essentially says all the pods matching these labels are grouped in our deployment.
→ After that, we have the template object. It’s essentially a pod template packed inside our deployment spec.
→ When the deployment creates pods, it will create them using this template!
→ For this example, we are deploying a replicate with four pods of the instance with an nginx docker image.
→ Kubernetes uses default deployment strategies called RollingUpdate to recreate pods.
→ Even if didn't mention any deployment strategy in the deployment YAML file, Kubernetes manage the pods and replica set with a RollingUpdate strategy.
→ If we compare the replica set and deployment YAML file both look almost the same. there is only one field different that is kind since we are creating a deployment object.
→ Deployment is responsible for two things, One is scaling and another is application deployment.

Deployment Strategies -

1. Recreate Deployment Strategy

In recreate deployment, we fully scale down the existing application version before we scale up the new application version. In the below diagram, Version 1 represents the current application version, and Version 2 represents the new application version. When updating the current application version, we first scale down the existing replicas of Version 1 to zero and then concurrently deploy replicas with the new version.

recreate-deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.27
        ports:
        - containerPort: 80
        readinessProbe: # Incorporating probes.
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 30
          failureThreshold: 2
        # NOTE: The default Nginx container does not include a "/health" endpoint.
        # Adjust the path below to point to a valid health check endpoint in your application.
        livenessProbe:
          httpGet:
            path: / # Default path; adjust as necessary for your application's health check.
            port: 80
          initialDelaySeconds: 15
          failureThreshold: 2
          periodSeconds: 45
$ kubectl apply -f recreate-deploy.yaml

$ kubectl rollout status deployment/nginx-deployment

2. RollingUpdate Deployment Strategy :

The rolling deployment is the default deployment strategy in Kubernetes. It replaces pods, one by one, of the previous version of our application with pods of the new version without any cluster downtime. A rolling deployment slowly replaces instances of the previous version of an application with instances of the new version of the application.

rolling-update-deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
        readinessProbe: # Incorporating probes.
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 30
          failureThreshold: 2
        # NOTE: The default Nginx container does not include a "/health" endpoint.
        # Adjust the path below to point to a valid health check endpoint in your application.
        livenessProbe:
          httpGet:
            path: / # Default path; adjust as necessary for your application's health check.
            port: 80
          initialDelaySeconds: 15
          failureThreshold: 2
          periodSeconds: 45

→ Kubernetes uses two deployment strategies called Recreate and RollingUpdate to recreate pods.
→ We can define those strategies in .spec.strategy.type field. → The RollingUpdate strategy is the default for deployments.

Recreate will delete all the existing pods before creating the new pods.
RollingUpdate will recreate the pods in a rolling update fashion. Moreover, it will delete and recreate pods gradually without interrupting the application availability.
This strategy utilizes the maxUnavailable and maxSurge values to control the rolling update process. maxSurge: The number of pods that can be created above the desired amount of pods during an update. This can be an absolute number or percentage of the replicas count. The default is 25%. maxUnavailable: The number of pods that can be unavailable during the update process. This can be an absolute number or a percentage of the replicas count; the default is 25%.

To understand the maxSurge and maxUnavailable, let’s go through the above configuration. let’s assume that we already have four instances of pods running with Nginx.
Now, when we initiate the upgrade from Nginx -1.8 to 1.9 using this YAML file, then it will first create two new pods with Nginx 1.9 and after a successful configuration, then it will delete the two pods running with Nginx 1.8.
After that, it will create two more pods with nginx1.9 and once both pods are running, it will delete old Nginx pods ie Nginx-1.8 In the end, you will have four pods instances running with nginx1.9

$ kubectl apply -f rolling-update-deploy.yaml

$ kubectl rollout status deployment/nginx-deployment

$ kubectl describe pod nginx-deployment-XXXXX |grep "Image"

$ kubectl set image deployment/nginx-deployment nginx=nginx:1.27

$ kubectl edit deployment/nginx-deployment

$ kubectl get rs

$ kubectl describe rs nginx-deployment-XXXXX

$ kubectl describe deploy nginx-deployment

If you update a Deployment while an existing rollout is in progress, the Deployment creates a new ReplicaSet as per the update and start scaling that up, and rolls over the ReplicaSet that it was scaling up previously -- it will add it to its list of old ReplicaSets and start scaling it down. For example, suppose you create a Deployment to create 5 replicas of nginx:1.14.2, but then update the Deployment to create 5 replicas of nginx:1.16.1, when only 3 replicas of nginx:1.14.2 had been created. In that case, the Deployment immediately starts killing the 3 nginx:1.14.2 Pods that it had created, and starts creating nginx:1.16.1 Pods. It does not wait for the 5 replicas of nginx:1.14.2 to be created before changing course.

2. Rolling Back a Deployment

$ kubectl rollout history deployment/nginx-deployment                 # check the revisions of this Deployment

$ kubectl rollout history deployment/nginx-deployment --revision=5    #To see the details of each revision

$ kubectl rollout undo deployment/nginx-deployment                    # Rollback to previous version

$ kubectl rollout undo deployment/nginx-deployment --to-revision=5    #  Rollback to a specific revision by specifying it with --to-revision 

3. Blue-Green Deployment Strategy:

The Blue-Green Kubernetes deployment strategy is a technique for releasing new versions of an application to minimise downtime and risk. It involves running two identical environments, one serving as the active production environment (blue) and the other as a new release candidate (green). The new release candidate is thoroughly tested before being switched with the production environment, allowing for a smooth transition without any downtime or errors.
After the deployment succeeds, we can either keep the blue deployment for a possible rollback or decommission it. Alternatively, it is possible to deploy a newer version of the application on these instances. In that case, the current (blue) environment serves as the staging area for the next release.
This technique can eliminate downtime as we faced in the recreate deployment strategy. In addition, blue-green deployment reduces risk: if something unexpected happens with our new version on Green, we can immediately roll back to the last version by switching back to Blue. There is instant rollout/rollback. We can also avoid versioning issues; the entire application state is changed in one deployment.

blue.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: blue-deployment
spec:
  selector:
    matchLabels:
      app: blue-deployment
      version: grafana-v1
  replicas: 3
  template:
    metadata:
      labels:
        app: blue-deployment
        version: grafana-v1
    spec:
      containers:
        - name: blue-deployment
          image: grafana/grafana:10.2.8

green.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: green-deployment
spec:
  selector:
    matchLabels:
      app: green-deployment
      version: grafana-v2
  replicas: 3
  template:
    metadata:
      labels:
        app: green-deployment
        version: grafana-v2
    spec:
      containers:
        - name: green-deployment
          image: grafana/grafana:10.3.7

blue-green-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: blue-green-service
  labels:
    app: blue-green-deployment
    version: grafana-v1
spec:
  ports:
    - name: http
      port: 8001
      targetPort: 3000
  selector:
    app: blue-deployment
    version: grafana-v1
  type: NodePort

Ingress Controller Create:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.1/deploy/static/provider/cloud/deploy.yaml
kubectl get pods --namespace=ingress-nginx
kubectl get pods --namespace=ingress-nginx
kubectl get pods --namespace=ingress-nginx
kubectl create deployment demo --image=httpd --port=80
kubectl expose deployment demo
kubectl create ingress demo-localhost --class=nginx \\n  --rule="demo.localdev.me/*=demo:80"
kubectl port-forward --namespace=ingress-nginx service/ingress-nginx-controller 8080:80
⚠️ **GitHub.com Fallback** ⚠️