Deploy and scale a workload on K8s
This post is going to walk through both deploying a workload onto kubernetes and describing some of the main components that makeup K8’s. For the examples which I’m going to walk through on this post I am using a local minikube. [Steps for installing]
You could also use a public cloud providers managed version of kubernetes if you wish, therefore either EKS/GCE/AKS. Please be aware however that using these will cost money, therefore if you wish to follow along with the examples in this post it would probably be best to use minikube!
Kubernetes is a container orchestration platform which is open source. Its written in goLang and was provided to the community by Google. Google have been running container workloads for more than a decade for a lot of their products, Gmail for example has been running on google Borg container orchestration platform, its this which kubernetes originates from. For more info on Borg please click on the link
High level Overview of kubernetes
This section is basically going to give you an insight into k8s from 1000 feet, I feel its important for folk who have very limited knowledge of kubernetes to understand the basics, rather than just jumping into deploying yaml files!
A kubernetes cluster will consist of a master and one or more worker nodes. The main components of the master node are:
- api
- etcd
- scheduler
- controller manager
All interaction with k8s will be through the API which sits on the master node, weather this be from a user issuing kubectl commands or a system pod on the master vm talking to another pod on a worker node all of the communication which takes place here is made through the API. The etcd key value store maintains the state of all cluster information and therefore as you can assume is a critical component which must always be available. The scheduler is used to schedule workloads onto worker nodes, with the controller manager tracking the actual state versus the desired state for all components. As a example if you were to deploy a frontend application and within the yaml you specify to always have 2 Pods running, should one of these die, the controller manager would see that the desired state for this particular deployment was to have two running pods, but only one is actually running, therefore it would ensure another pod is spun up so that the desired state which was specified as part of the deployment is met!
All user workloads get deployed onto worker nodes, depending on the size of the cluster and the amount of customers you are looking to support the number of worker nodes you allocate to cluster will vary. Furthermore the compute power of the worker nodes will match the workload requirements which you intend to support. If you are using a cloud provider the scaling of these is made simple with ASG’s. The number of pods which you can run on a particular node will depend on things like, how much resources are available on the node, how many NIC’s are available etc.
The worker nodes have a kubelet running on each of them, the kubelet listens out for requests from the API to run pods on the nodes, its the kubelet which talks back to the master node through the API. Each worker node will also have a kube-proxy its this which handles of the networking on the nodes, its translates virtual IP’s of services into the backend pods so that essentially all requests can reach there target pod over an IP:Port.
If you haven't yet used kubectl to deploy to kubernetes you might be thinking “What the hell are these pods being mentioned!!”
Pods in kubernetes are what your container will be deployed part of. A pod can run one or more containers, with the pod being deployed onto a worker node. The worker node the pod gets deployed onto will be determined by both the scheduler on the master and the kubelet on the worker nodes. Its important to remember that when we talk about containers in the vast majority of cases (like 99%) we are talking about docker. Remember kubernetes is a container orchestrator, the worker nodes all have a container runtime in order to run the images. For docker this will be containerd, docker images are built from a Dockerfile and will contain all the packages/frameworks along with the application code in order for the app to run successfully.
Once you have deployed your container you might be thinking ok thats great, now how can I access the application which i have just deployed. In order to access your application you will need to deploy a service, this could be of type Load Balancer if we were running on AWS this could create an ELB. The ELB name may not be very user friendly and therefore you may want to attach the ELB to a Route53 record. If you are just working locally and dont have access to a cloud provider you could use either Cluster IP or NodePort to connect to the application. With ClusterIP you will only get access if you are on one of the worker nodes, in other words access through ClusterIP is internal to the cluster. If you were to use NodePort then you will get access to the application from outside of the cluster by including the random port allocated. I realize there are more complex topics being included there, and as this is only a 1000 feet view of k8s I feel it would be more beneficial to have a separate post describing them!
Sweet! I think that's enough theory, lets deploy an application!!
At this stage I’m assuming you have the following setup:
Run the following commands:
minikube start
kubectl get nodes
You should see output similar to the following
NAME STATUS ROLES AGE VERSION
minikube Ready master 2d5h v1.14.1Run the following command
kubectl get pods --all-namespaces
You will see output similar to the below, as we haven't deployed any applications as of yet you might be wondering what are these pods! These are all system pods and many of which we have gave a brief explanation about above.
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-fb8b8dccf-h4kvf 1/1 Running 0 2d5h
kube-system coredns-fb8b8dccf-h7g8p 1/1 Running 0 2d5h
kube-system etcd-minikube 1/1 Running 0 2d5h
kube-system kube-addon-manager-minikube 1/1 Running 1 2d5h
kube-system kube-apiserver-minikube 1/1 Running 1 2d5h
kube-system kube-controller-manager-minikube 1/1 Running 1 2d5h
kube-system kube-proxy-rx85l 1/1 Running 0 24m
kube-system kube-scheduler-minikube 1/1 Running 1 2d5h
kube-system storage-provisioner 1/1 Running 0 2d5hYou can also see from above that all of these deployments are in the kube-system namespace. You can think of a namespace as a method for isolating different workloads or deployments from different product teams. There is a default namespace, if no namespace is provided then kubernetes will always deploy to the default space.
For the purpose of this demo lets create a namespace called demo-space you can running the following command to create the namespace kubectl create namespace demo-space
Now if we run kubectl get namespace you will see that this has been created. We could have also created this namespace by applying a yaml file, in the same method which we would do for creating deployments etc. If you run kubectl get namespace demo-space -o yaml you will be able to see what this looks like!
So we now have a namespace lets now deploy an application. Copy the below into a file called nginx.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80Here we are deploying nginx, where you see replicas: 2 this is where we are telling kubernetes to create 2 nginx pods. Where you see image: nginx:latest this is where we are going to be using the latest version of the docker image which will be pulled from docker hub. After you have saved the below into a file, run the following command, kubectl apply -f nginx.yml -n demo-space
You can now run:
kubectl get deployments -n demo-space and the output should be something similar to the below
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 77sTo get more detailed information about the deployment you can run:
kubectl describe deployment nginx-deployment -n demo-space
To get the deployment output in yaml format you could run:
kubectl get deployment nginx-deployment -o yaml -n demo-space
Previously when applying the configuration we had the number of pods set to 2. If we wanted to scale this we could edit the nginx.yml file which we previously created and set the replicas: 3 after we save the file we could then run kubectl apply -f nginx.yml -n demo-space this would then scale the number of pods to equal 3! We could have also done this by running kubectl edit deployment nginx-deployment -n demo-space and manually on the fly change the replicas: 3 however with this method we would not be using version control and the change would be overwritten the next time we apply the nginx.yml.
If you run kubectl get all -n demo-space you will see that we have our running pods, we have our deployment and we also have a replica set created. Once we applied the nginx.yml the replicaset gets created automatically and its this which the controller manager will query to ensure that we have the correct amount of running pods. If the replicaset was set to two, and we only had one running pod the controller manager would notice this difference and instruct another pod to be spun up, therefore allowing the desired state to match the actual state.
For the purpose of this tutorial this is all we are going to cover I hope if you are new to kubernetes it has taught you something. The last thing we are going to do is cleanup our environment.
Run the following:
kubectl delete deployment nginx-deployment -n demo-space && minikube delete
Thanks for reading!
