The Kubernetes Resume Challenge Part 1
Tags: kubernetes, kubernetesresumechallenge, docker, devops
Published: 2024-03-24 00:04:44

**Intro**
This is a two-part blog article on the steps I took while doing the Kubernetes resume challenge by [Forrest Brazeal](https://newsletter.goodtechthings.com/p/take-on-the-kubernetes-resume-challenge), who is also known for creating the popular [Cloud Resume Challenge](https://cloudresumechallenge.dev/docs/the-challenge/aws/). 

A little backstory, Some months after I got into Cloud Computing as a DevOps Engineer, I really wanted to do the Cloud Resume Challenge but something always came in my way of completing the project. most times, it was the lack of AWS credits (don't blame me, it's easy to drown in cloud bills as an enthusiastic newbie), or some other urgent project or task at work. At some point i gave up on the idea. 

Fast forward to March 2024, Forrest Brazeal is out with another challenge called "[The Kubernetes Resume](https://cloudresumechallenge.dev/docs/extensions/kubernetes-challenge/?utm_source=substack&utm_medium=email)", Click on the link to access this challenge and guidelines. Ignore the name, this is far from a resume! 
I got right into it and finally completed it. Link to my GitHub repo here. 
Come along as I walk you through the steps I followed to accomplish this task.
Let's jump straight in!

**Scenario**
We have to deploy a PHP e-commerce website. This is a web application which faces challenges surrounding scalability and availability. To address these, we are going to leverage containerization using Docker and the orchestration using Kubernetes.

**Prerequisites**
- Docker and Kubernetes CLI Tools
- Cloud Provider Account: Access to AWS, Azure, or GCP for - 
  creating a Kubernetes cluster.
- GitHub Account
- Kubernetes Crash Course
- E-commerce Application Source Code and DB Scripts: Available at 
  kodekloudhub/learning-app-ecommerce.

**Step 1: Certification**
The first step is to have the CKAD certification or complete the CKAD course on Kodekloud which I concluded last year but i had become rusty, nonetheless I proceeded. (don't be like me, take the course if you're not hands on with Kubernetes)

**Step 2: Containerize Your E-Commerce Website and Database**
The second step is containerizing the e-commerce website and the database. your proficiency with Docker is tested here because you have to update the database connection string and attach an initialization script that is mounted on the database during creation. That means creating two Dockerfiles, one for the website and another for the database.

**Website**
 php:7.4-apache as base image
install mysqli extension for PHP.
and expose port 80.
Test this to ensure there are no errors during build.

**Database **
The database Dockerfile was built using an official MariaDB image, but a database initialization script will be mounted on launch of database. I spent alot of time working on this step as I am not really a fan of PHP. I was torn between having the script as an entrypoint script or as a Kubernetes ConfigMap object that will be used on my deployment. 

The errors I had was because I was trying to create a .env file but I just needed to hardcode it either on the Dockerfile or as the website configmap variables. either way we need to ensure that the application has variables referencing to DB_NAME, DB_HOST, DB_PASSWORD and DB_USER.

Now after building locally, we push to Docker hub so we can pull this in on the deployment file. the below commands can be used to build, tag and push to Docker hub.

```
docker build -t cloudiepad/ecomm-img:v5
```

```
docker push cloudiepad/ecomm-img:v5
``` 



**Step 3: Set Up Kubernetes on a Public Cloud Provider**
As an AWS guy I used EKS to set up my clusters, If you are new to kubernetes as a whole, I would advise testing your cluster locally using minikube before going ahead to provision using EKS. it's pretty easy to rack up cloud debts using managed services on the cloud. 

It's best to test and ensure that all your manifest files are correct and working before deploying to EKS.
 
**Steps to deploy an EKS cluster using CLI**
- Install and configure AWS CLI
- Install eksctl: This is an EKS command line tool that enables us 
  run commands from the CLI to EKS.
- Install kubectl : we will need this to interact with our cluster
  To set up an eks cluster, ensure that the IAM user has the 
  appropriate permissions and roles to access both ECR and EKS. 

  Use eksctl create a cluster with the following command



```
eksctl create cluster --name eks-cluster --region us-east-1 --zones=us-east-1a,us-east-1b --nodegroup-name node-group --node-type t2.small --nodes 2 --nodes-min 2 --nodes-max 5 --managed
```


Replace `eks-cluster`,`us-east-1` and `us-east-1a,us-east-1b` with your preferred cluster name, AWS region and availability zones.

- create cluster: This part of the command instructs eksctl to create a new EKS cluster.

- name eks-cluster: This specifies the name of the EKS cluster to be created, in this case, it's named "eks-cluster".

- region us-east-1: Specifies the AWS region in which the cluster will be created. In this case, it's US East (N. Virginia).

- zones=us-east-1a,us-east-1b: Specifies the availability zones in which the worker nodes will be created. In this example, it's specifying us-east-1a and us-east-1b.

- nodegroup-name node-group: This specifies the name of the node group within the EKS cluster.

- node-type t2.small: Specifies the EC2 instance type for the worker nodes. In this case, it's t2.small.

- nodes 2: Specifies the initial number of worker nodes in the node group. In this example, it's set to 2.

- nodes-min 2: Specifies the minimum number of worker nodes in the node group. In this example, it's set to 2.

- nodes-max 5: Specifies the maximum number of worker nodes in the node group. In this example, it's set to 5.

- managed: Indicates that this node group will be managed by Amazon EKS.

**Step 4: Deploy Your Website to Kubernetes**
At this stage, I generated a _website-deployment.yaml_ file that declares my website deployment including the name of the website, the amount of replicas I want at all times, the name of my docker image and the location. 

There is also a need to generate a mariadb-deployment.yaml file for the database as well. Instead of using a custom MariaDb image for the DB, I stated all the environment variables in my Dockerfile, so that when the container is spun up, it has all the details I need already set up. 

Also ensure that the database pod has the db-load-script.sql script loaded unto the database and creates a database called 'ecomdb' . If you see that database then you have succesfully loaded the script as an entrypoint. 

Another issue that I encountered severally was the inability for my db-user to access the db.

```
ERROR 1045 (28000): Access denied for user 'ecomm-user'@ 'localhost' (using password: NO)
```

This error happens when the right password is not captured in the Dockerfile. little errors like this can consume a lot of time. beware of the password that the website is expecting and the password used to launch the db. They should be the same.

Below is an example of a deployment.yaml file on kubernetes.

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-app
  labels:
    app: sample
spec:
  replicas: 3
  selector:
    matchLabels:
      app: sample
  template:
    metadata:
      labels:
        app: sample
    spec:
      containers:
      - name: sample-app
        image: your-registry/sample-app:latest
        ports:
        - containerPort: 8080
```


**Step 5: Expose Your Website**
In this stage we have to generate another yaml file called a service.yaml file, we can call this website-service.yaml and as the guidelines state, we create a LoadBalancer type. 
When we deploy this service to EKS, AWS provisions an ALB (Application Load Balancer) to serve our website. An equivalent is created for the database to maintain consistency. A kubernetes service.yaml file looks like this.

```
apiVersion: v1
kind: Service
metadata:
  name: sample-service
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 8080
  selector:
    app: sample
```


**Step 6: Implement Configuration Management**
**Task**: Add a feature toggle to the web application to enable a "dark mode" for the website. 

Modify the Web Application: Add a simple feature toggle in the application code (e.g., an environment variable FEATURE_DARK_MODE that enables a CSS dark theme).

Use ConfigMaps: Create a ConfigMap named feature-toggle-config with the data FEATURE_DARK_MODE=true.

**Implementation**
This stage was a bit tricky for me because I am not a developer and even as a DevOps Engineer, PHP is not my favorite. The aim of this stage is to show that ConfigMaps can be used in several capacities. Anyways I reached out to a friend of mine who is a PHP developer and he helped me refactor the code and added a "style-dark.css" file as well to actually toggle. Now i was tasked with implementing this feature on ConfigMap. finally figured that out and my ConfigMap file looked like this.
```
apiVersion: v1
kind: ConfigMap
metadata:
  name: feature-toggle-config
data:
  FEATURE_DARK_MODE: "true"
```

Also the configMap had to be refereed to in the deployment file so the deployment is aware of this addition. When that is completed run

```
kubectl apply -f feature-toggle-config.yaml
```

to apply this config and voila we had a dark-mode website. I felt like a superman after this haha!


**Step 7: Scale Your Application**
AT this point we have deployment files, service files and a configmap file to toggle dark-mode. The next task is to Scale this website using the

```
kubectl scale deployment/<deployment_name> --replicas=6
```

 This command refers to the active deployment and it is telling the deployment to scale to 6 replicas.
this scale happens immediately and can be observed in real-time by running
```
kubectl get pods -w
```
We now observe that 6 pods will be in the running state as against 1 initial replica.

**Step 8: Perform a Rolling Update**
**Task**: Update the website to include a new promotional banner for the marketing campaign.

Update Application: Modify the web application's code to include the promotional banner.

Build and Push New Image: Build the updated Docker image as yourdockerhubusername/ecom-web:v2 and push it to Docker Hub.
Rolling Update: Update website-deployment.yaml with the new image version and apply the changes.

**Implementation**
This stage includes making a change in the website, building and pushing a new Dockerfile image version and updating the deployment with the new image version. 
Also, instead of just applying this new deployment we use the rollout mechanism where old pods will terminate while new pods are creating simultaneously so that there is no downtime hereby enhancing availability.
```
kubectl rollout status deployment/<deployment_name>
```
Replace <deployment_name> with the name of your deployment. This command will provide you with the status of the rollout, including whether it's in progress, successful, or failed.

**Step 9: Roll Back a Deployment**
**Task**: Suppose the new banner introduced a bug. Roll back to the previous version.

Identify Issue: After deployment, monitoring tools indicate a problem affecting user experience.

Roll Back: Execute kubectl rollout undo deployment/ecom-web to revert to the previous deployment state.

**Implementation**
Similar to the last step but this is the exact opposite, how do we undo a rollout that causes our website to break? firstly, we rollback to a working version while we troubleshoot the issue with that particular buggy release.
```
kubectl rollout undo deployment/<deployment_name>
```
The above command seamlessly handles this.

We have to take a coffee break now and and let's move on to the second part of the project.

[**CLICK HERE FOR PART 2 **](https://dev.to/cloudiepad/the-kubernetes-resume-challenge-part-2-2op1)
If you enjoyed this article and would love to connect with me. Find me with the below links.
[LinkedIn](https://www.linkedin.com/in/ogonna-nnamani/)
[GitHub](https://github.com/Waveey/Kubernetes-Resume-Challenge)
[Twitter](https://twitter.com/wavebuoyOG)