<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: robudexIT</title>
    <description>The latest articles on Forem by robudexIT (@robudexit).</description>
    <link>https://forem.com/robudexit</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1268827%2F776b7df4-dd92-49b7-8792-89145c7b85e7.png</url>
      <title>Forem: robudexIT</title>
      <link>https://forem.com/robudexit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/robudexit"/>
    <language>en</language>
    <item>
      <title>The Kubernetes Resume Challenge</title>
      <dc:creator>robudexIT</dc:creator>
      <pubDate>Tue, 26 Mar 2024 21:49:04 +0000</pubDate>
      <link>https://forem.com/robudexit/the-kubernetes-resume-challenge-2joi</link>
      <guid>https://forem.com/robudexit/the-kubernetes-resume-challenge-2joi</guid>
      <description>&lt;h2&gt;
  
  
  Project Title: The Kubernetes Resume Challenge
&lt;/h2&gt;

&lt;h2&gt;
  
  
  ProjectRepo: &lt;a href="https://github.com/robudexIT/resume-k8-challenge"&gt;https://github.com/robudexIT/resume-k8-challenge&lt;/a&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Project Architecture:
&lt;/h2&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvdfdtr849h9u95af4yik.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvdfdtr849h9u95af4yik.png" alt="Project Architecture" width="800" height="572"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  Project Overview:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;: This project is based on the guidelines provided by Cloud Resume Challenge.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Objective&lt;/strong&gt;: The primary objective of this project is to deploy an application with a focus on scalability, consistency, and availability using Docker and Kubernetes technologies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Key Features&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deployment of applications leveraging Docker containers for efficient management and isolation.&lt;/li&gt;
&lt;li&gt;Utilization of Kubernetes features such as deployments, services, configmaps, secrets, persistent volumes, and autoscaling to enhance scalability and reliability.&lt;/li&gt;
&lt;li&gt;Implementation of best practices for ensuring consistency and availability of the deployed application.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Exploration&lt;/strong&gt;: The project will delve into various aspects of Kubernetes, including but not limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up deployments for managing application instances.&lt;/li&gt;
&lt;li&gt;Configuring services to enable communication and load balancing.&lt;/li&gt;
&lt;li&gt;Utilizing configmaps and secrets for managing configuration and sensitive data.&lt;/li&gt;
&lt;li&gt;Implementing persistent volumes to ensure data persistence in Database Pods.&lt;/li&gt;
&lt;li&gt;Incorporating autoscaling mechanisms to dynamically adjust resources based on workload demands in Application Pods.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CI/CD Integration&lt;/strong&gt;: To streamline the development workflow, continuous integration and deployment (CI/CD) will be facilitated using GitHub Actions. This will enable automated building and deployment of code changes, ensuring a smooth and efficient development process.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  Project Prerequisite
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Dockerhub account&lt;/li&gt;
&lt;li&gt;Digital Ocean Account for Kubernetes Service &lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  Project Flow of Execution:
&lt;/h2&gt;


&lt;h4&gt;
  
  
  Create resume-k8-challenge project directory and cd to it.
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  mkdir resume-k8-challenge
  cd resume-k8-challenge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Clone &lt;a href="https://github.com/kodekloudhub/learning-app-ecommerce"&gt;https://github.com/kodekloudhub/learning-app-ecommerce&lt;/a&gt; and rename the it to app
&lt;/h3&gt;

&lt;p&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; git clone https://github.com/kodekloudhub/learning-app-ecommerce.git
 mv learning-app-ecommerce/ app/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Goto app/ directory and delete the .git directory
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  cd app
  rm -rf .git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Go back to resume-k8-challenge directory and create Dockerfile and build the Docker Image and push it to dockerhub
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; cd ..
 touch Dockerfile 
 vim Dockerfile 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM php:7.4-apache

RUN apt update -y

RUN docker-php-ext-install mysqli pdo pdo_mysql

COPY ./app /var/www/html/

ENV DB_HOST=mariadb-service

EXPOSE 80

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;**FROM php:7.4-apache&lt;br&gt;
**This line specifies the base image for your Docker container. In this case, it uses the PHP 7.4 version with Apache pre-installed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RUN apt update -y&lt;/strong&gt;&lt;br&gt;
This command updates the package lists inside the container (apt update) and the -y flag automatically answers yes to any prompts, ensuring a non-interactive update.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RUN docker-php-ext-install mysqli pdo pdo_mysql&lt;/strong&gt;&lt;br&gt;
This command installs PHP extensions required for database connectivity. Specifically, it installs the MySQL and PDO &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;COPY ./app /var/www/html/&lt;/strong&gt;&lt;br&gt;
This line copies the contents of the app directory from your local machine into the /var/www/html/ directory inside the Docker container. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ENV DB_HOST=mariadb-service&lt;/strong&gt;&lt;br&gt;
This line sets an environment variable DB_HOST with the value mariadb-service. Environment variables are used to configure settings within the container, and in this case, DB_HOST likely specifies the host name or IP address of a MariaDB database server that your PHP application will connect to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EXPOSE 80&lt;/strong&gt;&lt;br&gt;
This instruction exposes port 80 on the container. &lt;/p&gt;

&lt;p&gt;Note: the &lt;strong&gt;mariadb-service **this **ENV DB_HOST=mariadb-service&lt;/strong&gt; in the Dockerfile&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
*&lt;em&gt;Build and Push the Docker Image: *&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; docker build -t robudex17/ecom-web:v1 .
 docker login
 docker push robudex17/ecom-web:v1

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Verify on your dockerhub account the image was successfully push:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj84mmbpw2h8c80stsgsp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj84mmbpw2h8c80stsgsp.png" alt="Verify-dockerhub" width="680" height="144"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h4&gt;
  
  
  Set Up Kubernetes on a Public Cloud Provider
&lt;/h4&gt;

&lt;p&gt;For Kubernetes, I will use Digital Ocean&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install kubectl on your develepoment workstation.For installation, here's  link:(&lt;a href="https://kubernetes.io/docs/tasks/tools/"&gt;https://kubernetes.io/docs/tasks/tools/&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Login to Your Digital Ocean Account and Click Kubernetes
 For this project, I will create only 2 nodes with the Basic Machine type.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiatinogzu8xjvqp8ux6t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiatinogzu8xjvqp8ux6t.png" alt="Image description" width="800" height="258"&gt;&lt;/a&gt;&lt;br&gt;
     scroll down at the bottom and click &lt;strong&gt;Create Cluster&lt;/strong&gt; button.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It will take some time to create the Kubernetes Cluster. Once finished, select your newly created Kubernetes Cluster Manual tab and click the 'download the cluster configuration file'. This configuration will be needed to access your cluster from your development workstation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Copy the configuration file to the .kube/ directory and test your cluster using the kubectl get nodes command. It should return your two Kubernetes Nodes.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  cp yourcluster-kubernetes-cluster-kubeconfig.yaml ~/.kube/config

  kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqr3mo1e1ub0ozkipdsu1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqr3mo1e1ub0ozkipdsu1.png" alt="Image description" width="643" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now that our Kubernetes cluster and Docker images are ready, it's time to deploy the apps on the cluster.

&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Deploy The Apps in  Kubernetes.
&lt;/h4&gt;

&lt;p&gt;To organize all my Kubernetes manifests in one location, I created a 'kubernetes' folder in my project directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  mkdir kubernetes 
  cd kubernetes 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;We will start by creating our mariadb &lt;strong&gt;secrets&lt;/strong&gt;, &lt;strong&gt;configmap&lt;/strong&gt;, &lt;strong&gt;persistent-volume **, **deployment&lt;/strong&gt; and &lt;strong&gt;service&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  touch db-secrets.yaml
  touch db-configmap.yaml
  touch db-storage-class.yaml
  touch db-pv.yaml
  touch db-pvc.yaml 
  touch db-deployment.yaml 
  touch db-service.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;p&gt;*&lt;em&gt;db-secrets.yaml *&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
stringData:
  rootpassword: password123
  dbuser: ecomuser
  dbpassword: ecompassword
  dbname: ecomdb


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This YAML file defines a &lt;strong&gt;secret&lt;/strong&gt;, which is a way to store sensitive information securely in Kubernetes.&lt;/p&gt;

&lt;p&gt;The name of this secret is "&lt;strong&gt;db-secret&lt;/strong&gt;". You can think of it like a locked box where you keep important information.&lt;/p&gt;

&lt;p&gt;The type "&lt;strong&gt;Opaque&lt;/strong&gt;" means that Kubernetes doesn't interpret the data in any specific way. It's just raw, arbitrary data.&lt;/p&gt;

&lt;p&gt;Inside this secret, there are four pieces of sensitive information:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;rootpassword&lt;/strong&gt;: This is the password for the main administrator (root) of a database system, like MySQL. In this example, it's set to "&lt;strong&gt;password123&lt;/strong&gt;". You should replace this with your actual root password.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;dbuser&lt;/strong&gt;: This is the username used to access the database. In this case, it's "ecomuser". Replace it with the actual username you want to use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;dbpassword&lt;/strong&gt;: This is the password for the database user (ecomuser). For security reasons, it's set to "&lt;strong&gt;ecompassword&lt;/strong&gt;" here, but you should use a strong and secure password.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;dbname&lt;/strong&gt;: This is the name of the database itself, such as "&lt;strong&gt;ecomdb&lt;/strong&gt;". Replace it with the actual name of your database.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;db-configmap.yaml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: ConfigMap
metadata:
  name: db-config
data:
  db-load-script.sql: |
    USE ecomdb;
    CREATE TABLE products (
      id mediumint(8) unsigned NOT NULL auto_increment,
      Name varchar(255) default NULL,
      Price varchar(255) default NULL,
      ImageUrl varchar(255) default NULL,
      PRIMARY KEY (id)
    ) AUTO_INCREMENT=1;

    INSERT INTO products (Name, Price, ImageUrl)
    VALUES
      ("Laptop", "100", "c-1.png"),
      ("Drone", "200", "c-2.png"),
      ("VR", "300", "c-3.png"),
      ("Tablet", "50", "c-5.png"),
      ("Watch", "90", "c-6.png"),
      ("Phone Covers", "20", "c-7.png"),
      ("Phone", "80", "c-8.png"),
      ("Laptop", "150", "c-4.png");

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;apiVersion&lt;/strong&gt;: &lt;strong&gt;v1&lt;/strong&gt;: Specifies the Kubernetes API version being used, which is v1 for this ConfigMap resource.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;kind&lt;/strong&gt;: &lt;strong&gt;ConfigMap&lt;/strong&gt;: Defines that this YAML manifest describes a Kubernetes ConfigMap resource.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;metadata&lt;/strong&gt;:: Contains metadata about the &lt;strong&gt;ConfigMap&lt;/strong&gt;, such as its name.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: &lt;strong&gt;db-config&lt;/strong&gt;: Specifies the name of the ConfigMap resource as "&lt;strong&gt;db-config&lt;/strong&gt;". This is how you will refer to this ConfigMap within your Kubernetes cluster.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;&lt;strong&gt;data&lt;/strong&gt;:: Contains the actual data stored in the ConfigMap, using key-value pairs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;db-load-script.sql&lt;/strong&gt;: |: This key-value pair stores a SQL script as the value, with the &lt;strong&gt;key&lt;/strong&gt; "&lt;strong&gt;db-load-script.sql&lt;/strong&gt;". The &lt;strong&gt;|&lt;/strong&gt; indicates that the following lines are part of a** multi-line** string.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;db-storage-class.yaml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration in Kubernetes is like setting up a special storage rule called "&lt;strong&gt;local-storage&lt;/strong&gt;."&lt;/p&gt;

&lt;p&gt;It tells Kubernetes that we're not using any special tool to create new storage. Instead, we already have storage set up outside of Kubernetes.&lt;/p&gt;

&lt;p&gt;When something needs storage (like a program running in Kubernetes), Kubernetes waits until that program asks for storage before providing it. This helps use storage resources more efficiently.&lt;/p&gt;

&lt;p&gt;If we need to make our storage bigger in the future, this configuration allows us to do that. It's like having the flexibility to add more space to our storage if we need it later on.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;db-pv.yaml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: PersistentVolume
metadata:
  name: mariadb-persistent-volume
spec:
  storageClassName: local-storage
  persistentVolumeReclaimPolicy: Recycle
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /var/mariadb

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;apiVersion&lt;/strong&gt;: &lt;strong&gt;v1&lt;/strong&gt;: Specifies the Kubernetes API version being used, which is v1 for the PersistentVolume resource.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;kind&lt;/strong&gt;: PersistentVolume: Indicates that this YAML manifest describes a Kubernetes PersistentVolume resource, which represents storage in the cluster that has a lifecycle independent of any individual pod using the volume.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;metadata&lt;/strong&gt;:: Contains metadata about the PersistentVolume, such as its name.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: &lt;strong&gt;mariadb-persistent-volume&lt;/strong&gt;: Specifies the name of the PersistentVolume resource as "&lt;strong&gt;mariadb-persistent-volume&lt;/strong&gt;". This is how you will refer to this PersistentVolume within your Kubernetes cluster.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;&lt;strong&gt;spec&lt;/strong&gt;:: Defines the specifications for the PersistentVolume.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;storageClassName&lt;/strong&gt;: local-storage: Specifies the StorageClass that this PersistentVolume should use. In this case, it's set to "local-storage", which we defined earlier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;persistentVolumeReclaimPolicy&lt;/strong&gt;: Recycle: Sets the reclaim policy for the PersistentVolume. The value "Recycle" means that when the PersistentVolume is released, its resources will be recycled and made available for reuse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;capacity&lt;/strong&gt;:: Specifies the storage capacity of the PersistentVolume.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;storage&lt;/strong&gt;: 10Gi: Sets the storage capacity to 10 gigabytes (10Gi). This indicates how much storage space is available in this PersistentVolume.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;accessModes&lt;/strong&gt;:: Defines the access modes for the PersistentVolume.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ReadWriteOnce&lt;/strong&gt;: Specifies that the volume can be mounted as read-write by a single node at a time. This access mode is suitable for scenarios where only one pod needs read-write access to the volume.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;hostPath&lt;/strong&gt;:: Specifies the host path where the PersistentVolume will be located.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;path&lt;/strong&gt;: &lt;strong&gt;/var/mariadb&lt;/strong&gt;: Sets the host path to "/var/mariadb", indicating that the PersistentVolume will use storage located at that path on the host machine.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;db-pvc.yaml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mariadb-pvc
spec:
  storageClassName: local-storage
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;apiVersion&lt;/strong&gt;: &lt;strong&gt;v1&lt;/strong&gt;: Specifies the Kubernetes API version being used, which is v1 for the PersistentVolumeClaim resource.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;kind&lt;/strong&gt;: &lt;strong&gt;PersistentVolumeClaim&lt;/strong&gt;: Indicates that this YAML manifest describes a Kubernetes PersistentVolumeClaim resource, which is a request for storage resources from a StorageClass.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;metadata&lt;/strong&gt;:: Contains metadata about the PersistentVolumeClaim, such as its name.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: &lt;strong&gt;mariadb-pvc&lt;/strong&gt;: Specifies the name of the PersistentVolumeClaim resource as "&lt;strong&gt;mariadb-pvc&lt;/strong&gt;". This is how you will refer to this PersistentVolumeClaim within your Kubernetes cluster.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;&lt;strong&gt;spec&lt;/strong&gt;:: Defines the specifications for the PersistentVolumeClaim.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;storageClassName&lt;/strong&gt;: &lt;strong&gt;local-storage&lt;/strong&gt;: Specifies the StorageClass that this PersistentVolumeClaim should use. In this case, it's set to "local-storage", which we defined earlier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;accessModes&lt;/strong&gt;:: Defines the access modes for the PersistentVolumeClaim.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ReadWriteOnce&lt;/strong&gt;: Specifies that the volume can be mounted as read-write by a single node at a time. This access mode is suitable for scenarios where only one pod needs read-write access to the volume.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;resources&lt;/strong&gt;:: Specifies the requested resources for the PersistentVolumeClaim.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;requests&lt;/strong&gt;:: Indicates the requested resources within the PersistentVolumeClaim.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;storage&lt;/strong&gt;: &lt;strong&gt;10Gi&lt;/strong&gt;: Requests 10 gigabytes (10Gi) of storage capacity. This tells Kubernetes that the PersistentVolumeClaim needs at least 10 gigabytes of storage to be provisioned from the StorageClass.

&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note: Because I will utilize one of my Kubernetes nodes' storage in a&lt;br&gt;
&lt;strong&gt;PersistentVolume&lt;/strong&gt;, ensuring that MySQL deploys on that node. This will be&lt;br&gt;
achieved by adding a label to the node and using this label in the&lt;br&gt;
deployment. Here are the commands:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  kubectl get nodes
  kubectl label nodes &amp;lt;YOUR-CHOOSEN-NODENAME&amp;gt; nodetype=database
  kubectl get node mynode-pool-o6fg9 --show-labels

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fud47ltg365qef2pyvaov.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fud47ltg365qef2pyvaov.png" alt="Image description" width="619" height="161"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;db-deployment.yaml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: mariadb
  labels:
    db: mariadb
spec:
  #replicas: 3
  selector:
    matchLabels:
      db: mariadb
  template:
    metadata:
      labels:
        db: mariadb
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
                - key: nodetype
                  operator: In
                  values:
                    - database      
      volumes: 
        - name: initial-data 
          configMap: 
            name: db-config
        - name: mariadb-persistend-storage 
          persistentVolumeClaim:
            claimName: mariadb-pvc  
      containers:   
        - name: ecomdb 
          image: 'mariadb:latest'
          volumeMounts:
            - name: initial-data 
              mountPath: /docker-entrypoint-initdb.d
            - name: mariadb-persistend-storage
              mountPath: /var/lib/mysql    
          env:
            - name: MARIADB_ROOT_PASSWORD 
              valueFrom: 
                secretKeyRef:
                  name: db-secret
                  key: rootpassword 
            - name: MARIADB_DATABASE 
              valueFrom: 
                secretKeyRef: 
                  name: db-secret 
                  key: dbname  
            - name: MARIADB_USER 
              valueFrom: 
                secretKeyRef: 
                  name: db-secret 
                  key: dbuser  
            - name: MARIADB_PASSWORD 
              valueFrom: 
                secretKeyRef: 
                  name: db-secret 
                  key: dbpassword 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;apiVersion&lt;/strong&gt;: &lt;strong&gt;apps/v1&lt;/strong&gt;: Specifies the Kubernetes API version being used, which is apps/v1 for the Deployment resource.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;kind&lt;/strong&gt;: &lt;strong&gt;Deployment&lt;/strong&gt;: Indicates that this YAML manifest describes a Kubernetes Deployment resource, which manages the lifecycle of pods.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;metadata&lt;/strong&gt;:: Contains metadata about the Deployment, such as its name and labels.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: &lt;strong&gt;mariadb&lt;/strong&gt;: Specifies the name of the Deployment as "mariadb". This is how you will refer to this Deployment within your Kubernetes cluster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;labels&lt;/strong&gt;:: Specifies labels for identifying instances managed by this Deployment, with the label "db: mariadb" indicating that it's related to the MariaDB database.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;&lt;strong&gt;spec&lt;/strong&gt;:: Defines the specifications for the Deployment.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;selector&lt;/strong&gt;:: Specifies how the Deployment identifies which pods to manage.&lt;/li&gt;
&lt;li&gt;matchLabels:: Specifies that pods managed by this Deployment must have the label "db: mariadb".&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;template&lt;/strong&gt;:: Defines the pod template used to create pods managed by the Deployment.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;metadata&lt;/strong&gt;:: Contains labels for the pod.

&lt;ul&gt;
&lt;li&gt;labels:: Specifies labels for identifying pods created from this template, with the label "db: mariadb" indicating that it's related to the MariaDB database.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;spec&lt;/strong&gt;:: Specifies the specifications for the pod.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;affinity&lt;/strong&gt;:: Specifies node affinity to ensure that pods are scheduled on nodes with a specific nodetype label (e.g., "database").&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;volumes&lt;/strong&gt;:: Defines volumes to be used by the pod.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: initial-data: Specifies a ConfigMap volume named "initial-data" to store initial database configuration data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: &lt;strong&gt;mariadb-persistent-storage&lt;/strong&gt;: Specifies a PersistentVolumeClaim volume named "mariadb-persistent-storage" to provide persistent storage for MariaDB data.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;&lt;strong&gt;containers&lt;/strong&gt;:: Defines the containers running in the pod.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: &lt;strong&gt;ecomdb&lt;/strong&gt;: Specifies the container name as "ecomdb".&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;image&lt;/strong&gt;: '&lt;strong&gt;mariadb:latest&lt;/strong&gt;': Specifies the Docker image to use for the container, which is the latest version of MariaDB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;volumeMounts&lt;/strong&gt;:: Specifies how volumes are mounted into the container.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: &lt;strong&gt;initial-data&lt;/strong&gt;: Mounts the "initial-data" ConfigMap volume at the path "/docker-entrypoint-initdb.d" inside the container, where MariaDB expects initialization scripts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: &lt;strong&gt;mariadb-persistent-storage&lt;/strong&gt;: Mounts the "mariadb-persistent-storage" PersistentVolumeClaim volume at the path "/var/lib/mysql" inside the container, where MariaDB stores its data.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;env&lt;/strong&gt;:: Sets environment variables for the container, which are fetched from a Secret named "db-secret".

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: &lt;strong&gt;MARIADB_ROOT_PASSWORD&lt;/strong&gt;: Sets the MariaDB root password from the "db-secret" Secret using a secretKeyRef.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: &lt;strong&gt;MARIADB_DATABASE&lt;/strong&gt;: Sets the MariaDB database name from the "db-secret" Secret using a secretKeyRef.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: &lt;strong&gt;MARIADB_USER&lt;/strong&gt;: Sets the MariaDB user from the "db-secret" Secret using a secretKeyRef.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt;: &lt;strong&gt;MARIADB_PASSWORD&lt;/strong&gt;: Sets the MariaDB user's password from the "db-secret" Secret using a secretKeyRef.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;db-service.yaml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: mariadb-service
spec:
  type: ClusterIP
  selector:
     db: mariadb
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;apiVersion&lt;/strong&gt;: &lt;strong&gt;v1&lt;/strong&gt;: Specifies the API version being used. In this case, it's using the core/v1 version of Kubernetes API.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;kind&lt;/strong&gt;: &lt;strong&gt;Service&lt;/strong&gt;: Defines the type of Kubernetes resource being created, which is a Service. A Service in Kubernetes is an abstraction that defines a logical set of Pods and a policy by which to access them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;metadata&lt;/strong&gt;: Contains metadata about the Service, such as its &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt; (mariadb-service in this case).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;&lt;strong&gt;spec&lt;/strong&gt;: Describes the desired state for the Service.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;type&lt;/strong&gt;: &lt;strong&gt;ClusterIP&lt;/strong&gt;: Specifies the type of Service. In this case, it's a ClusterIP Service, which means the Service will only be accessible from within the cluster.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;selector&lt;/strong&gt;: Specifies the Pods that this Service will route traffic to. In this manifest, it selects Pods with the label &lt;strong&gt;db: mariadb&lt;/strong&gt;, indicating that this Service will forward traffic to Pods labeled with db=mariadb.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ports&lt;/strong&gt;: Defines the ports that the Service will listen on and forward traffic to.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;protocol&lt;/strong&gt;: &lt;strong&gt;TCP&lt;/strong&gt;: Specifies the protocol being used for the port (TCP in this case).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;port&lt;/strong&gt;: &lt;strong&gt;3306&lt;/strong&gt;: Specifies the port number on which the Service will listen for incoming traffic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;targetPort&lt;/strong&gt;: &lt;strong&gt;3306&lt;/strong&gt;: Specifies the port number on the Pod to which the traffic will be forwarded. In this case, it's targeting port 3306, which is commonly used for MySQL/MariaDB database connections.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Now that all mariadb manifest files are created, it's time to apply it by this order.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;db-storage-class&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f db-storage-class.yaml
kubectl get storageclass.storage.k8s.io/local-storage
kubectl describe storageclass.storage.k8s.io/local-storage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgopc2gd9yiyymbp4c2ym.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgopc2gd9yiyymbp4c2ym.png" alt="Image description" width="667" height="276"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;db-persistent-volume&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f db-pv.yaml
kubectl get persistentvolume/mariadb-persistent-volume
kubectl describe persistentvolume/mariadb-persistent-volume
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1le6k1nfegg23n5g3dsq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1le6k1nfegg23n5g3dsq.png" alt="Image description" width="727" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;db-persistent-volume-claim&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f db-pvc.yaml
kubectl get persistentvolumeclaim/mariadb-pvc
kubectl describe persistentvolumeclaim/mariadb-pvc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fempkyxw7h8nmhqqb4wko.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fempkyxw7h8nmhqqb4wko.png" alt="Image description" width="728" height="337"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;DB SECRETS&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f db-secrets.yaml
kubectl get secret/db-secret
kubectl describe secret/db-secret
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzh6vvv6f274a5feekjle.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzh6vvv6f274a5feekjle.png" alt="Image description" width="685" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;DB-CONFIGMAP&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f db-configmap.yaml 
kubectl get configmap/db-config
kubectl describe configmap/db-config

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5w6uustmojpijhbewpny.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5w6uustmojpijhbewpny.png" alt="Image description" width="661" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;DB-DEPLOYMENT&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f db-deployment.yaml
kubectl get deployment.apps/mariadb
kubectl describe deployment.apps/mariadb

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fojn4r6kqbs6m69xprolv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fojn4r6kqbs6m69xprolv.png" alt="Image description" width="675" height="638"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see from the above output, there is a lot of information. Let's dissect it one by one.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, the db-deployment create replica-set name &lt;strong&gt;mariadb-5d7f6f9c6c&lt;/strong&gt; which create one mariadb pod.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;-This pod has environment variables, and the values are obtained from the secrets manifest or object.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It also has two mount points. The first is pointing to a ConfigMap object, and the second is pointing to a PersistentVolumeClaim.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you run the command kubectl get pv mariadb-persistent-volume and kubectl get pvc mariadb-pvc, you will notice that some values have been updated.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbx5m1k91642zckzofiub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbx5m1k91642zckzofiub.png" alt="Image description" width="716" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's check the status of our MariaDB pod to ensure it is working as expected and that all configurations are properly set up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fohmib0jkhoz524g0o6db.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fohmib0jkhoz524g0o6db.png" alt="Image description" width="654" height="686"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It seem, that all are properly setup. Its time to expose our mariab pods by the use of service manifest.&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;DB-SERVICE&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f db-deployment.yaml
kubectl get deployment.apps/mariadb
kubectl describe deployment.apps/mariadb

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5rjrf0oyszgq4obibrw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5rjrf0oyszgq4obibrw.png" alt="Image description" width="652" height="379"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;br&gt;&lt;br&gt;
Now that our database are setup lets proceed to creating our ecomm-app &lt;strong&gt;configmap&lt;/strong&gt;** deployment** and &lt;strong&gt;service&lt;/strong&gt; manifest&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;APP-CONFIGMAP&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: ConfigMap
metadata:
  name: feature-toggle-config
data:
  FEATURE_DARK_MODE: "false"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;apiVersion&lt;/strong&gt;: &lt;strong&gt;v1&lt;/strong&gt;: Specifies the Kubernetes API version being used, which is the core/v1 version in this case.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;kind&lt;/strong&gt;: &lt;strong&gt;ConfigMap&lt;/strong&gt;: Indicates that this YAML is defining a ConfigMap resource.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;metadata.name&lt;/strong&gt;: &lt;strong&gt;feature-toggle-config&lt;/strong&gt;: Sets the name of the ConfigMap as feature-toggle-config.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;data: Contains the actual data entries for the ConfigMap.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FEATURE_DARK_MODE&lt;/strong&gt;: "&lt;strong&gt;false&lt;/strong&gt;": Defines a key-value pair within the ConfigMap. The key is &lt;strong&gt;FEATURE_DARK_MODE&lt;/strong&gt;, representing a feature toggle for dark mode, and the value is "false", indicating that dark mode is currently disabled.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;APP-DEPLOYMENT&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: ecomapp
  labels:
    app: ecomapp
spec:
  selector: 
    matchLabels: 
      app: ecomapp
  template:
    metadata:
      labels:
        app: ecomapp
    spec:
      containers:
      - image: robudex17/ecom-web:v2
        name: ecomapp
        imagePullPolicy: Always
        ports:
        - containerPort: 80
          name: ecomapp
        resources:
          requests:
            cpu: "250m"
            memory: "128Mi"
          limits: 
           cpu: "250m"
           memory: "128Mi"    
        env:
          - name: FEATURE_DARK_MODE 
            valueFrom: 
              configMapKeyRef:
                name: feature-toggle-config 
                key: FEATURE_DARK_MODE
          - name: DB_NAME
            valueFrom:
              secretKeyRef:
                name: db-secret
                key: dbname
          - name: DB_USER 
            valueFrom: 
              secretKeyRef: 
                name: db-secret 
                key: dbuser 
          - name: DB_PASSWORD 
            valueFrom:  
              secretKeyRef: 
                name: db-secret 
                key: dbpassword 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;apiVersion: apps/v1&lt;/strong&gt;: Specifies the Kubernetes API version being used, specifically the apps/v1 version for Deployments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;kind: Deployment&lt;/strong&gt;: Indicates that this YAML is defining a Deployment resource.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;metadata.name: ecomapp&lt;/strong&gt;: Sets the name of the Deployment as ecomapp.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;metadata.labels.app: ecomapp&lt;/strong&gt;: Assigns a label app: ecomapp to the Deployment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;spec&lt;/strong&gt;: Describes the desired state for the Deployment.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;selector.matchLabels.app: ecomapp&lt;/strong&gt;: Specifies that Pods managed by this Deployment should have the label app: ecomapp.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;template&lt;/strong&gt;: Defines the Pod template used by the Deployment to create and manage Pods.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;metadata.labels.app: ecomapp&lt;/strong&gt;: Assigns a label app: ecomapp to the Pods created from this template.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;spec&lt;/strong&gt;: Specifies the specifications for the  containers running in the Pods.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;containers&lt;/strong&gt;: Defines the containers running in the Pod.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;image: robudex17/ecom-web:v1&lt;/strong&gt;: Specifies the container image to use for the application, pulled from &lt;strong&gt;robudex17/ecom-web:v1&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;name: ecomapp&lt;/strong&gt;: Sets the name of the container as ecomapp.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;imagePullPolicy: Always&lt;/strong&gt;: Specifies that Kubernetes should always pull the latest version of the container image.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ports&lt;/strong&gt;: Specifies that the container exposes port 80 as ecomapp.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;resources&lt;/strong&gt;: Defines the resource requests and limits for the container (CPU and memory).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;env&lt;/strong&gt;: Specifies environment variables for the container.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name: FEATURE_DARK_MODE&lt;/strong&gt;: Sets an environment variable &lt;strong&gt;FEATURE_DARK_MODE&lt;/strong&gt; using a value retrieved from a ConfigMap named &lt;strong&gt;feature-toggle-config&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;name: DB_NAME&lt;/strong&gt;: Sets an environment variable DB_NAME using a value retrieved from a Secret named &lt;strong&gt;db-secret&lt;/strong&gt; with the key &lt;strong&gt;dbname&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;name: DB_USER&lt;/strong&gt;: Sets an environment variable &lt;strong&gt;DB_USER&lt;/strong&gt; using a value retrieved from a Secret named db-secret with the key &lt;strong&gt;dbuser&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;name: DB_PASSWORD&lt;/strong&gt;: Sets an environment variable &lt;strong&gt;DB_PASSWORD&lt;/strong&gt; using a value retrieved from a Secret named &lt;strong&gt;db-secret&lt;/strong&gt; with the key &lt;strong&gt;dbpassword&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;APP-SERVICE&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: Service
metadata:
  name: app-service
spec:

  type: LoadBalancer
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

  selector:
    app: ecomapp

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;apiVersion: v1&lt;/strong&gt;: Specifies the Kubernetes API version being used. In this case, it's using API version v1, which is the core Kubernetes API version.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;kind: Service&lt;/strong&gt;: Defines the type of Kubernetes resource being created, which is a Service. A Service in Kubernetes is an abstraction that enables access to a set of Pods in a uniform way.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;metadata&lt;/strong&gt;: Contains metadata about the Service, such as its name.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;name: app-service: Specifies the name of the Service as "app-service".&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;spec&lt;/strong&gt;: Describes the desired state for the Service, including its type, ports, and selector.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;type: LoadBalancer&lt;/strong&gt;: Specifies the type of Service. In this case, it's a LoadBalancer type, which exposes the Service externally using a cloud provider's load balancer (if available).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ports&lt;/strong&gt;: Defines the ports that the Service will listen on and where traffic will be directed.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;protocol&lt;/strong&gt;: &lt;strong&gt;TCP&lt;/strong&gt;: Specifies the protocol used for the port, which is TCP in this case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;port: 80&lt;/strong&gt;: Defines the port number on which the Service will listen within the cluster (internal port).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;targetPort: 80:&lt;/strong&gt; Specifies the target port on the Pods to which the traffic will be forwarded. In this example, traffic received on port 80 of the Service will be forwarded to port 80 on the Pods.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;selector&lt;/strong&gt;: Defines how the Service selects which Pods to target. In this case, it uses a label selector to target Pods with the label &lt;strong&gt;"app: ecomapp"&lt;/strong&gt;. This means that the Service will route traffic to Pods that have the label "app" with the value "ecomapp".&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Now that all ecomapp manifest files are created, it's time to apply them in this order.&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;APP-CONFIGMAP&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  kubectl apply -f app-configmap.yaml
  kubectl get configmap/feature-toggle-config
  kubectl describe  configmap/feature-toggle-config

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9b2ndyh819e6d0o867nb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9b2ndyh819e6d0o867nb.png" alt="Image description" width="719" height="329"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;APP-DEPLOYMENT&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; kubectl apply -f app-deployment.yaml
 kubectl get  deployment.apps/ecomapp
 kubectl describe deployment.apps/ecomapp

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4i1uzvfr0o3k89qzp7fa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4i1uzvfr0o3k89qzp7fa.png" alt="Image description" width="732" height="645"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see from the above output, there is a lot of information. Let's dissect it one by one.&lt;/p&gt;

&lt;p&gt;First, the app-deployment create replica-set name &lt;strong&gt;ecomapp-b89445bf&lt;/strong&gt; which then create one &lt;strong&gt;ecomapp pod&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This Pod have environment variables and the values came from the &lt;strong&gt;secrets&lt;/strong&gt; and &lt;strong&gt;configmap&lt;/strong&gt; manifest.&lt;/p&gt;

&lt;p&gt;It use our image &lt;strong&gt;/ecom-web:v1&lt;/strong&gt; that we create earlier &lt;/p&gt;

&lt;p&gt;If you run the command &lt;strong&gt;kubectl get pods -o wide&lt;/strong&gt; you will see that there's one ecomapp pod created&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo2i7mungqmbvfoqy2wuf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo2i7mungqmbvfoqy2wuf.png" alt="Image description" width="746" height="131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Currently, our app can only be accessed within the Kubernetes cluster. To access it from the outside world, we need to expose it using a service.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;APP-SERVICE&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  kubectl apply -f app-service.yaml
  kubectl get service/app-service
  kubectl describe service/app-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3s7rppd6g6cztxen6cbc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3s7rppd6g6cztxen6cbc.png" alt="Image description" width="730" height="491"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;As you can see, the EXTERNAL-IP status is in pending mode. It takes some time for it to resolve. You can run kubectl get service/app-service to check the status."&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
After a couple of minutes, it finally resolved the EXTERNAL-IP&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltk9m9os6v4m0bzrky8u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fltk9m9os6v4m0bzrky8u.png" alt="Image description" width="800" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Copy the EXTERNAL-IP and paste it to the browser address bar.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8uog9gogxk4y6lj5ebtl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8uog9gogxk4y6lj5ebtl.png" alt="Image description" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
And indeed it is working...&lt;/p&gt;



&lt;p&gt;Let's update our app to add a dark theme and use our app-config-map to toggle between themes. Currently, our FEATURE_DARK_MODE is set to false. Let's set it so that when FEATURE_DARK_MODE is true, our app will use the dark theme, and if it's false, it will return to its default white theme.&lt;/p&gt;



&lt;p&gt;Here's I do it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; In app/css I add &lt;strong&gt;dark-theme.css&lt;/strong&gt; and  add this css code.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* Set the background color to black and text color to white */
body {
    background-color: #1a1a1a;
    color: #ffffff;
}

/* Style links */
a {
    color: #ffffff;
}

/* Style headings */
h1, h2, h3, h4, h5, h6 {
    color: #ffffff;
}

/* Style buttons */
button {
    background-color: #333333;
    color: #ffffff;
}

/* Style input fields and textareas */
input[type="text"],
input[type="email"],
input[type="password"],
textarea {
    background-color: #333333;
    color: #ffffff;
    border: 1px solid #666666;
}

/* Style hover effect for buttons and links */
button:hover,
a:hover {
    opacity: 0.7;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;ul&gt;
&lt;li&gt;Then, update the app/index.php file by adding this code at the top of the file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Check if FEATURE_DARK_MODE environment variable is set
$isDarkModeEnabled = getenv('FEATURE_DARK_MODE') === 'true';

// Function to include the dark theme CSS based on the dark mode status
function includeDarkThemeCSS() {
    global $isDarkModeEnabled;
    if ($isDarkModeEnabled) {
        echo '&amp;lt;link rel="stylesheet" type="text/css" href="css/dark-theme.css"&amp;gt;';
    }
}
?&amp;gt;
&amp;lt;br&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Locate the &lt;strong&gt;&lt;/strong&gt; and the code below it &lt;strong&gt;&amp;lt;?php includeDarkThemeCSS(); ?&amp;gt;&lt;/strong&gt; and save the file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php includeDarkThemeCSS(); ?&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Build and Push the Docker Image again with *&lt;em&gt;v1 *&lt;/em&gt; tag.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   docker build -t robudex17/ecom-web:v1 .
   docker login
   docker push robudex17/ecom-web:v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Change FEATURE_DARK_MODE in "app-configmap.yaml** to true
&lt;strong&gt;FEATURE_DARK_MODE: "true"&lt;/strong&gt; and run *&lt;em&gt;kubectl apply again *&lt;/em&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  kubectl apply -f app-configmap.yaml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Restart the Deployment  and Refresh the browser
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   kubectl rollout restart deployment  ecomapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskh9woqe940f49eb75hv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fskh9woqe940f49eb75hv.png" alt="Image description" width="800" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As you can see, the dark theme is enabled. You can revert to the default theme by first changing FEATURE_DARK_MODE to "false" in the app-configmap.yaml file and then running kubectl apply followed by kubectl rollout restart again.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   kubectl apply -f app-configmap.yaml
   kubectl rollout restart deployment  ecomapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;*&lt;em&gt;Its Time to Scale our application *&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you run the kubectl get pods command, you will notice that there is only one ecommapp pod. We need an additional five pods by scaling it up to 6 replicas.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; kubectl scale deployment ecomapp  --replicas=6
 kubectl get deployment.apps/ecomapp
 kubectl get pods

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fakm4j2tamkqu00c6d1rs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fakm4j2tamkqu00c6d1rs.png" alt="Image description" width="797" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can scale it down by adjusting the number of replicas. Let's scale it down back to 1.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  kubectl scale deployment ecomapp --replicas=1

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Perform a Rolling Update&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; "Let's update our application by adding a simple promotional banner. Open app/index.php location &lt;strong&gt;&amp;lt;!--==========End Slider area==========--&amp;gt;&lt;/strong&gt; at the bottom, paste the this code
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  &amp;lt;!--Adding promotional banner--&amp;gt;
        &amp;lt;section&amp;gt;
           &amp;lt;div style="background-color: #ff0000; text-align:center;"&amp;gt;
               &amp;lt;h1 style="color: #2ef207"&amp;gt;Special offier! Get 20% off on all products. Use code &amp;lt;span style="background-color:blue; color: white"&amp;gt;SPECIAL20&amp;lt;/span&amp;gt; at checkout.&amp;lt;/h1&amp;gt;
           &amp;lt;/div&amp;gt;
       &amp;lt;/section&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Rebuild and Push the images with &lt;strong&gt;v2&lt;/strong&gt; tag
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   docker build -t &amp;lt;YOUR-DOCKERHUB-ACCOUNT&amp;gt;/ecom-web:v2 .
   docker login 
   docker push robudex17/ecom-web:v2

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Open app-deployment.yaml and udpate the image from v1 to v2
(&lt;strong&gt;image: /ecom-web:v1 to image: /ecom-web:v2&lt;/strong&gt;) and apply the changes
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  kubectl apply -f app-deployment.yaml
  kubectl rollout status deployment.apps/ecomapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm4exqeu1pxkctf0pm7nw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm4exqeu1pxkctf0pm7nw.png" alt="Image description" width="800" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fquta30yi1zj470w7uvf3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fquta30yi1zj470w7uvf3.png" alt="Image description" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Roll Back a Deployment&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Suppose the new banner introduced a bug. Roll back to the previous version. We can undo the rollout with this command
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl rollout undo deployment.apps/ecomapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftopy711kxxiziyitbyx1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftopy711kxxiziyitbyx1.png" alt="Image description" width="800" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Autoscale Your Application&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, let's check if there is an existing metrics-server installed in the kube-system namespace.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  kubectl get pods -n kube-system | grep metrics-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If there is no metrics-server we need to deploy it.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

 kubectl get pods -n kube-system | grep metrics-server

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjt74uy9w1w2w7jvprtdv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjt74uy9w1w2w7jvprtdv.png" alt="Image description" width="800" height="99"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Implement HPA: Create a Horizontal Pod Autoscaler targeting 50% CPU utilization, with a minimum of 2 and a maximum of 10 pods.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl autoscale deployment ecomapp --cpu-percent=50 --min=2 --max=10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagl2zyp9mwvsrm0cobfl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagl2zyp9mwvsrm0cobfl.png" alt="Image description" width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As you can see, when you run 'kubectl get pods', an additional ecomapp pod is created to satisfy the minimum pods requirement of 2 set by the HPA..&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58ob5165bud35832hir1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58ob5165bud35832hir1.png" alt="Image description" width="755" height="115"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let's simulate load by stressing the CPU using the 'stress' application. First, connect to the ecomapp pods, install the 'stress' app, and then run the stress command.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  kubectl get pods
  kubect exec -it ecomapp-*** -- bash 
  apt update
  apt install stress

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;verify the HPA and the deployments
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  kubectl get hpa
  kubectl describe  hpa ecomapp
  kubectl get deployment
  kubectl get pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwnq69thg1pqs0gg4zh53.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwnq69thg1pqs0gg4zh53.png" alt="Image description" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After the stress app finished running, and the average cpu load back 50% or less it back to original state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkjclk792twta9tn3ds3m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkjclk792twta9tn3ds3m.png" alt="Image description" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Implement Liveness and Readiness Probes&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add liveness and readiness probes to app-deployment.yaml.Under spec-&amp;gt;containers add code
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;       livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 3
          failureThreshold: 5
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 30
          periodSeconds: 3  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;livenessProbe&lt;/strong&gt;: Configures a liveness probe for the container to check if it's running properly.&lt;br&gt;
           - &lt;strong&gt;httpGet&lt;/strong&gt;: Defines an HTTP &lt;strong&gt;GET&lt;/strong&gt; request probe on the root path &lt;strong&gt;(/)&lt;/strong&gt; of the container's &lt;strong&gt;port 80&lt;/strong&gt;.&lt;br&gt;
           - &lt;strong&gt;initialDelaySeconds: 5&lt;/strong&gt;: Specifies a delay of &lt;strong&gt;5 seconds&lt;/strong&gt; before the first probe is performed.&lt;br&gt;
           - &lt;strong&gt;periodSeconds: 3&lt;/strong&gt;: Sets the period for &lt;br&gt;
           - &lt;strong&gt;failureThreshold: 5&lt;/strong&gt;: Sets the number of consecutive failures allowed before considering the liveness probe as failed. In this configuration, if the liveness probe fails 5 times in a row, the container will be considered as failing.&lt;br&gt;
subsequent probes to &lt;strong&gt;3 seconds&lt;/strong&gt;.&lt;br&gt;
        - &lt;strong&gt;readinessProbe&lt;/strong&gt;: Configures a readiness probe for the container to check if it's ready to serve traffic.&lt;br&gt;
           - &lt;strong&gt;httpGet&lt;/strong&gt;: Defines an &lt;strong&gt;HTTP GE&lt;/strong&gt;T request probe on the root path &lt;strong&gt;(/)&lt;/strong&gt; of the container's &lt;strong&gt;port 80&lt;/strong&gt;.&lt;br&gt;
           - &lt;strong&gt;initialDelaySeconds: 60&lt;/strong&gt;: Specifies a delay of 60 seconds before the first readiness probe is performed.&lt;br&gt;
           - &lt;strong&gt;periodSeconds: 3&lt;/strong&gt;: Sets the period for subsequent readiness probes to 3 seconds.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let's simulate failure scenarios by manually stopping the application or deleting the index.php file on one of the pods.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; kubectl get pods
 kubectl exec -it ecomapp-67c88bfcc7-99wbc  -- bash 
 rm index.php

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;After 15 seconds, which is the failureThreshold * periodSeconds, Pods will be marked as failed and restarted. Then, wait for 30 seconds before sending a health check again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzh0jaxbvfing2z007di.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqzh0jaxbvfing2z007di.png" alt="Image description" width="800" height="332"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;h3&gt;
  
  
  Implement Basic CI/CD Pipeline.
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Update image tag from v2 to &lt;strong&gt;latest&lt;/strong&gt; in &lt;strong&gt;app.deployment.yaml&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;Create Github repo name: &lt;strong&gt;resume-k8-challenge&lt;/strong&gt; and run this commands to your project directory
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "# resume-k8-challenge" &amp;gt;&amp;gt; README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/robudexIT/resume-k8-challenge.git
git push -u origin main

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;ul&gt;
&lt;li&gt;Under &lt;strong&gt;resume-k8-challenge&lt;/strong&gt; repo, click &lt;strong&gt;Actions&lt;/strong&gt; Tab click set &lt;em&gt;&lt;strong&gt;up a workflow yourself&lt;/strong&gt;&lt;/em&gt; Please paste the CI/CD code below and commit the changes
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Resume K8 Challenge Action 

on: workflow_dispatch #manual trigger
# on: 
#  push:
#    branches: main

permissions:
  issues: write
jobs: 
  BuildAndPushForProduction:
    runs-on: ubuntu-latest 

    steps: 
      - name: Code Checkout 
        uses: actions/checkout@v4 

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Build and Push docker image to Dockerhub 
        uses: docker/build-push-action@v5
        with: 
          context: ./
          push: true 
          tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{env.DOCKER_REPO}}:latest


  DeployToKubernetes:
    runs-on: ubuntu-latest 
    needs: BuildAndPushForProduction
    steps:
      - name: Code Checkout 
        uses: actions/checkout@v4  
      - name: Setup Kubernetes Configuration
        uses: tale/kubectl-action@v1
        with:
          base64-kube-config: ${{ secrets.KUBE_CONFIG }} 
      - name: Check for existing deployment
        run: |
          if kubectl get deployment shopping-cart-java-app -n app-namespace &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then
            echo "Deployment exists, rolling out update"
            kubectl rollout restart deployment deployment ecomapp
          else
            echo "Deployment not found, applying new resources"
            kubectl apply -f kubernetes/app-deployment.yaml
          fi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The GitHub Actions we just created are temporarily set to manual trigger &lt;strong&gt;(on: workflow_dispatch)&lt;/strong&gt; so that they will not run automatically without user intervention. This is because the pipeline is not yet ready.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you scan the code there are secrets variables that we need to configure first&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;secrets.DOCKERHUB_USERNAME&lt;/strong&gt; -&amp;gt; your dockerhub user&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;secrets.DOCKERHUB_TOKEN&lt;/strong&gt; -&amp;gt; your dockerhub password&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;secrets.KUBE_CONFIG&lt;/strong&gt; -&amp;gt; your kubernetest config encode using base64. You can use &lt;strong&gt;&lt;a href="https://www.base64encode.org/"&gt;https://www.base64encode.org/&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Under &lt;strong&gt;resume-k8-challenge&lt;/strong&gt;, Click Settings. Under Security Click Secrets and variables and click &lt;strong&gt;Actions&lt;/strong&gt;. Click ** New repository secret**&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DOCKERHUB_USERNAME&lt;/strong&gt; = your docker hub user&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DOCKERHUB_TOKEN&lt;/strong&gt; = your dockerhub password&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;KUBE_CONFIG&lt;/strong&gt; = your kubernetes config.This is the cluster configuration file that you downloaded earlier in this project. Once done, you should see three secret variables shown below:&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftyezswk9cyy9zyc01gm4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftyezswk9cyy9zyc01gm4.png" alt="Image description" width="783" height="251"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Under &lt;strong&gt;resume-k8-challenge&lt;/strong&gt;  Click Generals and Check &lt;strong&gt;Automatically delete head branches&lt;/strong&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under &lt;strong&gt;resume-k8-challenge&lt;/strong&gt;  In the &lt;strong&gt;Code and automation&lt;/strong&gt; section, click on '&lt;strong&gt;Branches&lt;/strong&gt;' and then select '&lt;strong&gt;Add branch protection rule&lt;/strong&gt;'."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the Branch name pattern field, enter "main".&lt;/li&gt;
&lt;li&gt;Check the following options: "&lt;strong&gt;Require a pull request before merging&lt;/strong&gt;," "&lt;strong&gt;Require review from Code Owners&lt;/strong&gt;," "&lt;strong&gt;Require status checks to pass before merging&lt;/strong&gt;," "&lt;strong&gt;Require branches to be up to date before merging&lt;/strong&gt;," and "&lt;strong&gt;Do not allow bypassing the above settings&lt;/strong&gt;."&lt;/li&gt;
&lt;li&gt; Click "&lt;strong&gt;Save&lt;/strong&gt;" to apply the changes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now that all required settings are configured, navigate to your project directory and run &lt;strong&gt;git pull&lt;/strong&gt;. After that, modify the event trigger in the &lt;strong&gt;.github/workflows/main.yml&lt;/strong&gt; file, and then push the changes."&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; #FROM 
 on: workflow_dispatch

#TO
on:
  push:
    branches: main


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi1joabpxbeihf45wog2w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi1joabpxbeihf45wog2w.png" alt="Image description" width="800" height="156"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you may have noticed, committing directly to the main branch is prohibited.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;We only allowed a pull request. Do this here's the steps  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After the change in the main branch, create a temporary branch and push the changes to it.&lt;/li&gt;
&lt;li&gt;From GitHub, create a pull request, review, and merge or reject the pull request.&lt;/li&gt;
&lt;li&gt;In the project directory, switch to the main branch and delete the temporary branch.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Great! You can proceed with making the change in the app/index.php file from "&lt;strong&gt;Make Your Shopping Easy&lt;/strong&gt;" to "&lt;strong&gt;Kubernetes is Fun and Easy&lt;/strong&gt;."&lt;br&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
  vim app/index.php
  git add .
  git commit -m "update index.php"
  git  checkout -b tempbranch
  git push --set-upstream origin tempbranch

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the push was successful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd42jwk6t8aeczixvh90k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd42jwk6t8aeczixvh90k.png" alt="Image description" width="800" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On the GitHub repository, navigate to '&lt;strong&gt;Pull requests&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fglyopq85jp5vg016go6z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fglyopq85jp5vg016go6z.png" alt="Image description" width="800" height="66"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Click the '&lt;strong&gt;Compare &amp;amp; pull request&lt;/strong&gt;' button, add a description, and then click '&lt;strong&gt;Create pull request&lt;/strong&gt;' &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Please add a comment, then click '&lt;strong&gt;Squash and merge&lt;/strong&gt;', and finally &lt;strong&gt;delete the branch&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvq004g0ak63o3gez239e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvq004g0ak63o3gez239e.png" alt="Image description" width="800" height="236"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9sb7l7raimka2s7dpfi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx9sb7l7raimka2s7dpfi.png" alt="Image description" width="800" height="84"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click Actions and see that our workflow is now running...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuljbu6956hbc40xcowdp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuljbu6956hbc40xcowdp.png" alt="Image description" width="800" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on the workflow to see if our two jobs have been successfully executed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpnm9wvyc3e5hm4z9tx3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjpnm9wvyc3e5hm4z9tx3.png" alt="Image description" width="800" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Now, let's check if our code changes are reflected in our application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjxg9nikwjln0t7eu4wdj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjxg9nikwjln0t7eu4wdj.png" alt="Image description" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;AND THATS CONCLUDE THE DOCUMENTATION AND PROCESS I MADE. THANK YOU&lt;/strong&gt;
&lt;/h2&gt;

</description>
      <category>kubernetes</category>
      <category>docker</category>
      <category>githubaction</category>
      <category>devops</category>
    </item>
    <item>
      <title>JAVA APP CICD USING GITHUB ACTIONS</title>
      <dc:creator>robudexIT</dc:creator>
      <pubDate>Mon, 11 Mar 2024 18:54:05 +0000</pubDate>
      <link>https://forem.com/robudexit/java-app-cicd-using-github-actions-12n1</link>
      <guid>https://forem.com/robudexit/java-app-cicd-using-github-actions-12n1</guid>
      <description>&lt;p&gt;Project Title: &lt;strong&gt;JAVA APP CICD USING GITHUB ACTIONS&lt;/strong&gt;&lt;br&gt;
ProjectRepo:&lt;a href="https://github.com/robudexIT/shopping_cart"&gt;https://github.com/robudexIT/shopping_cart&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Notes:The Java application use in this project is clone from this github.&lt;br&gt;
repository: &lt;a href="https://github.com/shashirajraja/shopping-cart.git"&gt;https://github.com/shashirajraja/shopping-cart.git&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Project Architecture:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftxdmhp1kw4q9c76aio24.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftxdmhp1kw4q9c76aio24.png" alt="projec-arch" width="800" height="565"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kubernetes Cluster Architecture:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdjhsvw5erpmwscm0sct.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdjhsvw5erpmwscm0sct.png" alt="kube-cluster" width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Project Overview:&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Workflow Structure&lt;/strong&gt;: The project utilizes two GitHub workflows or&lt;br&gt;
pipelines: one dedicated to the development/test environment and the&lt;br&gt;
other to the production environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Development/Test Pipeline&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This pipeline is triggered by pull requests to the main 
branch.&lt;/li&gt;
&lt;li&gt;It executes the following steps:

&lt;ol&gt;
&lt;li&gt;Running tests using Maven.&lt;/li&gt;
&lt;li&gt;Performing additional code analysis using SonarQube.&lt;/li&gt;
&lt;li&gt;Building a Docker image for the test environment.&lt;/li&gt;
&lt;li&gt;Pushing the Docker image to DockerHub.&lt;/li&gt;
&lt;li&gt;Deploying the Docker image to the test environment.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Production Pipeline&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This pipeline is triggered by merges or pushes to the main branch.&lt;/li&gt;
&lt;li&gt;It includes a manual approval step.&lt;/li&gt;
&lt;li&gt;Upon approval, the pipeline:

&lt;ol&gt;
&lt;li&gt;Builds and pushes the production Docker image with prod tag.&lt;/li&gt;
&lt;li&gt;Deploy the production image to the production environment.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Branch Protection&lt;/strong&gt;: Direct pushes to the main branch are prohibited&lt;br&gt;
to maintain code integrity and ensure changes go through the proper&lt;br&gt;
workflow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Team Structure&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The project team consists of three members:

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Dev01&lt;/strong&gt;: Responsible for updating the code by initiating pull
requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dev02&lt;/strong&gt;:Authorized to review and merge code changes. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dev03&lt;/strong&gt;: Responsible for granting manual approval in the CI/CD
production pipeline.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Test Environment&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Hosted on a single server running &lt;strong&gt;Docker Engine&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Infrastructure provided by Digital Ocean.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;7.&lt;strong&gt;Production Environment&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Utilizes a Kubernetes cluster.&lt;/li&gt;
&lt;li&gt;Infrastructure provided by Digital Ocean.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Project Flow of Execution:
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Create 3 github Users:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;robudex17 - Dev01&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Role: Initiates pull requests.&lt;/li&gt;
&lt;li&gt;Responsibilities: Updating code and initiating pull requests for
review.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;robudexIT - Dev02&lt;/strong&gt;: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Role: Responsible for merging and pushing changes to the main
branch.&lt;/li&gt;
&lt;li&gt;Responsibilities: Reviews pull requests and merges approved
changes into the main branch.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;robudex2023 - Dev03&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Role: Responsible for approving or rejecting changes in the
production workflow.&lt;/li&gt;
&lt;li&gt;Responsibilities: Manually approves changes in the CI/CD
production pipeline or requests adjustments if necessary. &lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then I clone &lt;a href="https://github.com/shashirajraja/shopping-cart.git"&gt;https://github.com/shashirajraja/shopping-cart.git&lt;/a&gt;&lt;br&gt;
java webapps project, create &lt;strong&gt;DockerFile&lt;/strong&gt; and &lt;strong&gt;Kubernetes&lt;/strong&gt; manifiests&lt;br&gt;
and push it to my &lt;strong&gt;Dev02&lt;/strong&gt; users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Current project tree. Shown below:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd994kc0mjyrzb6r8cyzd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd994kc0mjyrzb6r8cyzd.png" alt="project-tree" width="628" height="419"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  2. On the &lt;strong&gt;test server&lt;/strong&gt;, I created the latest &lt;strong&gt;MySQL Docker&lt;/strong&gt; container and restored the &lt;strong&gt;database&lt;/strong&gt; of the project using these
&lt;/h3&gt;

&lt;p&gt;commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; cd /root
 git clone https://github.com/robudexIT/shopping_cart.git 
 mkdir /root/mysqldb

docker run --name shopping-cart-db -v /root/mysqldb:/var/lib/mysql
-e MYSQL_ROOT_PASSWORD=password123 -e MYSQL_DATABASE=shopping-cart -
d mysql:latest

docker exec -i shopping-cart-db sh -c 'exec mysql -uroot -
ppassword123 shopping-cart' &amp;lt;
/root/shopping_cart/databases/mysql_query.sql

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Then, verify if the database was properly restored using the following commands:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec -it shopping-cart-db bash
mysql -uroot -ppassword123
show databases;
use shopping-cart;
show tables;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Figure shown that database is successfully Added:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpig2k5wcilzw0kgcbchc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpig2k5wcilzw0kgcbchc.png" alt="db-restored" width="667" height="621"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. On My Kubernetes Cluster I Create Mysql Deployment and Service
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Note: I will utilize one of my Kubernetes nodes' storage in a&lt;br&gt;
&lt;strong&gt;PersistentVolum&lt;/strong&gt;e, ensuring that MySQL deploys on that node. This will be&lt;br&gt;
achieved by adding a &lt;strong&gt;label&lt;/strong&gt; to the node and using this label in the&lt;br&gt;
deployment. Here are the commands:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  kubectl get nodes

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm5qk79ojr1wjk5zmryaq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm5qk79ojr1wjk5zmryaq.png" alt="get-nodes" width="584" height="84"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; kubectl label nodes mynode-pool-o6fg9 nodetype=database
 kubectl get node mynode-pool-o6fg9 --show-labels
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp16kev2ekvjhbikqtsty.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp16kev2ekvjhbikqtsty.png" alt="label-added" width="619" height="161"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I like the separation between the app and the database so I created&lt;br&gt;
&lt;strong&gt;namespace&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  kubectl create namespace database-namespace
  kubectl create namespace app-namespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clone git_ &lt;a href="https://github.com/robudexIT/shopping_cart.git_"&gt;https://github.com/robudexIT/shopping_cart.git_&lt;/a&gt; and&lt;br&gt;
Navigate (cd) to s*&lt;em&gt;hopping-cart/kubernetes/database&lt;/em&gt;* and run the command in&lt;br&gt;
order&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  kubectl apply -f storage-class.yaml -n database-namespace
  kubectl apply -f shopping-cart-pv.yaml -n database-namespace
  kubectl apply -f shopping-cart-pvc.yaml -n database-namespace
  kubectl apply -f shopping-cart-db-deploment.yaml -n database-
namespace
 kubectl apply -f shopping-cart-db-service.yaml -n database-
namespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Verify Kubernetes Objects&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; kubectl get namespace
 kubectl get sc -n database-namespace
 kubectl get pv -n database-namespace
 kubectl get pvc -n database-namespace
 kubectl get deployment -n database-namespace
 kubectl get service -n database-namespace
 kubectl get pods -n database-namespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Restore shopping-cart database to  shopping-cart-mysql pod with commands
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get pods  -n database-namespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7rd6igwz098f2y64uhy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7rd6igwz098f2y64uhy.png" alt="get-pods-database" width="675" height="170"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl cp shopping_cart/databases/mysql_query.sql shopping-cart-mysql-5b666ff5b5-994pm:/tmp --namespace database-namespace

kubectl exec -it shopping-cart-mysql-5b666ff5b5-994pm -n database-namespace -- bash -c 'mysql -u root -ppassword123 shopping-cart &amp;lt; /tmp/mysql_query.sql'

kubectl exec -it shopping-cart-mysql-5b666ff5b5-994pm  -n database-namespace – bash

mysql -uroot -ppassword123

show databases;

use shopping-cart;

show tables;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fky4eccd1q0y223jube7x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fky4eccd1q0y223jube7x.png" alt="kube-db-added" width="669" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feafnkwu8ms5s197mrxwb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feafnkwu8ms5s197mrxwb.png" alt="kube-db-added" width="673" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Now that the &lt;strong&gt;MySQL databases&lt;/strong&gt; are installed on the &lt;strong&gt;test server&lt;/strong&gt; and in the** Kubernetes cluster*&lt;em&gt;, it's time to set up the DockerHub repository, **SonarQube&lt;/em&gt;* &lt;strong&gt;(organization, project, quality gates and token)&lt;/strong&gt;.
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;DockerHub:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy8ylxq6oq3sk8al4veav.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy8ylxq6oq3sk8al4veav.png" alt="dockerhub" width="709" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sonarqube Organization and Project:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgydrb50jadyvzhbd05jj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgydrb50jadyvzhbd05jj.png" alt="sonarqube-org" width="691" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quality Gates have been added with the name "&lt;strong&gt;shop_cart_gate&lt;/strong&gt;". I have configured it to be less restrictive setting &lt;strong&gt;coverage to 0.0%&lt;/strong&gt; and &lt;strong&gt;duplicated lines to 10.0%&lt;/strong&gt;. &lt;em&gt;Please note that this configuration is not recommended and is solely for demonstration purposes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fizdz1qh9r5wx21axjtma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fizdz1qh9r5wx21axjtma.png" alt="sonarquality-gate" width="672" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add Token:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foovo3z6tu0a1y43wtj33.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foovo3z6tu0a1y43wtj33.png" alt="sonar-token" width="683" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Configure repository settings by adding production &lt;strong&gt;environment&lt;/strong&gt;, &lt;strong&gt;secrets&lt;/strong&gt;, and &lt;strong&gt;GitHub workflows/pipelines&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Add &lt;strong&gt;Dev01&lt;/strong&gt; and  &lt;strong&gt;Dev03&lt;/strong&gt; as Collaborators:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1pzyudwk1lg8li76lmh5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1pzyudwk1lg8li76lmh5.png" alt="collaborators-added" width="672" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, add the secrets and production environment variables. Navigate to &lt;strong&gt;Settings -&amp;gt; Security -&amp;gt; Secrets and Variables -&amp;gt; Actions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;These  are secrets that I added:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhr5e98fbzt74y1m4vd6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhr5e98fbzt74y1m4vd6.png" alt="secret-added" width="679" height="659"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DB_TEST_IP&lt;/strong&gt;  - mysql docker container IP Address running on Test Server.&lt;br&gt;&lt;br&gt;
You can get docker containter ip address by (docker inspect   /container-id)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxd23h95a8ejh6u5nn76n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxd23h95a8ejh6u5nn76n.png" alt="db-ipaddress" width="659" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DB_TEST_PWD&lt;/strong&gt; -  mysql docker container password running on Test Server &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DB_TEST_USERNAME&lt;/strong&gt;  - mysql docker container root user running on Test Server &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DOCKERHUB_USERNAME&lt;/strong&gt; – dockerhub username &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DOCKERHUB_TOKEN&lt;/strong&gt; – dockerhub password &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;KUBE_CONFIG&lt;/strong&gt; – kubernetes cluster configuration you can get this in .kube/config   &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SONAR_ORGANIZATION&lt;/strong&gt; – your sonarqube organization on this project &lt;br&gt;
&lt;strong&gt;SONAR_PROJECT_KEY&lt;/strong&gt; – your sonarqube project key&lt;br&gt;
&lt;strong&gt;SONAR_TOKEN&lt;/strong&gt; -  your sonarqube token &lt;br&gt;
&lt;strong&gt;SONAR_URL&lt;/strong&gt; – sonarqube url (&lt;a href="https://sonarcloud.io"&gt;https://sonarcloud.io&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TEST_HOST_IP **– IP address of the Test Server &lt;br&gt;
**TEST_HOST_PORT&lt;/strong&gt; – Test Server SSH port &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TEST_HOST_PRIVATE_KEY&lt;/strong&gt;  -  Test Server Private Key&lt;br&gt;
You can generate the key using ssh-keygen.&lt;br&gt;
&lt;strong&gt;TEST_HOST_USER&lt;/strong&gt; – Test Server User (root) &lt;/p&gt;

&lt;p&gt;Create the Production Environment and add Dev03 as a reviewer. The Production pipeline will not run without &lt;strong&gt;Dev03&lt;/strong&gt;'s approval.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffd0vm8xmekak9ayzqcyc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffd0vm8xmekak9ayzqcyc.png" alt="env-production" width="680" height="353"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production Environment Secrets&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgsh5ws9igcrdn4euqnln.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgsh5ws9igcrdn4euqnln.png" alt="prod-secrets" width="672" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DB_PROD_IP&lt;/strong&gt; – mysql Pod IP address in kubernets cluster &lt;br&gt;
&lt;strong&gt;DB_PROD_USERNAME&lt;/strong&gt; – mysql Pod username in kubernetes cluster&lt;br&gt;
&lt;strong&gt;DB_PROD_PWD&lt;/strong&gt;– mysql Pod password in kubernetes cluster&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating  Test/Dev Pipelines:&lt;/strong&gt;&lt;br&gt;
Now that all secrets and environments are set up, it's time to create pipelines.&lt;/p&gt;

&lt;p&gt;On my &lt;strong&gt;Dev02&lt;/strong&gt; shopping_cart repository, I click on Actions and create a new blank workflow named &lt;strong&gt;shopping_cart_cicd.yml&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  name: Shopping Cart Action 

on: workflow_dispatch #manual trigger
# on: 
#  pull_request:
#    branches: main

permissions:
  issues: write
jobs:        
  TestingCode: 
    runs-on: ubuntu-latest  #this runner has install maven by default
    steps: 

      - name: Code Checkout 
        uses: actions/checkout@v4 

      - name: Maven Test 
        run: mvn test 

      - name: Maven Checkstyle
        run: mvn checkstyle:checkstyle 

      - name: Install Java 11 
        uses: actions/setup-java@v4 
        with: 
          distribution: 'temurin' 
          java-version: '11'

      - name: Setup SonarQube 
        uses: warchant/setup-sonar-scanner@v7 

      - name: SonarQube Scan 
        run: sonar-scanner 
            -Dsonar.host.url=${{ secrets.SONAR_URL }}
            -Dsonar.token=${{ secrets.SONAR_TOKEN }}
            -Dsonar.organization=${{ secrets.SONAR_ORGANIZATION }}
            -Dsonar.projectKey=${{ secrets.SONAR_PROJECT_KEY }}
            -Dsonar.sources=src/ 
            -Dsonar.java.checkstyle.reportPaths=target/checkstyle-result.xml
            -Dsonar.java.binaries=target/classes/com/shashi/

      - name: SonarQube Quality Gate Check 
        id: sonarqube-quality-gate-check 
        uses: sonarsource/sonarqube-quality-gate-action@master
        timeout-minutes: 5 
        env: 
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_URLL }}

  BuildAndPushForTesting:
    runs-on: ubuntu-latest 
    needs: TestingCode
    env: 
      DOCKER_REPO: shopping-cart 
    steps: 
      - name: Code Checkout 
        uses: actions/checkout@v4 

      - name: Update application.properties file
        env:
           DB_TEST_IP: ${{ secrets.DB_TEST_IP }}
           DB_TEST_USERNAME: ${{ secrets.DB_TEST_USERNAME }}
           DB_TEST_PWD: ${{ secrets.DB_TEST_PWD }}
        run: |
          sed -i "s|db.connectionString =.*|db.connectionString = jdbc:mysql://$DB_TEST_IP:3306/shopping-cart|"  src/application.properties
          sed -i "s|db.username =.*|db.username = $DB_TEST_USERNAME|" src/application.properties
          sed -i "s|db.password =.*|db.password = $DB_TEST_PWD|" src/application.properties

      - name: Login to Docker Hub 
        uses: docker/login-action@v3 
        with: 
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Build and Push docker image to Dockerhub 
        uses: docker/build-push-action@v5
        with: 
          context: ./
          push: true 
          tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{env.DOCKER_REPO}}:test
           # - ${{ secrets.DOCKERHUB_USERNAME }}/${{ DOCKER_REPO }}:${{GITHUB_RUN_NUMBER}}

  DeployToTestEnv:
    runs-on: ubuntu-latest 
    needs: BuildAndPushForTesting 
    env: 
      DOCKER_USER: ${{ secrets.DOCKERHUB_USERNAME }}
      DOCKER_REPO: shopping-cart
      APP: shopping-cart-app 
      APP_PORT: 8081 

    steps:
      - name: Execute SSH commmands on remote server
        uses: JimCronqvist/action-ssh@master
        with:
          hosts: ${{ secrets.TEST_HOST_USER }}@${{secrets.TEST_HOST_IP}}
          privateKey: ${{ secrets.TEST_HOST_PRIVATE_KEY }}
          command: |
            docker stop ${{env.APP}} 
            sleep 2
            docker pull ${{env.DOCKER_USER }}/${{env.DOCKER_REPO}}:test
            sleep 2
            docker run --name ${{env.APP}} -d --rm -p ${{env.APP_PORT}}:8080 ${{env.DOCKER_USER }}/${{env.DOCKER_REPO}}:test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating  Production Pipelines:On My Dev02 shopping_cart repo,  I created  new blank workflow  name it  shopping_cart_cicd_production.yml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  name: Shopping Cart Action Production

on: workflow_dispatch #manual trigger
# on: 
#  push:
#    branches: main

permissions:
  issues: write
jobs: 
  BuildAndPushForProduction:
    runs-on: ubuntu-latest 
    environment: production
    env: 
      DOCKER_REPO: shopping-cart 
    steps: 
      - name: Code Checkout 
        uses: actions/checkout@v4 

      - name: Update application.properties file
        env:
           DB_PROD_IP: ${{ secrets.DB_PROD_IP }}
           DB_PROD_USERNAME: ${{ secrets.DB_PROD_USERNAME }}
           DB_PROD_PWD: ${{ secrets.DB_PROD_PWD }}      

        run: |
          sed -i "s|db.connectionString =.*|db.connectionString = jdbc:mysql://$DB_PROD_IP:3306/shopping-cart|"  src/application.properties
          sed -i "s|db.username =.*|db.username = $DB_PROD_USERNAME|" src/application.properties
          sed -i "s|db.password =.*|db.password = $DB_PROD_PWD|" src/application.properties

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Build and Push docker image to Dockerhub 
        uses: docker/build-push-action@v5
        with: 
          context: ./
          push: true 
          tags: ${{ secrets.DOCKERHUB_USERNAME }}/${{env.DOCKER_REPO}}:prod
           # - ${{ secrets.DOCKERHUB_USERNAME }}/${{ DOCKER_REPO }}:${{GITHUB_RUN_NUMBER}}

  DeployToKubernetes:
    runs-on: ubuntu-latest 
    needs: BuildAndPushForProduction
    steps:
      - name: Code Checkout 
        uses: actions/checkout@v4  
      - name: Setup Kubernetes Configuration
        uses: tale/kubectl-action@v1
        with:
          base64-kube-config: ${{ secrets.KUBE_CONFIG }} 
      - name: Check for existing deployment
        run: |
          if kubectl get deployment shopping-cart-java-app -n app-namespace &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then
            echo "Deployment exists, rolling out update"
            kubectl rollout restart deployment shopping-cart-java-app -n app-namespace
          else
            echo "Deployment not found, applying new resources"
            kubectl apply -f kubernetes/application/shopping-cart-app-deployment.yaml -n app-namespace
          fi

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you notice,  I temporarily set the two pipelines to manual trigger (workflow_dispatch) to avoid running the pipeline because it is not ready yet.&lt;/p&gt;

&lt;p&gt;Create branch rules for the main branch by navigating to Settings -&amp;gt; Branches. Check the option as seen below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhtqrflz8if24qa7jfpzn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhtqrflz8if24qa7jfpzn.png" alt="branch-rule-main" width="771" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5hq1lbtwnt3c51d867ki.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5hq1lbtwnt3c51d867ki.png" alt="branch-rule-main" width="771" height="147"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On Settings-&amp;gt; General-&amp;gt; Pull Requests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi44ho5mc5wm593tqk1an.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi44ho5mc5wm593tqk1an.png" alt="general-settings" width="780" height="106"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Now that everything is set up, it's time to proceed with testing.
&lt;/h3&gt;

&lt;p&gt;On Dev01-&amp;gt; I Update shopping_cart_cicd.yml  from workflow_dispatch to pull_request  &lt;/p&gt;

&lt;p&gt;As you can see, it is not possible to directly push changes to the main branch. Please click 'Propose changes', add a description, and create a pull request.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsu8cuo5qnpw2u3q5s83a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsu8cuo5qnpw2u3q5s83a.png" alt="pull-request" width="665" height="784"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Goto Dev02 Account  and check the Pull Request and Approved it&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffamfir9ahe7qdg86gtpu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffamfir9ahe7qdg86gtpu.png" alt="pull-request-apporove" width="675" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbayczxobe4z1aii793ax.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbayczxobe4z1aii793ax.png" alt="pullrequest-approved" width="672" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go to Actions and verify that the shopping_cart_cicd has executed successfully.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmn4gpqzccb778s4lywmz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmn4gpqzccb778s4lywmz.png" alt="pipeline-running-successful" width="675" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste Test Server Public Ip and 8081 port&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F51r9xc386opdagovwo7u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F51r9xc386opdagovwo7u.png" alt="paste-test-server-ip" width="671" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After ensuring the successful deployment on the &lt;strong&gt;Test Env&lt;/strong&gt;, it's time to merge the changes into the main branch. To do so,** Dev02** should navigate to the &lt;strong&gt;Pull Requests&lt;/strong&gt; section, select the relevant pull request, and opt for the "&lt;strong&gt;Squash and Merge&lt;/strong&gt;" option. This action condenses all commits from the feature branch into a single commit before merging them into the main branch. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykxj1mmrmpwwiynxej0v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fykxj1mmrmpwwiynxej0v.png" alt="squash-and-merge" width="674" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that the change to &lt;strong&gt;.github/workflows/shopping_cart_cicd.yml&lt;/strong&gt; has been merged into the main branch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vi69ojddx6szctrlzw6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vi69ojddx6szctrlzw6.png" alt="change-to-shopping_cart_cicd.yml" width="704" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now it's time to update the &lt;strong&gt;.github/workflows/shopping_cart_cici_production.yaml&lt;/strong&gt; as well, changing '&lt;strong&gt;workflow_dispatch&lt;/strong&gt;' to '&lt;strong&gt;push&lt;/strong&gt;'. On &lt;strong&gt;Dev01&lt;/strong&gt;, modify the file and create a pull request. Then, approve the &lt;strong&gt;pull request&lt;/strong&gt; on the &lt;strong&gt;Dev02&lt;/strong&gt; account.&lt;/p&gt;

&lt;p&gt;Note that the &lt;strong&gt;shopping_cart_cicd pipeline&lt;/strong&gt; executes because another pull request has been initiated. Please wait for the pipeline execution to finish before &lt;strong&gt;merging **it into the **main&lt;/strong&gt; branch.&lt;/p&gt;

&lt;p&gt;Now because there is a merge or a push in the main branch production pipeline execute&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Focakgohmp89fbuhxkk5c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Focakgohmp89fbuhxkk5c.png" alt="running-pipe-line" width="679" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click the workflow and notice it requires approval &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpnd6pds87dz865n1hoh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcpnd6pds87dz865n1hoh.png" alt="request-for-approval" width="664" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Given that I've configured &lt;strong&gt;Dev03&lt;/strong&gt; to solely approve or reject the pipeline execution, it won't initiate or conclude without &lt;strong&gt;Dev03&lt;/strong&gt;'s approval. &lt;strong&gt;Please proceed to Dev03 and provide approval.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ferbqceuqe3csn565gheb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ferbqceuqe3csn565gheb.png" alt="manual-approved" width="659" height="720"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Production pipeline Start executing...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fubmsf2wrxgdwoztdszq2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fubmsf2wrxgdwoztdszq2.png" alt="production-pipeline-start-executing" width="675" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Production pipeline Done..  Check Kubernetes cluster&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8nz04z2jgicpq5utks1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8nz04z2jgicpq5utks1b.png" alt="production-pipeline-done" width="689" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste the  EXTERNAL-IP to Browser &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhe213sdew5b2vaexyg5y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhe213sdew5b2vaexyg5y.png" alt="production-test-app" width="673" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The production environment in the Kubernetes cluster is operational. Now, it's time to implement some code changes, create a pull request, merge it into the main branch, and ultimately, approve the production pipeline.&lt;/p&gt;

&lt;p&gt;The flow will start in..&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dev01&lt;/strong&gt; --&amp;gt; make code change then make pull request &lt;br&gt;
&lt;strong&gt;Dev02 ** --&amp;gt; Approve the pull request and then merge to main &lt;br&gt;
**Dev03&lt;/strong&gt;  --&amp;gt; Approve the production pipeline execution.&lt;/p&gt;

&lt;p&gt;Since I am not a &lt;strong&gt;Java developer&lt;/strong&gt;, I will only change the header background color to &lt;strong&gt;purple&lt;/strong&gt; in the &lt;strong&gt;WebContent/header.jsp&lt;/strong&gt; file."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F43zuejadt9pynt55eniy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F43zuejadt9pynt55eniy.png" alt="app-state-after-code-change" width="687" height="715"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's check our &lt;strong&gt;SonarQube&lt;/strong&gt; account. Under 'Your Organization,' click on the 'shop-cart' project, then click on the '&lt;strong&gt;Pull Request&lt;/strong&gt;' tab, and see that the result has passed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe5nn4qb2upcr67vw8s15.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe5nn4qb2upcr67vw8s15.png" alt="sonar-status-check" width="697" height="236"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's adjust the Quality Gate and rerun the Test Pipeline. (Note that we expect the execution to fail this time.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr0wj3d5tklm5it7pm9ip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr0wj3d5tklm5it7pm9ip.png" alt="adjust-quality-gates-metrics" width="693" height="276"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the latest workflow of the TEST Pipeline and rerun all jobs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh350paexnishgnhkgn1s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh350paexnishgnhkgn1s.png" alt="latest-jobs-rerun" width="670" height="563"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And indeed the pipeline fails.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxgclh8bbwi8uax1p5er.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbxgclh8bbwi8uax1p5er.png" alt="pipeline-fail-to-exectue" width="670" height="563"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On SonarQube:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqqwbwtfyai83g32hbsdq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqqwbwtfyai83g32hbsdq.png" alt="sonar-quality-gate-fail" width="673" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's revert the SonarQube metrics for 'sonar_cart_gate' to be less restrictive again and rerun the Test Pipeline to ensure it passes once more&lt;/p&gt;

&lt;h2&gt;
  
  
  That concludes the documentation. Thank you.
&lt;/h2&gt;

</description>
    </item>
  </channel>
</rss>
