Certified Kubernetes Administrator (CKA) learning note | Wenhan Code life

Certified Kubernetes Administrator (CKA) learning note

Install

  1. Install docker.io
1
apt install docker.io

If you install docker with other cgroup driver, you have to make sure that
docker and Kubernetes will use same cgroup driver.

1
2
3
4
5
cat << EOF >> /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
EOF
  1. install apt key and source to system
1
2
3
4
5
root@kube-master:~# curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
OK
root@kube-master:~# cat <<EOF >> /etc/apt/sources.list.d/kubernetes.list
> deb http://apt.kubernetes.io/ kubernetes-xenial main
> EOF

Then install kubernetes packages

1
2
root@kube-master:~# apt update -y
root@kube-master:~# apt install -y kubelet kubeadm kubectl
  1. setup and config with kubeadm

You must choose a CNI when you execute kubeadm init, in this post I choose
flunnel, so I have to add --pod-network-cidr options.

1
root@k8sm:~# kubeadm init --pod-network-cidr=10.244.0.0/16

after waiting for some while, you should see below message that shows the
install is complete

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Your Kubernetes master has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of machines by running the following on each node
as root:

kubeadm join 192.168.122.75:6443 --token .....<snip>

Follow the instruction, run below comand as a regular user

1
2
3
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

And you need to memo the command start with kubeadm join, you will need to
exeute this command on your kubernetes node to join to the cluster

In order for your pods to communicate with one another, you’ll need to install
pod networking. We are going to use Flannel for our Container Network Interface
(CNI) because it’s easy to install and reliable. Enter this command:

1
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

Next run below command to make sure everything is coming up.

1
kubectl get pods --all-namespaces

If you see the coredns-xxxxxx pod is running, and your master node is Ready,
your cluster is ready to accept worker nodes.

1
2
3
4
5
6
7
8
9
10
11
12
13
wshi@k8sm:~$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-78fcdf6894-ltgw2 1/1 Running 0 17m
kube-system coredns-78fcdf6894-n8hw2 1/1 Running 0 17m
kube-system etcd-k8sm 1/1 Running 0 16m
kube-system kube-apiserver-k8sm 1/1 Running 0 16m
kube-system kube-controller-manager-k8sm 1/1 Running 0 16m
kube-system kube-flannel-ds-amd64-ktcqm 1/1 Running 0 1m
kube-system kube-proxy-nczhf 1/1 Running 0 17m
kube-system kube-scheduler-k8sm 1/1 Running 0 16m
wshi@k8sm:~$ kubectl get node
NAME STATUS ROLES AGE VERSION
k8sm Ready master 17m v1.11.2
  1. setup other node and join to the cluster

For the rest worker nodes, you just need to install kubectl, kubeadm, kubelet
and docker refer above, then execute the kubeadm join ... command which was
mentioned before.
After a while, you should see all worker nodes are ready to use.

1
2
3
4
5
wshi@k8sm:~$ kubectl get node
NAME STATUS ROLES AGE VERSION
k8sm Ready master 44m v1.11.2
k8sn1 Ready <none> 11m v1.11.2
k8sn2 Ready <none> 11m v1.11.2

Run a Job

Applications that running inside a pod are called “jobs”.

Most Kubernetes objects are created using yaml. Here is a sample yaml for a job which uses perl to calculate pi to 2000 digits and then stops.

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
backoffLimit: 4

Create this yaml file on your master node and call it “pi-job.yaml”. Run the job with the command:

1
kubectl create -f pi-job.yaml

Get the detail information of this job with the command:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
...
pi-72c7r 0/1 Completed 0 3m

$ kubectl describe pod pi-72c7r
Name: pi-72c7r
Namespace: default
Node: juju-cfb27c-2/10.188.44.225
Start Time: Wed, 29 Aug 2018 02:45:34 +0000
Labels: controller-uid=9a903f30-ab35-11e8-9b51-feb3e5f3b327
job-name=pi
Annotations: <none>
Status: Succeeded
IP: 10.1.33.7
Controlled By: Job/pi
Containers:
pi:
Container ID: docker://0d48f71cc6a2825cf4113f237170e63b06e1e310eca2e950dc979b48f26fb41f
Image: perl
Image ID: docker-pullable://perl@sha256:a264b269d0ea9687ea1485e47a0f4039b2dab99fc9c6e3faf001b452b57d6087
Port: <none>
Host Port: <none>
Command:
perl
-Mbignum=bpi
-wle
print bpi(2000)
State: Terminated
Reason: Completed
Exit Code: 0
Started: Wed, 29 Aug 2018 02:47:01 +0000
Finished: Wed, 29 Aug 2018 02:47:07 +0000
Ready: False
Restart Count: 0
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-pkk4t (ro)
Conditions:
Type Status
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
default-token-pkk4t:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-pkk4t
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 3m default-scheduler Successfully assigned default/pi-72c7r to juju-cfb27c-2
Normal Pulling 3m kubelet, juju-cfb27c-2 pulling image "perl"
Normal Pulled 1m kubelet, juju-cfb27c-2 Successfully pulled image "perl"
Normal Created 1m kubelet, juju-cfb27c-2 Created container
Normal Started 1m kubelet, juju-cfb27c-2 Started container

And view the log(STDOUT) with below command:

1
2
$ kubectl logs pi-72c7r
3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275898

Here is another example YAML file for job which use the image “busybox” and sleep for 10 seconds

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: batch/v1
kind: Job
metadata:
name: busybox
spec:
template:
spec:
containers:
- name: busybox
image: busybox
command: ["sleep", "10"]
restartPolicy: Never
backoffLimit: 4

Deploy a Pod

Pods usually represent running applications in a Kubernetes cluster. Here is an example of some yaml which defines a pod:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Pod
metadata:
name: alpine
namespace: default
spec:
containers:
- name: alpine
image: alpine
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
restartPolicy: Always

run a Pod

1
kubectl create -f alpine.yaml

delete a Pod

1
kubectl delete -f alpine.yaml

Or

1
kubectl delete pod alpine
1
kubectl delete pod/alpine

Examine the current status

1
2
3
kubectl get nodes
kubectl describe node node-name
kubectl get pods --all-namespaces -o wide

Use -n will specify the namespace in use

1
kubectl get pods -n kube-system

Deployment

A yaml file for an nginx deployment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80

Create the deployment and pod

1
kubectl create -f nginx-deployment.yaml

Find the detail info

1
kubectl describe deployment nginx-deployment

Check pod is running on which node

1
2
3
$ kubectl get pod nginx-deployment-7fc9b7bd96-c6wwh -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
nginx-deployment-7fc9b7bd96-c6wwh 1/1 Running 0 21h 10.1.33.6 juju-cfb27c-2 <none>

rollout image version

Change the image version to 1.8, you run below command

1
kubectl set image deployment nginx-deployment nginx=nginx:1.8

Or, you can update the line in the yaml to 1.8 version of the image, and apply
the changes with

1
kubectl apply -f nginx-deployment.yaml

Check the status of the rollout with below command

1
kubectl rollout status deployment nginx-deployment

Undo the previous rollout

1
kubectl rollout undo deployment nginx-deployment

View the history

1
kubectl rollout history deployment nginx-deployment

Go to a specific point in history

1
kubectl rollout history deployment nginx-deployment --revision=x

Setting Container Environment Variables

Deploy a pod to print Environment Variables

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: Pod
metadata:
name: env-dump
spec:
containers:
- name: busybox
image: busybox
command:
- env
env:
- name: STUDENT_NAME
value: "Your Name"
- name: SCHOOL
value: "Linux Academy"
- name: KUBERNETES
value: "is awesome"

After executed the pod, you can check Environment Viriables by log

1
2
3
4
5
6
$ kubectl logs env-dump
....
STUDENT_NAME=Your Name
SCHOOL=Linux Academy
KUBERNETES=is awesome
....

Scaling pod

command line

Use scale to deployment with –replicas=X

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 2 2 2 2 21h
$ kubectl scale deployment nginx-deployment --replicas=3
deployment.extensions/nginx-deployment scaled
$ kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 3 3 3 3 21h
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
...
nginx-deployment-7fc9b7bd96-c6wwh 1/1 Running 0 21h
nginx-deployment-7fc9b7bd96-kddj5 1/1 Running 0 31s
nginx-deployment-7fc9b7bd96-s86gc 1/1 Running 0 21h

yaml file

Update replicas: x part in yaml file, and apply the changes with

1
kubectl apply -f nginx-deployment.yml

Replication Controllers, Replica Sets, and Deployments

Deployments replaced the older ReplicationController functionality, but it never
hurts to know where you came from. Deployments are easier to work with,
and here’s a brief exercise to show you how.
A Replication Controller ensures that a specified number of pod replicas are running
at any one time. In other words, a Replication Controller makes sure that a pod or
a homogeneous set of pods is always up and available.

To maintain three copies of an nginx container

Replication Controllers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx
spec:
replicas: 3
selector:
app: nginx
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80

ReplicaSet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1beta2
kind: ReplicaSet
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80

Deployment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1beta2 # for versions before 1.8.0 use apps/v1beta1
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
ports:
- containerPort: 80

Label

Label node with colors

1
2
3
4
kubectl label node node1-name color=black
kubectl label node node2-name color=red
kubectl label node node3-name color=green
kubectl label node node4-name color=blue

Label all pod in default namespace by using --all

1
kubectl label pods -n default color=white --all

Get pod/node/etc with specific label

1
kubectl get pods -l color=white -n default

Get pod with multi labels

1
kubectl get pods -l color=white,app=nginx

DaemonSet

Deploy nginx pod on all node with

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: cthulu
labels:
daemon: "yup"
spec:
selector:
matchLabels:
daemon: "pod"
template:
metadata:
labels:
daemon: pod
spec:
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: cthulu-jr
image: nginx

Confirm that pod is running on each node

1
2
3
4
5
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
cthulu-kvbk9 1/1 Running 0 2m 10.1.33.8 juju-cfb27c-2 <none>
cthulu-t7hfc 1/1 Running 0 2m 10.1.45.13 juju-cfb27c-1 <none>
cthulu-x8hdf 1/1 Running 0 2m 10.1.31.9 juju-cfb27c-3 <none>

Label a Node & Schedule a Pod

Label a Node to let you can schedule a pod on it.

1
kubectl label node juju-cfb27c-3 deploy=here

use nodeSelector in yaml file to let a pod being deployed on the specific
node

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: Pod
metadata:
name: busybox
namespace: default
spec:
containers:
- name: busybox
image: busybox
command:
- sleep
- "300"
imagePullPolicy: IfNotPresent
restartPolicy: Always
nodeSelector:
deploy: here

Confirm

1
2
3
$ kubectl get pod busybox -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE
busybox 1/1 Running 0 10s 10.1.31.10 juju-cfb27c-3 <none>

Specific Schedulers

Ordinarily, we don’t need to specify the scheduler’s name in the spec because everyone uses a
single default one. Sometimes, however, developers need to have custom schedulers in charge of
placing pods due to legacy or specialized hardware constraints.

Use schedulerName in yaml to specific a customer scheduler

1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: Pod
metadata:
name: annotation-default-scheduler
labels:
name: multischeduler
annotations:
scheduledBy: custom-scheduler
spec:
schedulerName: custom-scheduler
containers:
- name: pod-container
image: k8s.gcr.io/pause:2.0

Logs

View the current logs of a pod

1
kubectl logs pod-name

View the current logs of a pod interactively

1
kubectl logs pod-name -f

Print last 10 lines of the log.

1
kubectl logs pod-name --tail=10

Log file in master/node machine can be found at /var/log/containers directory

Node maintenance

Maintenance a node by preventing the scheduler from putting new pods on to it and
evicting any existing pods. Ignore the DaemonSets – those pods are only providing
services to other local pods and will come back up when the node comes back up.

In this example I’m going to remove juju-cfb27c-2 from cluster.

1
2
3
root@juju-cfb27c-0:~# kubectl drain juju-cfb27c-2 --ignore-daemonsets
node/juju-cfb27c-2 cordoned
WARNING: Ignoring DaemonSet-managed pods: cthulu-kvbk9, nginx-ingress-kubernetes-worker-controller-t6qh9

juju-cfb27c-2 is marked as “SchedulingDisabled”

1
2
3
4
5
# kubectl get node
NAME STATUS ROLES AGE VERSION
juju-cfb27c-1 Ready <none> 4d v1.11.2
juju-cfb27c-2 Ready,SchedulingDisabled <none> 4d v1.11.2
juju-cfb27c-3 Ready <none> 4d v1.11.2

Now -2 node can be shutdown and do maintenance work, no pod will be schedule on
it. If you create some new pods, they will only placed on juju-cfb27c-1 and -3.

Next, when -2 node is ready to use, you can get it back with

1
2
3
4
5
6
7
# kubectl uncordon juju-cfb27c-2 
node/juju-cfb27c-2 uncordoned
# kubectl get node
NAME STATUS ROLES AGE VERSION
juju-cfb27c-1 Ready <none> 4d v1.11.2
juju-cfb27c-2 Ready <none> 4d v1.11.2
juju-cfb27c-3 Ready <none> 4d v1.11.2

Upgrading Kubernetes Components

Confirm the current version with

1
kubectl get nodes
  1. Upgrade kubeadm on the master node
1
sudo apt upgrade kubeadm

And confirm the version of kubeadm with

1
kubeadm version
  1. check the upgrade plan
1
sudo kubeadm upgrade plan
  1. apply the upgrade plan
1
sudo kubeadm upgrade apply v1.x.x
  1. upgrade kubelet

Before upgrade kubelet, first you need to drain the node which you want to
upgrade

1
kubectl drain NODENAME --ignore-daemonsets

Then, update kubelet manaully with

1
2
sudo apt update
sudo apt upgrade kubelet

Don’t forget to make your node avaliable after the upgrade.

1
kubectl uncordon NODENAME

Network

Inbound Node Port Requirements

  • Master Nodes
    • TCP 6443 – Kubernetes API Server
    • TCP 2379-2380 – etcd server client API
    • TCP 10250 – Kubelet API
    • TCP 10251 – Kube-scheduler
    • TCP 10252 – kube-controller-manager
    • TCP 10255 – Read-only Kubelet API
  • Worker Nodes
    • TCP 10250 – Kubelet API
    • TCP 10255 – Read-only Kubelet API
    • TCP 30000-32767 – Node Port Services

export pod to the internet

1
# kubectl expost deployment NAME --type="NodePort" --port XX

Deploying a Load Balancer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Kind:Service
apiVersion: v1
metadata:
name: la-lb-service
spec:
selector:
app: la-lb
ports:
- protocol: TCP
port: 80
targetPort:9376
clusterIP: 10.0.171.223
loadBalancerIP: 78.12.23.17
type: LoadBalancer