✔️ Discover the Dev Ops universe
✔️ Learn about basic Kubernetes concepts
✔️ Deploy a web application
Welcome to this workshop about Kubernetes, the leading container orchestration system! In 3 hours time you will learn how to deploy a web application on Kubernetes and grow familiar with multiple Kubernetes concepts.
Most of this workshop will consist in putting together YAML files that define your Kubernetes resources. You can find many examples of those on the web.
To get started, please follow the installation steps listed in this guide.
⚠️ It's essential that you complete the setup guide before attempting any of the steps.
Let's start deploying on Kubernetes!
First, your web application is going to have to run somewhere. Pods are the perfect place.
A Pod is a type of Kubernetes resource which runs multiple containers (Yes, like Docker containers!).
Your first task is to configure and run a single pod on your local Kubernetes cluster. To do so, you will have to write a YAML file for your Pod resource and apply it with kubectl
.
Your Pod resource must:
- Be of
kind
Pod. - Have the name
my-pod
. - Feature one container based on the
hello-world
image.
If you struggle to understand the syntax, make use of the kubectl explain
.
For example, kubectl explain pod
will help you figure out the syntax for defining a Pod resource. You can also ask kubectl
to explain a specific field like with kubectl explain pod.metadata
.
💡 Check out the links in the Resources section for guidance.
If you have completed this step successfully, you should be able to see your Pod when running the following command:
kubectl get pods
You can also access the output of your Pod through the following command:
kubectl logs pod/my-pod
The output of your Pod should match the output of this command:
docker run hello-world
kubectl explain pod.*
- Kubernetes cheat sheet
- Understanding Kubernetes objects
- Pod documentation
- Managing resources
Congratulations on completing the first step!
It's now time to define deployments for your web application. Deployments are like Pods but better! Deployments represent a group of one or multiple pods. When your app grows, deployments allow you to quickly scale the number of pods.
The application you ought to deploy is split into two main parts: the web server (written in Golang) and the database (MongoDB). In this step you will have to create two deployments, one for each.
The Deployment resource for the database must:
- Be of kind
Deployment
. - Have the name
mongo-deployment
. - Have one replica.
- Feature one container based on the
mongo
image. - Have the
spec.selector.matchLabels.app
field and thespec.template.metadata.labels.app
set tomongo
. This will be important for later. - Expose the port
27017
The Deployment resource for the web server must:
- Be of kind
Deployment
. - Have the name
server-deployment
. - Have one replica.
- Feature one container based on the
rojasdiego/ poc-innovation:kubernetes-workshop
image. - Expose the port
3000
Once your deployments YAML are valid, apply them with the kubectl
command.
If you have completed this step successfully, you should be able to see both your deployments and their associated pods when running the following command.
kubectl get all
kubectl explain deployment.*
- Deployment documentation
You might have noticed, that when you run kubectl get all
, the pod associated to the server-deployment
is in a state of CrashLoopBackOff
and is said to have restarted multiple times.
...
NAME READY STATUS RESTARTS AGE
pod/server-deployment-5ddbdc478-qqcwr 0/1 CrashLoopBackOff 4 115s
...
If we investigate the issue by inspecting the deployment's logs (kubectl logs deployment.apps/server-deployment
) we get the following output.
panic: server selection error: context deadline exceeded, current topology: { Type: Unknown, Servers: [{ Addr: mongo-service:27017, Type: Unknown, Average RTT: 0, Last error: connection() error occurred during connection handshake: dial tcp: lookup mongo-service on 10.96.0.10:53: server misbehaving }, ] }
goroutine 1 [running]:
gokube/models.init.0()
/app/models/db.go:26 +0x2d4
Weird! The server application is telling us it cannot connect to the Mongo database.
That's because, for now, the mongo-deployment
and the server-deployment
are isolated from one another. They cannot communicate.
This is where Kubernetes services come into play. A service allows a Kubernetes object to expose itself to other objects.
Your job is to create a service for the mongo-deployment
so it's accessible by other objects.
The service for the mongo-deployment
must:
- Be of kind
Service
. - Have the name
mongo-service
. - Forward the port
27017
to the target port27017
. - Have the
spec.selector.app
set tomongo
. This will ensure the service is linked to yourmongo-deployment
.
Once it's done, apply all your changes and run kubectl get all
. Your deployments should be running without any errors.
💡 Make sure to restart any deployment or resource that might be affected by the changes you made.
You can inspect the server-deployment
's logs to make sure everything is okay.
kubectl explain service.*
- Service documentation
- Connecting applications using services
- Kubernetes services
You never know what can happen with your application. Crashes happen all the time and as a developer you can't afford downtime or data loss.
Kubernetes already shields you against your app going offline. It will identify crashes and restart your app so it's always available. However, it's your job to make sure your data persists!
In this final step, your job is to create a persistent storage for your database in case it crashes.
You must:
- Create a
PersistentVolumeClaim
resource.- It must be named
mongo-pvc
. - Have a storage limit of
256Mi
.
- It must be named
- Link the
PersistentVolumeClaim
to yourmongo-deployment
.- The mount path must be set to
/data/db
. (This is where MongoDB stores its data).
- The mount path must be set to
💡 Make sure to restart any deployment or resource that might be affected by the changes you made.
To make sure your PersistentVolumeClaim
works, we can create a document in our database through the web app.
To do so we have to send an HTTP request to the web server.
To access the web server, you need to forward the API port. The following command will link the port 3000
of your localhost to the port 3000
of the server-deployment
.
kubectl port-forward deployments.apps/server-deployment 3000:3000
In another terminal, you can then send a request to create a new post in the database using the following command.
curl --data '{"title":"A simple post","body":"Lorem ipsum dolor sit amet"}' -i localhost:3000/posts
You should receive an OK
response from the server like so:
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Date: Wed, 25 Aug 2021 09:49:13 GMT
Content-Length: 105
{"created":{"id":"61261219c3db3a060d691ddb","title":"A simple post","body":"Lorem ipsum dolor sit amet"}}
Now make a request to see all the posts.
curl -i localhost:3000/posts
You should see your post appear in the output.
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Date: Wed, 25 Aug 2021 09:55:30 GMT
Content-Length: 105
{"posts":[{"id":"61261219c3db3a060d691ddb","title":"A simple post","body":"Lorem ipsum dolor sit amet"}]}
Now delete the mongo-deployment
and server-deployment
using kubectl
. Once that's done, your database should be gone. Now you must recreate your mongo-deployment
and server-deployment
using kubectl apply
. Don't forget to re-forward the port of the server-deployment
!
We simulated a crash of your application. If your PersistentVolumeClaim
works, you should still be able to see your post when running the following command.
curl -i localhost:3000/posts
Good job! You can now stop your cluster with minikube stop
, you've nailed this workshop!
There's still a lot you can look into with Kubernetes. Feel free to experiment with other Kubernetes objects like StatefulSets.
You can also play around with tools like helm, rancher, kustomize which will speed up your Kubernetes hacking.
Diego Rojas |
---|
🚀 Don't hesitate to follow us on our different networks, and put a star 🌟 on
PoC's
repositories.