loading...
Cover image for Kubernetes for everyone 鈽革笍馃挕馃帀

Kubernetes for everyone 鈽革笍馃挕馃帀

sendilkumarn profile image Sendil Kumar N Updated on 銉7 min read

Kubernetes

Kubernetes is the de facto standard for running containerized applications.

Kubernetes (K8s) is an open-source system for automating deployment, scaling, and management of containerized applications.

Kubernetes makes it easy to deploy and run containerized applications. Kubernetes is simple to use.

Kubernetes is complex to understand because it provides a huge set of options to make your deployment easier.

Aptly named, Kubernetes is a pilot (or) helmsman that helps you to sail the container world. Kubernetes is a portable and extensible system built by the community for the community.

As Kelsey, correctly quotes

Kubernetes does the things that the very best system administrator would do automation, failover, centralized logging, monitoring. It takes what we鈥檝e learned in the DevOps community and makes it default, out of the box.

In order to work with Kubernetes, it is very important to understand

  • How Kubernetes works?
  • How Kubernetes is architected?
  • What are the various components in Kubernetes?

Let us start hacking on Kubernetes.

How does Kubernetes work?

The Kubernetes run in a highly available cluster mode. Each Kubernetes cluster consists of one or more master node and a few worker nodes.

Alt Text

Master Node

The master node consists of an API server, Scheduler, Controllers, etcd. This node is called the control plane of Kubernetes. This control plane is the brain of Kubernetes.

That is the control plane is responsible for all the actions inside Kubernetes.

Alt Text

Via the API server, we can instruct the Kubernetes or get information from the Kubernetes.

The Scheduler is responsible for scheduling the pods.

The controllers are responsible for running the resource controllers.

The etcd is a storage for the Kubernetes. It is key-value storage.

Node

Alt Text

The worker nodes have a Kubelet and proxy.

The Kubelets are the actual workhorse and the Kube-proxy handles the networking.

Working

Alt Text

We provide the yaml file to the Kubernetes cluster through kubectl apply command.

The apply command calls the API server, which will send the information to the controller and simultaneously stores the information to the etcd.

The etcd then replicate this information across multiple nodes to survive any node failure.

The controller will check whether the given state matches the desired state. If it is not it initiates the pod deployment, by sending the information to the scheduler

The checks are called as the reconciliation loop that runs inside the Kubernetes. The job of this loop is to validate whether the state requested is maintained correctly. If the expected state and actual states mismatch this loop will do the necessary actions to convert the actual state into the expected state.

The scheduler has a queue inside. Once the message is received in the queue.

The scheduler will then invoke the kubelet to do the intended action such as deploying the container.

This is a 10000 feet bird view of how Kubernetes does the deployment.

There are various components inside the Kubernetes. Let us take a look at what are they and how are they useful.

Components of Kubernetes

Pods

In general terms, pods are nothing but a group of dolphins or whales.

Similarly, in Kubernetes world, pods are a group of containers living together. A pod may have one or more containers in it.

The pod is the smallest unit of deployment in Kubernetes. Usually, the containers that cannot live outside the scope of another container are grouped to form a pod.

This is how you define a pod in Kubernetes.

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']
  • apiVersion denotes the Kubernetes cluster which version of API to use when parsing and executing this file.
  • kind defines what is the kind of Kubernetes object, this file will refer to.
  • metadata includes all the necessary metadata to identify the Pod.
  • spec includes the container information.

Deployments

While pods are the unit of deployment. For an application to work, it needs one or more pods. Kubernetes considers this entire set as deployment.

Thus deployment is recorded information about pods. Kubernetes uses this deployment information to manage and monitor the applications that are deployed in them.

The below file is the sample deployment file that tells the Kubernetes to create a deployment of nginx using the nginx:1.7.9 container.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

Replicasets

While deployment tells the Kubernetes what containers are needed for your application and how many replicas to run. The replica sets are the ones that ensure those replicas are up and running.

ReplicaSet is responsible for managing and monitoring the replicas.

StatefulSet

Often times we will need to have persistent storage or permanent network identifiers or ordered deployment, scaling, and update. During those times we will use StatefulSets.

You can define the StatefulSet like below:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx # has to match .spec.template.metadata.labels
  serviceName: "nginx"
  replicas: 3 # by default is 1
  template:
    metadata:
      labels:
        app: nginx # has to match .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: k8s.gcr.io/nginx-slim:0.8
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "my-storage-class"
      resources:
        requests:
          storage: 1Gi

We mounted the volume and also claimed the volume storage.

DaemonSet

Sometimes you need to run a pod on every node of your Kubernetes cluster. For example, if you are collecting metrics from every node, then we will need to schedule some pods on every node that collects the metrics. We can use DaemonSet for those nodes.

Services

The deployments define the actual state of the application running on the containers. Users will need to access the application or you might need to connect to the container to debug it. Services will help you.

The services are the Kubernetes object that provides access to the containers from the external world or between themselves.

We can define the service like below:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376

The above service maps incoming connections on port 80 to the targetPort 9376.

You can consider the services as the load balancer, proxy or traffic router in the world of Kubernetes.

Networking

This is the most important element of Kubernetes. The pods running should be exposed to the network. The containers that are running inside the pods should communicate between themselves and also to the external world.

While service provides a way to connect to the pods, networking determines how to expose these services.

In Kubernetes we can expose the service through the following ways:

  • Load Balancer
    • The Load Balancer provides an external IP through which we can access the pods running inside.
    • The Kubernetes will start the services and then asynchronously starts a load-balancer.

  • Node Port
    • Each of the services will have a dynamically assigned port.
    • We can access the services using the Kubernetes master IP.

  • Ingress
    • Each of the services will have a separate address.
    • These services are then accessed by an ingress controller.
    • The ingress controller is not a public IP or external IP.

Secrets

Often for the applications, we need to provide passwords, tokens, etc., Kubernetes provides secrets object to store and manage the sensitive information. We can create a secret like below:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
stringData:
  config.yaml: |-
    apiUrl: "https://my.api.com/api/v1"
    username: {{username}}
    password: {{password}}

Best practices

While Kubernetes is an ocean and whatever we have seen is just a drop in it. Since Kubernetes supports a wide range of applications and options, there are various different options and features available.

Few best practices to follow while working with Kubernetes are:

Make smaller YAML

The yaml files are the heart of Kubernetes configuration.

We can define multiple Kubernetes configurations in a single yaml. While yaml reduces the boilerplate when compared with JSON. But still yaml files are space-sensitive and error-prone.

So always try to minimize the size of yaml files.

For every service, deployment, secrets, and other Kubernetes objects define them in a separate yaml file.

Split your yaml files into smaller files.

The single responsibility principle applies here.

Smaller and Fast boot time for images

Kubernetes automatically restarts the pods when there is a crash or upgrade or increased usage. It is important to have a faster boot time for the images. In order to have a faster boot time, we need to have smaller images.

Alpine images are your friends. Use the Alpine images as the base and then add in components or libraries to the images only when they are absolutely necessary.

Always remember to have smaller image sizes. Use builder pattern to create the images from Alpine images.

Healthy - Zombie Process

Docker containers will terminate only when all the processes running inside the container are terminated. The Docker containers will return healthy status even when one of the processes is killed. This creates a Healthy-Zombie process.

Try to have a single process inside the container. If running a single process is not possible then try to have a mechanism to figure out whether all the required processes are running.

Clean up unused resources

In the container world, it is quite common to have unused resources occupying the memory. It is important to ensure the resources are properly cleaned.

Think about Requests & Limits

Ensure that requests and limits are properly specified for all the containers.

resources:
    requests:
        memory: "100Mi"
        cpu: "100m"
    limits:
        memory: "200Mi"
        cpu: "500m"

The requests are the limits that the container is guaranteed to get. The limits are is the maximum or minimum resource a container is allowed to use.

Each container in the pod can request and limit their resources.

RED / USE pattern

Monitor and manage your services using RED pattern.

  • Requests
  • Errors
  • Duration

Track the requests, errors in the response and the duration to receive the response. Based on this information, tweak your service to receive optimum performance.

For the resources, use the USE pattern.

  • Utilization
  • Saturation
  • Errors

Monitor the resource utilization and how much the resources are saturated and what are the errors. Based on this information, tweak your resources to optimize resource allocation.

Hopefully, this might have given you a brief overview of Kubernetes. Head over kubernetes.io for more information on Kubernetes.

Now you want deploy a sample application on top of Kubernetes with Istio check out this post.

You can follow me on Twitter.

If you like this article, please leave a like or a comment. 鉂わ笍

Posted on by:

sendilkumarn profile

Sendil Kumar N

@sendilkumarn

An explorer wandering in the land of programs. I am passionate about Open Source. "Docendo discimus"

Discussion

pic
Editor guide
 

Great article! If you want to try out some of these kubectl commands, I run KubeSail which gives you a small free slice of our powerful, security-hardened Kubernetes cluster. You get full access to the Kube API, so you should be able to follow along and try applying all of the YAML in this tutorial.

 

Love the article, how you summarized the main K8s components and explained them in your own language. Especially the Services and Networking part that can be fuzzy ;)
Good job!
We need more like this one.
I hope the next one is on PV ;)
Thanks

 

It is not necessary to use alpine to minimize resources. There are easy ways to build image "from scratch". Like mount your empty image and put your staff in, for example

dnf install --installroot...

 

just remember you'll need ca-certs if you're doing any tls in your container

 

oh.. that sounds interesting. I will take it a spin. Thanks 馃憤馃檪

 

I can recommend you some useful tools

  • buildah makes building images easier
  • ansible-bender allows you to use ansible to build your image (also uses buildah)
 

Thank you for the detailed article Sendil. I was thinking of doing this exact thing but you beat me to the punch. :D. Very well done. Keep up the good work.

 

Oops, sorry about that :). Between thanks.

 

Can't help recalling that each time I see anything on Kubernetes...

 

Thanks a lot for this great article.

Jus a little correction i think: "Alphine" should be "Alpine"

 

Thanks I updated 馃憤

 

Great and simple overview ... if you cover k8s rbac at some point - check this open source tool
github.com/alcideio/rbac-tool

 

Thanks :) will take a look :)

 

Thank you for that article!

 
 

Great easy read, thanks Sendil!

 

Sorry, this is really not "for everyone". You just bombard the reader with an enormous amount of new concepts that are nowhere introduced nor defined. I don't doubt that this helps people who already know all these terms to systematize their knowledge, but calling it "for everyone" is really wrong.

 

This is a good one. Ideally I expect how Kubernetes works part to be for everyone except for few jargons like pods. And have an explanation for them.

May be I should have named it Kubernetes for anyone who knows Docker?

How about instead of calling something wrong, can you share the list of things that you feel needs an explanation. (feel free to comment) let us make this post for everyone :)

 

Well, you could start with explaining Kubernetes relies on Docker containers and how it's all related. I dug a little bit around Docker and Kubernetes seemed to appear here and there but I didn't have time to look it closer. So now I thought good maybe here I will know what's it all about. But here not a word about Kubernetes and Docker connection...

 

May be I should have named it Kubernetes for anyone who knows Docker?

Yes, that's probably it. I really don't know anything about Docker. But that's also a part of the problem: you mention Docker only after 85% of your article, and of course I didn't get to there.

can you share the list of things that you feel needs an explanation. (feel free to comment) let us make this post for everyone :)

I tried. But there's too much of it, and the article is really long. As I said above, the fact that you didn't even mention Docker for 5/6ths of your article is illustrative. Probably it would need a thorough rewrite, and it still wouldn't be worth it.

Hmm, I'm working with Docker and compose for a year or two but I have to admit i still don鈥檛 really understand the differences between pods, services, deployments and load balancing strategies.

For every section i thought, 鈥渙h this is interesting鈥 and then the section was over and i did not really get it.

I think it鈥檚 hard to cover such a complex technology in an article but maybe you could have made up one example application that you鈥檝e built with Kubernetes and explain the details along it.