Skip to content

Case Study: Operations on Resources

Scenario:

  • Node Label
  • Annotation
  • Namespace
  • ServiceAccount Authorization
  • Grant API access authorization to default ServiceAccount
  • Deployment
  • Expose Service
  • Scale out the Deployment
  • Rolling update
  • Rolling back update
  • Event
  • Logging

Node Label

  • Add/update/remove node Label.
# Update node label
kubectl label node cka002 node=demonode

# Get node info with label info
kubectl get node --show-labels

# Search node by label
kubectl get node -l node=demonode

# Remove a lable of node
kubectl label node cka002 node-

Annotation

Create Nginx deployment

kubectl create deploy nginx --image=nginx:mainline

Get Annotation info.

kubectl describe deployment/nginx

Result

......
Labels:                 app=nginx
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=nginx
......

Add new Annotation.

kubectl annotate deployment nginx owner=James.H

Now annotation looks like below.

......
Labels:                 app=nginx
Annotations:            deployment.kubernetes.io/revision: 1
                        owner: James.H
Selector:               app=nginx
......

Update/Overwrite Annotation.

kubectl annotate deployment/nginx owner=K8s --overwrite

Now annotation looks like below.

......
Annotations:            deployment.kubernetes.io/revision: 1
                        owner: K8s
Selector:               app=nginx
......

Remove Annotation

kubectl annotate deployment/nginx owner-
......
Labels:                 app=nginx
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=nginx
......

Clean up

kubectl delete deployment nginx

Namespace

  • Get current available namespaces.
kubectl get namespace

Result

NAME              STATUS   AGE
default           Active   3h45m
dev               Active   3h11m
kube-node-lease   Active   3h45m
kube-public       Active   3h45m
kube-system       Active   3h45m
  • Get Pod under a specific namespace.
kubectl get pod -n kube-system

Result

NAME                                       READY   STATUS    RESTARTS   AGE
calico-kube-controllers-5c64b68895-jr4nl   1/1     Running   0          3h25m
calico-node-dsx76                          1/1     Running   0          3h25m
calico-node-p5rf2                          1/1     Running   0          3h25m
calico-node-tr22l                          1/1     Running   0          3h25m
coredns-6d8c4cb4d-g4jxc                    1/1     Running   0          3h45m
coredns-6d8c4cb4d-sqcvj                    1/1     Running   0          3h45m
etcd-cka001                                1/1     Running   0          3h45m
kube-apiserver-cka001                      1/1     Running   0          3h45m
kube-controller-manager-cka001             1/1     Running   0          3h45m
kube-proxy-5cdbj                           1/1     Running   0          3h41m
kube-proxy-cm4hc                           1/1     Running   0          3h45m
kube-proxy-g4w52                           1/1     Running   0          3h41m
kube-scheduler-cka001                      1/1     Running   0          3h45m
  • Get Pods in all namespaces.
kubectl get pod --all-namespaces
kubectl get pod -A

ServiceAccount Authorization

With Kubernetes 1.23 and lower version, when we create a new namespace, Kubernetes will automatically create a ServiceAccount default and a token default-token-xxxxx.

With Kubernetes 1.24, only ServiceAccount default is created automatically when a new namespace is created, need manually create a toke linked to the ServiceAccount default.

Here is an example to create a new namespace dev, we can see that only ServiceAcccount: default was created in namespace dev, no secretes (token) linked to the ServiceAccount default.

kubectl create namespace dev
kubectl get serviceaccount -n dev
kubectl get secrets -n dev

There is a default cluster role admin. But there is no clusterrole binding to the cluster role admin.

kubectl get clusterrole admin
kubectl get clusterrolebinding | grep ClusterRole/admin

Role and rolebinding is namespaces based. On namespace dev, there is no role and rolebinding.

kubectl get role -n dev
kubectl get rolebinding -n dev

A Secret in the Kubernetes cluster is an object and it is used to store sensitive information such as username, password, and token, etc. The objective of Secrets is to encode or hash the credentials. The secrets can be reused in the various Pod definition file.

A kubernetes.io/service-account-token type of Secret is used to store a token that identifies a service account. When using this Secret type, you need to ensure that the kubernetes.io/service-account.name annotation is set to an existing service account name.

Let's create token for the ServiceAcccount: default in namespace dev.

kubectl apply -f - << EOF
apiVersion: v1
kind: Secret
metadata:
  name: default-token-dev
  namespace: dev
  annotations:
    kubernetes.io/service-account.name: "default"
type: kubernetes.io/service-account-token

EOF

Now we get ServiceAcccount: default and Secret (token) default-token-dev in namespace dev.

kubectl get serviceaccount -n dev
kubectl get secrets -n dev

Get token of the service account default.

TOKEN=$(kubectl -n dev describe secret $(kubectl -n dev get secrets | grep default | cut -f1 -d ' ') | grep -E '^token' | cut -f2 -d':' | tr -d ' ')
echo $TOKEN

Get API Service address.

APISERVER=$(kubectl config view | grep https | cut -f 2- -d ":" | tr -d " ")
echo $APISERVER

Get Pod resources in namespace dev via API server with JSON layout.

curl $APISERVER/api/v1/namespaces/dev/pods --header "Authorization: Bearer $TOKEN" --insecure

We will receive 403 forbidden error message. The ServiceAccount default does not have authorization to access pod in namespace dev.

Let's create a rolebinding rolebinding-admin to bind cluster role admin to service account default in namespapce dev. Hence service account default is granted adminstrator authorization in namespace dev.

# Usage:
kubectl create rolebinding <rule> --clusterrole=<clusterrule> --serviceaccount=<namespace>:<name> --namespace=<namespace>

# Crate rolebinding:
kubectl create rolebinding rolebinding-admin --clusterrole=admin --serviceaccount=dev:default --namespace=dev

Result looks like below by executing kubectl get rolebinding -n dev.

NAME                ROLE                AGE
rolebinding-admin   ClusterRole/admin   10s

Try again, get pod resources in namespace dev via API server with JSON layout.

curl $APISERVER/api/v1/namespaces/dev/pods --header "Authorization: Bearer $TOKEN" --insecure

Clean up.

kubectl delete namespace dev

Deployment

Create a Ubuntu Pod for operation. And attach to the running Pod.

kubectl create -f - << EOF
apiVersion: v1
kind: Pod
metadata:
  name: ubuntu
  labels:
    app: ubuntu
spec:
  containers:
  - name: ubuntu
    image: ubuntu:latest
    command: ["/bin/sleep", "3650d"]
    imagePullPolicy: IfNotPresent
  restartPolicy: Always
EOF

kubectl exec --stdin --tty ubuntu -- /bin/bash

Create a deployment, option --image specifies a image,option --port specifies port for external access. A pod is also created when deployment is created.

kubectl create deployment myapp --image=docker.io/jocatalin/kubernetes-bootcamp:v1 --replicas=1 --port=8080

Get deployment status

kubectl get deployment myapp -o wide

Result

NAME    READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS            IMAGES                                       SELECTOR
myapp   1/1     1            1           79s   kubernetes-bootcamp   docker.io/jocatalin/kubernetes-bootcamp:v1   app=myapp

Get detail information of deployment.

kubectl describe deployment myapp

Result

Name:                   myapp
Namespace:              dev
CreationTimestamp:      Sat, 23 Jul 2022 14:36:43 +0800
Labels:                 app=myapp
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=myapp
Replicas:               1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=myapp
  Containers:
   kubernetes-bootcamp:
    Image:        docker.io/jocatalin/kubernetes-bootcamp:v1
    Port:         8080/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   myapp-b5d775f5d (1/1 replicas created)
Events:
  Type    Reason             Age   From                   Message
  ----    ------             ----  ----                   -------
  Normal  ScalingReplicaSet  95s   deployment-controller  Scaled up replica set myapp-b5d775f5d to 1

Expose Service

Get the Pod and Deployment we created just now.

kubectl get deployment myapp -o wide
kubectl get pod -o wide

Result

NAME                    READY   STATUS    RESTARTS   AGE     IP             NODE     NOMINATED NODE   READINESS GATES
myapp-b5d775f5d-cx8dx   1/1     Running   0          2m34s   10.244.102.7   cka003   <none>           <none>

Send http request to the Pod curl 10.244.102.7:8080 with below result.

Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1

To make pod be accessed outside, we need expose port 8080 to a node port. A related service will be created.

kubectl expose deployment myapp --type=NodePort --port=8080

Get details of service myapp by executing kubectl get svc myapp -o wide.

NAME    TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE   SELECTOR
myapp   NodePort   11.244.74.3   <none>        8080:30514/TCP   7s    app=myapp

Send http request to service port.

curl 11.244.74.3:8080
Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-cx8dx | v=1

Get more details of the service.

kubectl get svc myapp -o yaml
kubectl describe svc myapp

Get details of related endpoint myapp by executing kubectl get endpoints myapp -o wide.

NAME    ENDPOINTS           AGE
myapp   10.244.102.7:8080   43s

Send http request to the service and node sucessfully. Pod port 8080 is mapped to node port 32566.

Send http request to node port on cka003.

curl <cka003_node_ip>:30514
Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1

Attach to Ubuntu Pod we created and send http request to the Service and Pod and Node of myapp.

kubectl exec --stdin --tty ubuntu -- /bin/bash
curl 10.244.102.7:8080
curl 11.244.74.3:8080
curl <cka003_node_ip>:30514
Hello Kubernetes bootcamp! | Running on: myapp-b5d775f5d-6jtgs | v=1

Scale out Deployment

Scale out by replicaset. We set three replicasets to scale out deployment myapp. The number of deployment myapp is now three.

kubectl scale deployment myapp --replicas=3

Get status of deployment

kubectl get deployment myapp

Get status of replicaset

kubectl get replicaset

Rolling update

Command usage: kubectl set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N.

With the command kubectl get deployment, we will get deployment name myapp and related container name kubernetes-bootcamp.

kubectl get deployment myapp -o wide

With the command kubectl set image to update image to many versions and log the change under deployment's annotations with option --record.

kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record

Current replicas status

kubectl get replicaset -o wide -l app=myapp

Result. Pods are running on new Replicas.

NAME               DESIRED   CURRENT   READY   AGE   CONTAINERS            IMAGES                                       SELECTOR
myapp-5dbd68cc99   1         1         0       8s    kubernetes-bootcamp   docker.io/jocatalin/kubernetes-bootcamp:v2   app=myapp,pod-template-hash=5dbd68cc99
myapp-b5d775f5d    3         3         3       14m   kubernetes-bootcamp   docker.io/jocatalin/kubernetes-bootcamp:v1   app=myapp,pod-template-hash=b5d775f5d

We can get the change history under metadata.annotations.

kubectl get deployment myapp -o yaml

Result

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "2"
    kubernetes.io/change-cause: kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2
      --record=true
  ......

We can also get the change history by command kubectl rollout history, and show details with specific revision --revision=<revision_number>.

kubectl rollout history deployment/myapp

Result

deployment.apps/myapp 
REVISION  CHANGE-CAUSE
1         <none>
2         kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true

Get rollout history with specific revision.

kubectl rollout history deployment/myapp --revision=2

Roll back to previous revision with command kubectl rollout undo, or roll back to specific revision with option --to-revision=<revision_number>.

kubectl rollout undo deployment/myapp --to-revision=1

Revision 1 was replaced by new revision 3 now.

kubectl rollout history deployment/myapp

Result

deployment.apps/myapp 
REVISION  CHANGE-CAUSE
2         kubectl set image deployment/myapp kubernetes-bootcamp=docker.io/jocatalin/kubernetes-bootcamp:v2 --record=true
3         <none>

Event

Get detail event info of related Pod.

kubectl describe pod myapp-b5d775f5d-jlx6g

Result looks like below.

......
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  54s   default-scheduler  Successfully assigned dev/myapp-b5d775f5d-jlx6g to cka003
  Normal  Pulled     53s   kubelet            Container image "docker.io/jocatalin/kubernetes-bootcamp:v1" already present on machine
  Normal  Created    53s   kubelet            Created container kubernetes-bootcamp
  Normal  Started    53s   kubelet            Started container kubernetes-bootcamp

Get detail event info of entire cluster.

kubectl get event

Logging

Get log info of Pod.

kubectl logs -f <pod_name>
kubectl logs -f <pod_name> -c <container_name> 

Get a Pod logs

kubectl logs -f myapp-b5d775f5d-jlx6g
Kubernetes Bootcamp App Started At: 2022-07-23T06:54:18.532Z | Running On:  myapp-b5d775f5d-jlx6g

Get log info of K8s components.

kubectl logs kube-apiserver-cka001 -n kube-system
kubectl logs kube-controller-manager-cka001 -n kube-system
kubectl logs kube-scheduler-cka001 -n kube-system
kubectl logs etcd-cka001 -n kube-system
systemctl status kubelet
journalctl -fu kubelet
kubectl logs kube-proxy-5cdbj -n kube-system

Clean up.

kubectl delete service myapp
kubectl delete deployment myapp