Create a new pod called admin-pod with image busybox. Allow the pod to be able to set system time.
The container should sleep for 3200 seconds.
$ k run admin-pod -n cka --image=busybox --dry-run=client -o yaml --command -- sleep 3200 > admin-pod.yaml
$ cat admin-pod.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: admin-pod
name: admin-pod
namespace: cka
spec:
containers:
- command:
- sleep
- "3200"
image: busybox
name: admin-pod
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
Next, we need to figure out how to give pod the capabiliy to set the system time. This can be done by heading to https://kubernetes.io/docs and search for capabilities, which should lead to https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ page.
Search for SYS_TIME, and copy the sample code to merge with admin-pod.yaml.
# admin-pod.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: admin-pod
name: admin-pod
namespace: cka
spec:
containers:
- command:
- sleep
- "3200"
image: busybox
name: admin-pod
securityContext:
capabilities:
add: ["SYS_TIME"]
Create the Pod:
$ k apply -f admin-pod.yaml
pod/admin-pod created
$ k get pods -n cka
NAME READY STATUS RESTARTS AGE
admin-pod 1/1 Running 0 6s
Create a new deployment called web-proj-268, with image nginx:1.16 and 1 replica in cka namespace. Next, upgrade the deployment to version 1.17 using rolling update.
Make sure that the version upgrade is recorded in the resource annotation.
Let's practice using the CLI to create the required deployment.
$ k create deployment web-proj-268 --image=nginx:1.16 --replicas=1 --namespace cka
deployment.apps/web-proj-268 created
$ k get deploy web-proj-268 -n cka
NAME READY UP-TO-DATE AVAILABLE AGE
web-proj-268 1/1 1 1 43s
$ k get pods -n cka
NAME READY STATUS RESTARTS AGE
web-proj-268-569d995986-4sc5w 1/1 Running 0 53s
Next, upgrade the deployment to version 1.17 using rolling update.
$ k describe deploy web-proj-268 -n cka | grep Contain -A 2
Containers:
nginx:
Image: nginx:1.16
$ k set image deploy web-proj-268 -n cka nginx=nginx:1.17
deployment.apps/web-proj-268 image updated
$ kubectl rollout status deployments/web-proj-268 -n cka
deployment "web-proj-268" successfully rolled out
$ k describe deploy web-proj-268 -n cka | grep Contain -A 2
Containers:
nginx:
Image: nginx:1.17
We need to satify "Make sure that the version upgrade is recorded in the resource annotation."
$ k rollout history deployment.apps/web-proj-268 -n cka --revision=2
deployment.apps/web-proj-268 with revision #2
Pod Template:
Labels: app=web-proj-268
pod-template-hash=dff8c4569
Containers:
nginx:
Image: nginx:1.17
Port: <none>
Host Port: <none>
Environment: <none>
Mounts: <none>
Volumes: <none>
Node-Selectors: <none>
Tolerations: <none>
Let's annotate the CHANGE-CAUSE for revision 2.
$ k annotate deploy web-proj-268 -n cka kubernetes.io/change-cause='Update nginx to 1.17'
deployment.apps/web-proj-268 annotated
$ k rollout history deploy web-proj-268 -n cka
deployment.apps/web-proj-268
REVISION CHANGE-CAUSE
1 <none>
2 Update nginx to 1.17
My solution did not really meet the requirement for recorded in the resource annotation.
The provided solution is to pass --record to k set image....
$ k set image deployment web-proj-268 nginx=nginx:1.17 -n cka --record
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/web-proj-268 image updated
$ k rollout history deployment web-proj-268 -n cka
deployment.apps/web-proj-268
REVISION CHANGE-CAUSE
1 <none>
2 kubectl set image deployment web-proj-268 nginx=nginx:1.17 --namespace=cka --record=true
Interesting! The --record flag has been deprecated. It seems that the new method is to use k annotate to record Change Cause.
Here's an example to use k annotate .... --overwrite (Note: The --overwrite flag guarantees that the command updates the value if an older annotation already exists).
$ k annotate deploy web-proj-268 -n cka kubernetes.io/change-cause='Update nginx to 1.17 annotation with --overwrite' --overwrite
deployment.apps/web-proj-268 annotated
$ k rollout history deployment web-proj-268 -n cka
deployment.apps/web-proj-268
REVISION CHANGE-CAUSE
1 <none>
2 Update nginx to 1.17 annotation with --overwrite
Create a new deployment called web-003 in cka namespace. Scale the deployment to 3 replicas. Make sure the desired number of pod always running.
Pretend that you didn't know anything about the condition of the cluster. Just run the command below, only then proceed with the task.
sudo sed -i 's/\(^.*\- kube-controller-man\)ager/\1/' /etc/kubernetes/manifests/kube-controller-manager.yaml
Note: If the above command didn't work, you can manually open the kube-controller-manager.yaml with vim and make change to line 12.
$ k -n cka create deploy web-003 --image=nginx --replicas=3
deployment.apps/web-003 created
$ k get deploy -n cka
NAME READY UP-TO-DATE AVAILABLE AGE
web-003 0/3 0 0 41s
$ k get pods -n cka
No resources found in cka namespace.
Why isn't the cluster control manager create any pods?
$ k get pod -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-7d764666f9-dqssr 1/1 Running 5 (96m ago) 16d
coredns-7d764666f9-dxt7v 1/1 Running 5 (96m ago) 16d
etcd-ckacontrol 1/1 Running 6 (96m ago) 16d
etcd-s3-backup-29794359-tfsrr 0/1 Completed 0 13d
etcd-s3-backup-29805879-zfz6n 0/1 Completed 0 5d2h
etcd-s3-backup-29813079-z7xfb 0/1 Completed 0 95m
kube-apiserver-ckacontrol 1/1 Running 6 (96m ago) 16d
kube-controller-manager-ckacontrol 0/1 CrashLoopBackOff 5 (55s ago) 3m54s
kube-proxy-4cssm 1/1 Running 5 (96m ago) 16d
kube-proxy-5z6x4 1/1 Running 5 (95m ago) 16d
kube-scheduler-ckacontrol 1/1 Running 5 (96m ago) 16d
Ahhh, the kube-controller-manager-ckacontrol pod is in CrashLoopBackOff state.
$ k describe pod kube-controller-manager-ckacontrol -n kube-system | grep Event -A 6
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Pulled 2m16s (x6 over 5m15s) kubelet spec.containers{kube-controller-manager}: Container image "registry.k8s.io/kube-controller-manager:v1.35.8" already present on machine and can be accessed by the pod
Normal Created 2m16s (x6 over 5m15s) kubelet spec.containers{kube-controller-manager}: Container created
Warning Failed 2m16s (x6 over 5m15s) kubelet spec.containers{kube-controller-manager}: Error: failed to create containerd task: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: exec: "kube-controller-man": executable file not found in $PATH
Warning BackOff 53s (x18 over 5m13s) kubelet spec.containers{kube-controller-manager}: Back-off restarting failed container kube-controller-manager in pod kube-controller-manager-ckacontrol_kube-system(a18c2fe544e09ff2153b017af8df4c20)
The kube-controller-manager-ckacontrol is a static pod. Its YAML lives in /etc/kubernetes/manifests/.
$ sudo grep -w 'kube-controller-man' /etc/kubernetes/manifests/kube-controller-manager.yaml -A 2 -B 3 -n
9-spec:
10- containers:
11- - command:
12: - kube-controller-man
13- - --allocate-node-cidrs=true
14- - --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf
On line 12, we can see the command for the container was set to kube-controller-man, it should eb kube-controller-manager. Let's fix that.
$ sudo sed -i '12s/kube-controller-man/kube-controller-manager/' /etc/kubernetes/manifests/kube-controller-manager.yaml
$ k get pod kube-controller-manager-ckacontrol -n kube-system
NAME READY STATUS RESTARTS AGE
kube-controller-manager-ckacontrol 1/1 Running 0 15s
Without having to do anyting to the web-003 deployment, we can see all 3 pods are running:
$ k get deploy -n cka
NAME READY UP-TO-DATE AVAILABLE AGE
web-003 3/3 3 3 12m
$ k get pods -n cka
NAME READY STATUS RESTARTS AGE
web-003-6d9999cbb9-4n4z2 1/1 Running 0 14s
web-003-6d9999cbb9-ndddf 1/1 Running 0 14s
web-003-6d9999cbb9-nvrkn 1/1 Running 0 14s
Upgrade the Cluster (control and worker nodes) from 1.35.8 to 1.36.1. Make sure to first drain both nodes and make it available after upgrade.
For this upgrade task, we can refer to the official document: 'kubeadm upgrade'
On conrol node.
$ grep v1.35 /etc/yum.repos.d/kubernetes.repo
baseurl=https://pkgs.k8s.io/core:/stable:/v1.35/rpm/
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.35/rpm/repodata/repomd.xml.key
$ sudo sed -i 's/v1.35/v1.36/' /etc/yum.repos.d/kubernetes.repo
$ sudo yum list --showduplicates kubeadm --setopt=disable_excludes=kubernetes
Kubernetes 6.9 kB/s | 9.8 kB 00:01
Installed Packages
kubeadm.x86_64 1.35.8-150500.1.1 @kubernetes
Available Packages
kubeadm.aarch64 1.36.0-150500.1.1 kubernetes
kubeadm.ppc64le 1.36.0-150500.1.1 kubernetes
kubeadm.s390x 1.36.0-150500.1.1 kubernetes
kubeadm.src 1.36.0-150500.1.1 kubernetes
kubeadm.x86_64 1.36.0-150500.1.1 kubernetes
kubeadm.aarch64 1.36.1-150500.1.1 kubernetes
kubeadm.ppc64le 1.36.1-150500.1.1 kubernetes
kubeadm.s390x 1.36.1-150500.1.1 kubernetes
kubeadm.src 1.36.1-150500.1.1 kubernetes
kubeadm.x86_64 1.36.1-150500.1.1 kubernetes
... <snip> ...
$ sudo yum install -y kubeadm-'1.36.1-*' --setopt=disable_excludes=kubernetes
$ sudo kubeadm upgrade plan
$ sudo kubeadm upgrade apply v1.36.1
$ kubectl drain ckacontrol --ignore-daemonsets
$ sudo yum install -y kubelet-'1.36.1-*' kubectl-'1.36.1-*' --setopt=disable_excludes=kubernetes
$ sudo systemctl daemon-reload
$ sudo systemctl restart kubelet
The control node upgrade had been completed.
$ k get nodes
NAME STATUS ROLES AGE VERSION
ckacontrol Ready control-plane 33d v1.36.1
ckaworker1 Ready <none> 31d v1.35.8
Next, upgrade the worker node.
$ grep v1.35 /etc/yum.repos.d/kubernetes.repo
baseurl=https://pkgs.k8s.io/core:/stable:/v1.35/rpm/
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.35/rpm/repodata/repomd.xml.key
$ sudo sed -i 's/v1.35/v1.36/' /etc/yum.repos.d/kubernetes.repo
$ grep v1.36 /etc/yum.repos.d/kubernetes.repo
baseurl=https://pkgs.k8s.io/core:/stable:/v1.36/rpm/
gpgkey=https://pkgs.k8s.io/core:/stable:/v1.36/rpm/repodata/repomd.xml.key
$ sudo yum install -y kubeadm-'1.36.1-*' --setopt=disable_excludes=kubernetes
$ sudo kubeadm upgrade node
Drain the node.
$ kubectl drain ckaworker1 --ignore-daemonsets
node/ckaworker1 cordoned
error: unable to drain node "ckaworker1" due to error: cannot delete Pods with local storage (use --delete-emptydir-data to override): metrics-server/metrics-server-6678cf797c-qxmlb, continuing command...
There are pending nodes to be drained:
ckaworker1
cannot delete Pods with local storage (use --delete-emptydir-data to override): metrics-server/metrics-server-6678cf797c-qxmlb
$ kubectl drain ckaworker1 --ignore-daemonsets --delete-emptydir-data
$ sudo yum install -y kubelet-'1.36.1-*' kubectl-'1.36.1-*' --setopt=disable_excludes=kubernetes
$ sudo systemctl daemon-reload
$ sudo systemctl restart kubelet
Uncordon the node.
$ kubectl uncordon ckaworker1
node/ckaworker1 uncordoned
Verify:
$ k get nodes
NAME STATUS ROLES AGE VERSION
ckacontrol Ready control-plane 33d v1.36.1
ckaworker1 Ready <none> 31d v1.36.1
Deloy a web-load-5461 pod using the nginx:1.30 image with the labels set to tier=web.
TIP:
$ k run -h |grep label
Sample help output:
$ k run -h |grep label
# Start a hazelcast pod and set labels "app=hazelcast" and "env=prod" in the container
kubectl run hazelcast --image=hazelcast/hazelcast --labels="app=hazelcast,env=prod"
-l, --labels='':
Comma separated labels to apply to the pod. Will override previous values.
$ k run web-load-5461 --image=nginx:1.30 --labels="tier=web"
pod/web-load-5461 created
Verify:
$ k get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
web-load-5461 1/1 Running 0 28s tier=web
$ k describe pod web-load-5461 | grep -i image:
Image: nginx:1.30
A pod my-nginx-pod (image=nginx) in custom namespace is not running. Find the problem and fix it and make it running.
Note: All the supported definition files has been placed at root.
k create ns custom
cat <<EOF > my-nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-nginx-pod
namespace: custom
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: pv-claim-log
EOF
k apply -f my-nginx-pod.yaml
cat <<EOF > pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pv-claim-log
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-path
resources:
requests:
storage: 10Mi
EOF
k apply -f pvc.yaml
Note: Rancher's local-path is the only StorageClass (SC) available on my test cluster. local-path SC requires a PVC to be created, and the PV will be created automatically.
$ k get pod -n custom
NAME READY STATUS RESTARTS AGE
my-nginx-pod 0/1 Pending 0 42s
Whenever the pods is in pending state, we can use k describe to inspect the Events.
$ k -n custom describe pod my-nginx-pod | grep -A5 Events
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 3m13s default-scheduler 0/2 nodes are available: persistentvolumeclaim "pv-claim-log" not found. not found
$ k get pvc -n custom
No resources found in custom namespace.
$ k get pvc -A
NAMESPACE NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
default pv-claim-log Pending local-path <unset> 61s
We can see that a pvc named pv-claim-log was created in the default namespace. We need to delete that pvc, modify the pvc.yaml to ensure it'll be created in custom namespace.
$ k delete pvc pv-claim-log
persistentvolumeclaim "pv-claim-log" deleted from default namespace
$ cat pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pv-claim-log
namespace: custom
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-path
resources:
requests:
storage: 10Mi
$ k apply -f pvc.yaml
persistentvolumeclaim/pv-claim-log created
$ k get pod -n custom
NAME READY STATUS RESTARTS AGE
my-nginx-pod 1/1 Running 0 5m53s
k delete ns custom
Create a multi-container pod, named multi-pod in development namespace using images nginx and redis.
$ k create ns development
namespace/development created
$ cat multi-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: multi-pod
namespace: development
spec:
containers:
- name: nginx
image: nginx
- name: redis
image: valkey/valkey
$ k apply -f multi-pod.yaml
$ k get pod -n development
NAME READY STATUS RESTARTS AGE
multi-pod 2/2 Running 0 17s
k delete ns development
A pod nginx-pod (image=nginx) in the default namespace is not running. Find the problem and fix it and make it running.
kubectl taint nodes ckaworker1 color=blue:NoSchedule
k run nginx-pod --image=nginx
$ k get pod
NAME READY STATUS RESTARTS AGE
nginx-pod 0/1 Pending 0 12s
$ k describe pods nginx-pod | grep -i events: -A5
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 41s default-scheduler 0/2 nodes are available: 2 node(s) had untolerated taint(s). no new claims to deallocate, preemption: 0/2 nodes are available: 2 Preemption is not helpful for scheduling.
Check the taint on the nodes:
$ k describe nodes ckaworker1 | grep -i taint
Taints: color=blue:NoSchedule
$ k describe node ckacontrol | grep -i taint
Taints: node-role.kubernetes.io/control-plane:NoSchedule
Specify a toleration to the nginx-pod to schedule on ckaworker1 node.
$ k edit pod nginx-pod
Add the following under
tolerations:
- key: "color"
operator: "Equal"
value: "blue"
effect: "NoSchedule"
Verify that the pod is now running:
$ k get pods
NAME READY STATUS RESTARTS AGE
nginx-pod 1/1 Running 0 6m36s
$ k describe pod nginx-pod | grep -i toleration -A 2
Tolerations: color=blue:NoSchedule
node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
k taint nodes ckaworker1 color=blue:NoSchedule-
k delete pod nginx-pod
Create a new deployment called nginx-deploy, with image nginx:1.31.5 and 4 replicas. There are 2 worker node in cluster.
Make sure no pods will get deployed on 1 worke node ckaworker2.
Note: Revert any changes that you did in the cluster.
The solution provided here, suggests to cordon ckaworker2 node, created the deployment, the uncordon the node. While this solution seems to work, I'm going to use pod affinity feacher to ensure the deployment will not deploy to the worker node ckaworker2.
$ k get nodes ckaworker2 --show-labels
NAME STATUS ROLES AGE VERSION LABELS
ckaworker2 Ready <none> 63m v1.36.4 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=ckaworker2,kubernetes.io/os=linux
$ k create deploy nginx-deploy --image=nginx:1.31.5 --replicas=4 --dry-run=client -o yaml > nginx-deploy.yaml
Go to official doc, search for nodeAffinity. Update the nginx-deploy.yaml to include node affinity.
[kenno@ckacontrol ~]$ cat nginx-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy
name: nginx-deploy
spec:
replicas: 4
selector:
matchLabels:
app: nginx-deploy
template:
metadata:
labels:
app: nginx-deploy
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- ckaworker2
containers:
- image: nginx:1.31.5
name: nginx
Apply the manifest to create 4 Pods to be scheduled on worker nodes beside ckaworker2.
$ k apply -f nginx-deploy.yaml
deployment.apps/nginx-deploy created
$ k get deploy nginx-deploy -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nginx-deploy 4/4 4 4 2m12s nginx nginx:1.31.5 app=nginx-deploy
$ k get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deploy-6cb669cfdf-2sjll 1/1 Running 0 2m30s 172.16.237.196 ckaworker1 <none> <none>
nginx-deploy-6cb669cfdf-cq6fv 1/1 Running 0 2m30s 172.16.237.210 ckaworker1 <none> <none>
nginx-deploy-6cb669cfdf-qxb46 1/1 Running 0 2m30s 172.16.237.198 ckaworker1 <none> <none>
nginx-deploy-6cb669cfdf-z2rm5 1/1 Running 0 2m30s 172.16.237.205 ckaworker1 <none> <none>
k delete deploy nginx-deploy
Create a ReplicaSet named web-pod with image=nginx:1.31.5, with 3 replicas. Makes sure that total count of Pod running into a cluster is not more than 3.
k run demo-pod --image=nginx --labels="app=web"
A quick recap about ReplicaSet, it uses label to group Pods. Since, there exist a running Pod, and we need to create a ReplicaSet of 3 replicas without exceeding total 3 pods in the cluster, we therefore need to add the existing Pod to the group by reusing the label of the running Pod.
$ k get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
demo-pod 1/1 Running 0 3m18s app=web
Next, use official doc to find example manifest of a ReplicaSet.
# cat web-pod-rs.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: web-pod
labels:
app: web-pod
spec:
# modify replicas according to your case
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.31.5
Apply the manifest to create the ReplicaSet.
$ k apply -f web-pod-rs.yaml
replicaset.apps/web-pod created
$ k get rs
NAME DESIRED CURRENT READY AGE
web-pod 3 3 3 15s
Verify:
$ k get pods
NAME READY STATUS RESTARTS AGE
demo-pod 1/1 Running 0 5m48s
web-pod-892kn 1/1 Running 0 33s
web-pod-ck8vh 1/1 Running 0 33s
k delete pod demo-pod
k delete rs/web-pod
There are 3 nodes in the cluster. Create DaemonSet named my-pod,image=nginx, on each node except on node ckaworker1.
The provided solution is to taint ckaworker1, and use toleration to not schedule on this node. I guess it does work as well. I prefer to use infinity as I don't need to taint any node.
The official doc, has a section explaining on how to run pods on select nodes: use .spec.template.spec.nodeSelector or .spec.template.spec.affinity.
# my-pod-ds.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: my-pod
labels:
app: nginx
spec:
selector:
matchLabels:
name: nginx
template:
metadata:
labels:
name: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- ckaworker1
containers:
- name: nginx
image: nginx
Apply the manifest.
$ k apply -f my-pod-ds.yaml
daemonset.apps/my-pod created
$ k get ds
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
my-pod 1 1 1 1 1 <none> 75s
$ k get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
my-pod-2plfl 1/1 Running 0 57s 172.16.116.9 ckaworker2 <none> <none>
k delete ds/my-pod
Generate a file CKA007.txt with details about the available size of all the node in a Kubernetes cluster using a custom colmn, format as metioned below:
| NAME | AVAILABLE_MEMORY | AVAIALABLE_CPU |
|---|---|---|
| node1 | ... | ... |
| node2 | ... | ... |
$ k get nodes
NAME STATUS ROLES AGE VERSION
ckacontrol Ready control-plane 34d v1.36.1
ckaworker1 Ready <none> 33d v1.36.1
ckaworker2 Ready <none> 160m v1.36.4
We need to build the custom json output.
$ k get nodes ckaworker1 -o json
{
"apiVersion": "v1",
"kind": "Node",
"metadata": {
"annotations": {
"csi.volume.kubernetes.io/nodeid": "{\"csi.tigera.io\":\"ckaworker1\"}",
"node.alpha.kubernetes.io/ttl": "0",
"projectcalico.org/IPv4Address": "192.168.1.61/24",
"projectcalico.org/IPv4VXLANTunnelAddr": "172.16.237.192",
"projectcalico.org/Interfaces": "[{\"name\":\"enX0\",\"addresses\":[\"192.168.1.61\"]}]",
"volumes.kubernetes.io/controller-managed-attach-detach": "true"
},
"creationTimestamp": "2026-08-07T11:42:36Z",
"labels": {
"beta.kubernetes.io/arch": "amd64",
"beta.kubernetes.io/os": "linux",
"kubernetes.io/arch": "amd64",
"kubernetes.io/hostname": "ckaworker1",
"kubernetes.io/os": "linux"
},
"name": "ckaworker1"
...
"status": {
"addresses": [
{
"address": "192.168.1.61",
"type": "InternalIP"
},
{
"address": "ckaworker1",
"type": "Hostname"
}
],
"allocatable": {
"cpu": "1",
"ephemeral-storage": "11932375430",
"hugepages-1Gi": "0",
"hugepages-2Mi": "0",
"memory": "1897140Ki",
"pods": "110"
},
"capacity": {
"cpu": "1",
"ephemeral-storage": "12644Mi",
"hugepages-1Gi": "0",
"hugepages-2Mi": "0",
"memory": "1999540Ki",
"pods": "110"
},
...
$ k get nodes ckaworker1 ckaworker2 -o custom-columns=NAME:.metadata.name,AVAILABLE_MEMORY:.status.allocatable.memory,AVAILABLE_CPU:.status.allocatable.cpu > CKA007.txt
$ cat CKA007.txt
NAME AVAILABLE_MEMORY AVAILABLE_CPU
ckaworker1 1897140Ki 1
ckaworker2 3892144Ki 1
There are various Pods running in all the namespaces of Kubernetest Cluster. Write a commnad into /opt/pods_asc.sh which lists all the Pods sorted by their age in ascending order.
How?
$ k get pod -h | grep -i sort
--sort-by='':
If non-empty, sort list types using this field specification. The field specification is expressed as a JSONPath expression (e.g. '{.metadata.name}'). The field in the API resource specified by this JSONPath expression must be an integer or a string.
We need to find the JSONPath or YAML path that contains Pod start time.
$ k -n kube-system get pods etcd-ckacontrol -o yaml | grep -i time
creationTimestamp: "2026-09-08T10:21:25Z"
timeoutSeconds: 15
timeoutSeconds: 15
timeoutSeconds: 15
type: RuntimeDefault
- lastProbeTime: null
lastTransitionTime: "2026-09-10T08:55:54Z"
- lastProbeTime: null
lastTransitionTime: "2026-09-10T08:55:53Z"
- lastProbeTime: null
lastTransitionTime: "2026-09-10T08:56:10Z"
- lastProbeTime: null
lastTransitionTime: "2026-09-10T08:56:10Z"
- lastProbeTime: null
lastTransitionTime: "2026-09-10T08:55:53Z"
startTime: "2026-09-10T08:55:53Z
$ k -n kube-system get pods etcd-ckacontrol -o yaml | less
The creationTimestamp is a good metric we can use for Pod's age. I was able to construct the JSONPath expression as .metadata.creationTimestamp.
$ k get pods --sort-by='{.metadata.creationTimestamp}' -A
NAMESPACE NAME READY STATUS RESTARTS AGE
calico-system csi-node-driver-5qlrn 2/2 Running 62 (3h32m ago) 34d
calico-system csi-node-driver-qx786 2/2 Running 52 (3h32m ago) 34d
calico-system calico-node-d6qjb 1/1 Running 19 (3h32m ago) 27d
calico-system calico-node-24jft 1/1 Running 18 (3h32m ago) 27d
kube-system kube-proxy-8pwjd 1/1 Running 3 (3h32m ago) 2d2h
kube-system kube-proxy-gc8k5 1/1 Running 3 (3h32m ago) 2d2h
kube-system kube-controller-manager-ckacontrol 1/1 Running 3 (3h32m ago) 2d2h
kube-system kube-apiserver-ckacontrol 1/1 Running 4 (3h32m ago) 2d2h
kube-system kube-scheduler-ckacontrol 1/1 Running 3 (3h32m ago) 2d2h
kube-system etcd-ckacontrol 1/1 Running 3 (3h32m ago) 2d2h
calico-system calico-typha-7c79f6b9f5-65cgn 1/1 Running 3 (3h32m ago) 2d2h
calico-system calico-kube-controllers-8595d8b6c4-7rs5j 1/1 Running 3 (3h32m ago) 2d2h
calico-system whisker-77d846cb94-p2275 2/2 Running 6 (3h32m ago) 2d2h
kube-system coredns-589f44dc88-tqbzq 1/1 Running 3 (3h32m ago) 2d2h
tigera-operator tigera-operator-55f97df97b-25bd2 1/1 Running 3 (3h32m ago) 2d2h
calico-system goldmane-6f4684d4c9-njc64 1/1 Running 3 (3h32m ago) 2d2h
calico-system calico-apiserver-58c7d4d846-bvw5m 1/1 Running 3 (3h32m ago) 2d2h
kube-system coredns-589f44dc88-jdp7t 1/1 Running 3 (3h32m ago) 2d2h
metrics-server metrics-server-6678cf797c-jwvpc 1/1 Running 4 (3h31m ago) 2d2h
local-path-storage local-path-provisioner-85b7f88cfc-ljdl4 1/1 Running 3 (3h32m ago) 2d2h
calico-system calico-apiserver-58c7d4d846-ds46l 1/1 Running 3 (3h32m ago) 2d2h
kube-system etcd-s3-backup-29814519-dv5vc 0/1 Completed 0 47h
kube-system kube-proxy-cnqlp 1/1 Running 2 (3h32m ago) 24h
calico-system calico-node-6fkgs 1/1 Running 2 (3h32m ago) 24h
calico-system csi-node-driver-524p5 2/2 Running 4 (3h32m ago) 24h
calico-system calico-typha-7c79f6b9f5-cb92x 1/1 Running 2 (3h32m ago) 24h
kube-system etcd-s3-backup-29815959-pkt7j 0/1 Completed 0 23h
By default, the
--sort-byoption sorts the items in descending order (i.e. from oldest to youngest). We need to usetacto reverse it.
$ k get pods --sort-by='{.metadata.creationTimestamp}' -A --no-headers | tac
kube-system etcd-s3-backup-29815959-pkt7j 0/1 Completed 0 23h
calico-system calico-typha-7c79f6b9f5-cb92x 1/1 Running 2 (3h35m ago) 24h
calico-system csi-node-driver-524p5 2/2 Running 4 (3h35m ago) 24h
calico-system calico-node-6fkgs 1/1 Running 2 (3h35m ago) 24h
kube-system kube-proxy-cnqlp 1/1 Running 2 (3h35m ago) 24h
kube-system etcd-s3-backup-29814519-dv5vc 0/1 Completed 0 47h
calico-system calico-apiserver-58c7d4d846-ds46l 1/1 Running 3 (3h35m ago) 2d2h
local-path-storage local-path-provisioner-85b7f88cfc-ljdl4 1/1 Running 3 (3h35m ago) 2d2h
metrics-server metrics-server-6678cf797c-jwvpc 1/1 Running 4 (3h34m ago) 2d2h
kube-system coredns-589f44dc88-jdp7t 1/1 Running 3 (3h35m ago) 2d2h
calico-system calico-apiserver-58c7d4d846-bvw5m 1/1 Running 3 (3h35m ago) 2d2h
calico-system goldmane-6f4684d4c9-njc64 1/1 Running 3 (3h35m ago) 2d2h
tigera-operator tigera-operator-55f97df97b-25bd2 1/1 Running 3 (3h35m ago) 2d2h
kube-system coredns-589f44dc88-tqbzq 1/1 Running 3 (3h35m ago) 2d2h
calico-system whisker-77d846cb94-p2275 2/2 Running 6 (3h35m ago) 2d2h
calico-system calico-kube-controllers-8595d8b6c4-7rs5j 1/1 Running 3 (3h35m ago) 2d2h
calico-system calico-typha-7c79f6b9f5-65cgn 1/1 Running 3 (3h35m ago) 2d2h
kube-system etcd-ckacontrol 1/1 Running 3 (3h35m ago) 2d2h
kube-system kube-scheduler-ckacontrol 1/1 Running 3 (3h35m ago) 2d2h
kube-system kube-apiserver-ckacontrol 1/1 Running 4 (3h35m ago) 2d2h
kube-system kube-controller-manager-ckacontrol 1/1 Running 3 (3h35m ago) 2d2h
kube-system kube-proxy-gc8k5 1/1 Running 3 (3h35m ago) 2d2h
kube-system kube-proxy-8pwjd 1/1 Running 3 (3h35m ago) 2d2h
calico-system calico-node-24jft 1/1 Running 18 (3h35m ago) 27d
calico-system calico-node-d6qjb 1/1 Running 19 (3h35m ago) 27d
calico-system csi-node-driver-qx786 2/2 Running 52 (3h35m ago) 34d
calico-system csi-node-driver-5qlrn 2/2 Running 62 (3h35m ago) 34d
Finally:
$ echo "kubectl get pods --sort-by='{.metadata.creationTimestamp}' -A --no-headers | tac" | sudo tee /opt/pod_asc.sh
$ sudo chmod +x /opt/pod_asc.sh
Create a Pod nginx-k8s using image nginx and initContainer git-k8s with image alpine/git. Volume mount path of the main container /usr/share/nginx/html. Nginx index.html need to be override with shared volume.
# init-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-k8s
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- mountPath: /usr/share/nginx/html
name: share-volume
initContainers:
- name: git-k8s
image: alpine/git
command: ['git', 'clone', 'https://github.com/jhawithu/k8s-nginx.git', '/share']
volumeMounts:
- mountPath: /share
name: share-volume
volumes:
- name: share-volume
emptyDir:
sizeLimit: 50Mi
Apply the manifest.
$ k apply -f init-pod.yaml
pod/nginx-k8s created
$ k get pods
NAME READY STATUS RESTARTS AGE
nginx-k8s 0/1 Init:0/1 0 6s
$ k get pods
NAME READY STATUS RESTARTS AGE
nginx-k8s 1/1 Running 0 24s
Verify:
$ k exec -it nginx-k8s -- cat /usr/share/nginx/html/index.html
Defaulted container "nginx" out of: nginx, git-k8s (init)
<html>
<head>
<title>I Love Kubernetes</title>
<meta charset="utf-8" />
</head>
<body>
<h1>
Please don't forget to subscribe my channel! :)
</h1>
</body>
</html>