Kubernetes Objects
Kubernetes Objects are persistent entities in the cluster. These objects are used to represent the state of the cluster.
The following are some of the Kubernetes Objects:
- pods
- Namespaces
- ReplicationController (Manages Pods)
- DeploymentController (Manages Pods)
- StatefulSets
- DaemonSets
- Services
- ConfigMaps
- Volumes
Docker World:
Before starting, let’s look at what is docker container first?
Any application requires software to run, some sort of configuration (between environments) and dependent libraries. Docker
makes it easy to package all of them together and ship it as one standalone package. Docker Container image
is a lightweight, executable software that package application, environment and dependent libraries. Docker Container image
become containers
at runtime. We can create any number of containers from Container Image. In terms of Java world, Container Image is a Java Class and running containers are the objects that we can instantiate by using Class.
Before starting Kubernetes Objects, I would encourage to go through Kubernetes Architecture (my second post of K8s journey) to understand the K8s components and how they interact with each other.
Let’s start our discussion with basic building block of K8s…
Pods:
In Docker World, Every Microservice is deployed as Container
. In K8s world, A Pod
is the basic building block of K8s Objects. A pod
is a colocated group of containers. A pod
can contain single container as well. But when it contains multiple containers, all of the containers are running on single worker node
. A pod
won’t distribute across multiple worker nodes
.
Now, the question of why do we need colocated containers in the same pod?
- There are certain cross cutting concerns which you need to take care before bringing up actual application container. For example, let’s say your application stores all its secret/password configuration in
vault
. To integrate with vault you need short lived vault token so that you can retrieve the passwords during runtime. Now you can bring up the first container which is responsible to integrate with vault and query for vault token and write it to ashared volume
. Actual appcontainer
can read this token which was inshared volume
and get the secret/passwords needed. - Another example, Let’s say our application is responsible for serving traffic for web content. We can divide the app into two
containers
, One container is responsible for serving the content, and another container is responsible for loading the content from external systems. - Another example, Our app
container
is responsible for handling the ecommerce store, anothercontainer
is responsible for collecting the logs and sending it to a central location.
It’s not necessary that, we need to have multiple containers running under one pod. If there is a need K8s supports with colocated containers (grouping) under one pod which will share the same linux namespace. We can mount a shared volume which will be available for all the containers under one pod that can read/write the data on shared volume. Containers that are running under one Pod share the IP address allocated and port space, which means the IP address is allocated for the pod not for each container under the same pod.
Assumption: You have a kubernetes cluster running, either on google cloud, on-prem or as minikube for experimenting. You have installed kubectl, which is a command line tool for accessing k8s cluster.
Enough of theory, Let’s look at how to create a Pod?
Create Pod:
We can use kubectl or Rest api (to the api server) to submit the pod manifest to K8s to create a resource (Or Object). Ultimately kubectl also connects to api server and submit the pod manifest using Rest api only.
The commands are pretty simple to use and you need to write a manifest either in YAML or JSON notation. To create a Pod:
kubectl create <pod-manifest>
Pod manifest sample: spring-app.yaml
- kind: Represent the type of k8s object created. It can be a Pod, DaemonSet, Deployments or Service.
- version: K8s api version used to create the resource, It can be v1, v1beta and v2. Some of the resources can be released under beta and available for general public usage.
- metadata: provides information about the resource like name of the pod, namespace under which the pod will be running,
labels and annotations. - spec: consists of the core information about pod. Here we will tell k8s what would be the expected state of resource, Like container image, number of replicas, environment variables and volumes.
- status: consists of information about the running pod, status of each container. Status field is supplied and updated by Kubernetes after creation.
When we create an object in K8s, we need to provide the object spec
(manifest) which describes the object desired state. The status describes the actual state of the object.
Probably it would make sense now to understand the pod manifest that we have submitted to k8s master. The type of resource that we are creating is a pod
and it has only one container
as mentioned in the spec, and we are referring a sample image springdemoapp
which is a spring boot java based application and the container is running on port 8080.
You can get the running pod information using:
kubectl get pods
Now you should see:
NAME READY STATUS RESTARTS AGE
spring-pod 1/1 Running 0 10m
You can get the complete yaml by specifying -o (output format) option. The returned pod manifest will consists of the additional fields added by K8s such as status, hostIp (k8s worker node) and podIp Address.
kubectl get pod spring-pod -o yaml
You can check the logs for your container using:
kubectl logs -f spring-pod --tail 200
You should see something like:
s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
c.m.main.SpringDemoAppApplication : Started SpringDemoAppApplication in 6.997 seconds (JVM running for 7.762)
If we have multiple containers running under one pod, to look at the logs for specific container we can use -c option as:
kubectl logs -f spring-pod --tail 200 -c spring-demoapp
Now that our pod is running successfully, how do we access our application? There are several different ways to access the application running on K8s. We can use hostPort
or else port-forward
or service
based approach. We will discuss about service
based approach in next medium post. Let’s start with how to access using hostPort.
Access Pod Using hostPort:
We need to tweak our spring-pod.yaml
and add hostPort
parameter to the ports
section.
With this change our application is exposed to host network using hostIp (In case of gcloud, on-prem it’s the running worker node or in case of minikube you can get the host IP address using minikube status
which will print the IP Address of k8s master) and hostPort at 9090.
We can validate by running spring boot health call at:
curl -v http://192.168.99.100:9090/health
The output should be:
Trying 192.168.99.100...
* Connected to 192.168.99.100 (192.168.99.100) port 9090 (#0)
> GET /health HTTP/1.1
< HTTP/1.1 200
{"status":"UP"}
Access Pod Using port-forward:
Using port-forward
to access the application. port-forward
option, I would recommend using it for only local testing.
kubectl port-forward spring-pod 10000:8080
After that you will see the following operation happening in the console, which will be exactly similar to hostPort
option.
Forwarding from 127.0.0.1:10000 -> 8080
Forwarding from [::1]:10000 -> 8080
Now we can try the same request with 10000
port using:
curl -v http://127.0.0.1:10000/health
Now we see:
* Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 10000 (#0)
> GET /health HTTP/1.1
> Host: 127.0.0.1:10000
< HTTP/1.1 200
{"status":"UP"}
View Pod Details:
We can get the running pod details, events, container status by using describe command:
kubectl describe pod spring-pod
Now view the details:
Name: spring-labels
Namespace: default
Node: minikube/192.168.99.100
Labels: <none>
Annotations: <none>
Status: Running
IP: 172.17.0.6
Containers:
spring-demoapp:
Image: chkrishna/springdemoapp:latest
Port: 8080/TCP
State: Running
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 31s default-scheduler Successfully assigned spring-labels to minikube
Normal SuccessfulMountVolume 30s kubelet, minikube MountVolume.SetUp succeeded for volume "default-token-5fvlr"
Normal Pulling 30s kubelet, minikube pulling image "chkrishna/springdemoapp:latest"
Normal Pulled 29s kubelet, minikube Successfully pulled image "chkrishna/springdemoapp:latest"
Normal Created 29s kubelet, minikube Created container
Normal Started 29s kubelet, minikube Started container
Delete Pod:
We can delete the pod based on the name of the pod or by passing the same manifest
that we have used to create the resource.
kubectl delete pod spring-pod
# OR
kubectl delete -f spring-app.yaml
Using Labels:
A label is a key/value pair which can be associated to a k8s object (resource). We can use these labels
when selecting the resources using label selectors
. We can associate any number of labels to a k8s object. We can add/delete/modify the labels even after creating the resource.
For example we can tag all the api services with appType
as api
, all the web applications with appType
as web
. Now create one more pod by adding labels.
Pod manifest: spring-labels.yaml
kubectl create -f spring-labels.yaml
Now to list all the pods along with labels, we can use --show-labels
option.
kubectl get pods --show-labels
The output would be like this:
NAME READY STATUS RESTARTS AGE LABELS
spring-labels 1/1 Running 0 35s appType=api
spring-pod 1/1 Running 0 1h <none>
We can add the labels after creating the pod as well. We can label our spring-pod also with appType
label using:
kubectl label pod spring-pod appType=api
kubectl label pod spring-labels dept=billing
Now you should see:
pod "spring-pod" labeled
Now get all the pods again with --show-labels
option:
kubectl get pods --show-labels
Your output should be:
NAME READY STATUS RESTARTS AGE LABELS
spring-labels 1/1 Running 0 16m appType=api,dept=billing
spring-pod 1/1 Running 0 1h appType=api
To delete a label from running pod:
kubectl label pod spring-pod appType-
Now if we run the get pods with --show-labels
option we will see the earlier status for spring-pod with label as <none>
.
Similarly we can update the existing label of a pod using:
kubectl label pod spring-labels dept=customer_service --overwrite
To update existing label we have to use --overwrite
option. Now get all the pods again with show-labels
option
kubectl get pods --show-labels
The output should be:
NAME READY STATUS RESTARTS AGE LABELS
spring-labels 1/1 Running 0 18m appType=api,dept=customer_service
spring-pod 1/1 Running 0 1h <none>
We can also list pods based on label selectors, For that we can use -l option.
kubectl get pods -l dept
The output should be:
NAME READY STATUS RESTARTS AGE LABELS
spring-labels 1/1 Running 0 22m appType=api,dept=customer_service
We can narrow down the list based on specific value of label as well using:
kubectl get pods -l appType=api
The output should be:
NAME READY STATUS RESTARTS AGE LABELS
spring-labels 1/1 Running 0 22m appType=api,dept=customer_service
We can also delete the pods using label selectors like:
kubectl delete pod -l appType=api
Now you should see:
pod "spring-labels" deleted
Experimenting Kubernetes:
If on-premise or gcloud k8s cluster is not an option for you to explore you don’t need to worry. You can experiment kubernetes using the following interactive terminals:
It’s a lot of information for now with only one resource (Pod), I will cover the remaining objects in next post (will add the link soon). Please let me know your feedback in the comments section.