RBAC

1
2
3
4
5
6
7
8
9
10
11
12
13
设置配置环境:
[student@node-1] $ kubectl config use-context k8s

Context
为部署流水线创建一个新的ClusterRole并将其绑定到范围为特定的 namespace 的特定ServiceAccount

Task
创建一个名为deployment-clusterrole且仅允许创建以下资源类型的新ClusterRole
Deployment
StatefulSet
DaemonSet
在现有的 namespace app-team1中创建一个名为cicd-token的新 ServiceAccount
限于 namespace app-team1中,将新的ClusterRole deployment-clusterrole绑定到新的 ServiceAccount cicd-token
1
2
3
4
5
6
7
8
9
10
11
12
13
切换集群
kubectl config use-context k8s

开始操作
kubectl create clusterrole deployment-clusterrole --verb=create --resource=deployments,statefulsets,daemonsets
kubectl -n app-team1 create serviceaccount cicd-token

# 题目中要求“限于namespace app-team1中”,则创建rolebinding。没有要去,则创建clusterrolebinding。
# rolebinding后面的名字cicd-token-rolebinding随便起的,因为题目中没有要求,如果题目中有要求,就不能随便起了。
kubectl -n app-team1 create rolebinding cicd-token-rolebinding --clusterrole=deployment-clusterrole --serviceaccount=app-team1:cicd-token

检查
kubectl -n app-team1 describe rolebinding cicd-token-rolebinding
1
参考连接:http://kubernetes.io/zh/docs/reference/access-authn-authz/rbac

查看 pod 的 CPU

1
2
3
4
5
6
设置配置环境:
[student@node-1] $ kubectl config use-context k8s

Task
通过 pod label name=cpu-loader,找到运行时占用大量 CPU 的 pod,
并将占用 CPU 最高的 pod 名称写入文件 /opt/KUTR000401/KUTR00401.txt(已存在)。
1
2
3
4
5
6
7
8
9
10
11
开始操作
# kubectl config use-context k8s

# 查看pod名称 -A是所有namespace
kubectl top pod -l name=cpu-loader --sort-by=cpu -A

# 将cpu占用最多的pod的name写入/opt/test1.txt文件
echo "查出来的Pod Name" > /opt/KUTR000401/KUTR00401.txt

检查
cat /opt/KUTR000401/KUTR00401.txt

NetworkPolicy

1
2
3
4
5
6
7
8
9
10
11
Task - 1(可能会考的问题1

设置配置环境:
[student@node-1] $ kubectl config use-context hk8s

在现有的namespace my-app中创建一个名为allow-port-from-namespace的新NetworkPolicy
确保新的NetworkPolicy允许namespace echo中的Pods连接到namespace my-app中的Pods的9000端口。

进一步确保新的NetworkPolicy
不允许对没有在监听 端口9000的Pods的访问
不允许非来自 namespace echo中的Pods的访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@k8s-master cka]# cat networkpolicy.yaml 
#注意 :set paste,防止yaml文件空格错序。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-port-from-namespace
namespace: my-app #被访问者的命名空间
spec:
podSelector: #这两行必须要写,或者也可以写成一行为podSelector: {}
matchLabels: {}
policyTypes:
- Ingress #策略影响入栈流量
ingress:
- from: #允许流量的来源
- namespaceSelector:
matchLabels:
project: echo #访问者的命名空间的标签label
#- podSelector: {} #注意,这个不写。如果ingress里也写了- podSelector: {},则会导致my-app中的pod可以访问my-app中pod的9000了,这样不满足题目要求不允许非来自 namespace echo中的Pods的访问。而这道题有两种问法,在下面的Task-2里,是需要写的。
ports:
- protocol: TCP
port: 9000 #被访问者公开的端口
1
2
3
4
5
6
7
8
9
10
11
Task - 2(可能会考的问题2

设置配置环境:
[student@node-1] $ kubectl config use-context hk8s

在现有的namespace internal中创建一个名为allow-port-from-namespace-2的新NetworkPolicy
确保新的NetworkPolicy允许命名空间internal中的Pods能访问相同命名空间下的所有Pods的8080端口。

进一步确保新的NetworkPolicy
不允许对没有在监听 端口8080的Pods的访问
不允许非来自 namespace internal中的Pods的访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@k8s-master cka]# cat networkpolicy.yaml 
#注意 :set paste,防止yaml文件空格错序。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-port-from-namespace-2
namespace: internal
spec:
podSelector: #这两行必须要写,或者也可以写成一行为podSelector: {}
matchLabels: {}
policyTypes:
- Ingress
ingress:
- from:
- podSelector: {} #必须要写,这样才能满足internal命名空间下的所有Pods可以互相访问8080端口。
ports:
- protocol: TCP
port: 8080
1
参考连接:http://kubernetes.io/zh/docs/concepts/services-networking/network-policies

暴露服务 service

1
2
3
4
5
6
7
设置配置环境:
[student@node-1] $ kubectl config use-context k8s

Task
请重新配置现有的部署front-end以及添加名为http的端口规范来公开现有容器 nginx 的端口80/tcp。
创建一个名为front-end-svc的新服务,以公开容器端口http。
配置此服务,以通过在排定的节点上的 NodePort 来公开各个 Pods。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
开始操作
# kubectl config use-context k8s

检查deployment信息
kubectl get deploy front-end

参考官方文档,按照需要edit deployment,添加端口信息
kubectl edit deployment front-end
#注意 :set paste,防止yaml文件空格错序。
spec:
containers:
- image: vicuu/nginx:hello
imagePullPolicy: IfNotPresent
name: nginx #找到此位置。
ports: #往下添加这4行--------
- name: http
containerPort: 80
protocol: TCP

创建svc暴露对应端口
[root@k8s-master cka]# kubectl expose deployment front-end --type=NodePort --port=80 --target-port=80 --name=front-end-svc
1
参考连接:http://kubernetes.io/zh/docs/concepts/workloads/controllers/deployment

创建 Ingress

1
2
3
4
5
6
7
8
9
10
11
12
设置配置环境:
[student@node-1] $ kubectl config use-context k8s

Task
如下创建一个新的nginx Ingress资源:
名称: ping
Namespace: ing-internal
使用服务端口 5678在路径 /hello 上公开服务 hello


可以使用以下命令检查服务 hello的可用性,该命令应返回 hello:
curl -kL <INTERNAL_IP>/hello
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@k8s-master cka]# cat ingress.yaml 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
kubernetes.io/ingress.class: "nginx" #建议考试时,先不加这句,然后apply,等5分钟,如果一直没有出IP,则删除后,再加上这句,apply一下,如果5分钟还是没出。只有一种可能,你别的地方写错了。如果此时你又找不出错误,我建议你将这行去掉,继续做题
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /hello
pathType: Prefix
backend:
service:
name: hello
port:
number: 5678
[root@k8s-master cka]# kubectl get ingress -n ing-internal
[root@k8s-master cka]# curl $IP/hello
hello World
1
参考连接:http://kubernetes.io/zh/docs/concepts/services-networking/ingress/#the-ingress-resource

扩容 deployment副本数量

1
2
3
4
5
设置配置环境:
[student@node-1] $ kubectl config use-context k8s

Task
将 deployment presentation 扩展至 4个 pods
1
2
3
[root@k8s-master cka]# kubectl scale --replicas=4 deployment presentation
[root@k8s-master cka]# kubectl get pod -l app=presentation | wc -l
4

调度 pod 到指定节点

1
2
3
4
5
6
7
8
设置配置环境:
[student@node-1] $ kubectl config use-context k8s

Task
按如下要求调度一个 pod:
名称:nginx-kusc00401
Image:nginx
Node selector:disk=ssd
1
2
3
4
5
6
7
8
9
10
11
[root@k8s-master cka]# cat nodeslector.yaml 
apiVersion: v1
kind: Pod
metadata:
name: nginx-kusc00401
spec:
containers:
- name: nginx
image: nginx
nodeSelector:
disk: ssd
1
参考连接:http://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node

查看可用节点

1
2
3
4
5
6
设置配置环境:
[student@node-1] $ kubectl config use-context k8s

Task
检查有多少 nodes 已准备就绪(不包括被打上 Taint:NoSchedule 的节点),
并将数量写入 /opt/KUSC00402/kusc00402.txt
1
[root@k8s-master cka]# kubectl describe nodes | grep -i taints | grep -vc NoSchedule > /opt/KUSC00402/kusc00402.txt

创建多容器的 pod

1
2
3
4
5
6
7
8
9
10
设置配置环境:
[student@node-1] $ kubectl config use-context k8s

Task
按如下要求调度一个Pod:
名称:kucc8
app containers: 2
container 名称/images:
* nginx
* consul
1
2
3
4
5
6
7
8
9
10
11
[root@k8s-master cka]# cat pod.yaml 
apiVersion: v1
kind: Pod
metadata:
name: kucc8
spec:
containers:
- name: nginx
image: nginx
- name: consul
image: consul
1
参考连接:http://kubernetes.io/zh/docs/concepts/workloads/pods

创建 PV

1
2
3
4
5
6
设置配置环境:
[student@node-1] $ kubectl config use-context hk8s

Task
创建名为 app-config 的 persistent volume,容量为 1Gi,访问模式为 ReadWriteMany。
volume 类型为 hostPath,位于 /srv/app-config
1
2
3
4
5
6
7
8
9
10
11
12
13
[root@k8s-master cka]# cat pv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
name: app-config
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
hostPath:
path: "/srv/app-config"
1
参考连接:https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-persistent-volume-storage/

创建 PVC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
设置配置环境:
[student@node-1] $ kubectl config use-context ok8s

Task
创建一个新的PersistentVolumeClaim:
名称: pv-volume
Class: csi-hostpath-sc
容量: 10Mi


创建一个新的Pod,来将PersistentVolumeClaim作为volume进行挂载:
名称:web-server
Image:nginx
挂载路径:/usr/share/nginx/html
配置新的Pod,以对volume具有ReadWriteOnce权限。
最后,使用kubectl edit或kubectl patch将 PersistentVolumeClaim的容量扩展为70Mi,并记录此更改。
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
[root@k8s-master cka]# cat pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pv-volume #2相同
spec:
storageClassName: csi-hostpath-sc
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Mi
---
apiVersion: v1
kind: Pod
metadata:
name: web-server
spec:
volumes:
- name: task-pv-storage #1相同
persistentVolumeClaim:
claimName: pv-volume #2相同
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: task-pv-storage #1相同
在线修改
[root@k8s-master cka]# kubectl edit pvc pv-volume --save-config
resources.requests.storage : 10Mi 修改为70Mi
1
参考连接:https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-persistent-volume-storage/

查看 pod 日志

1
2
3
4
5
6
7
#设置配置环境:
[student@node-1] $ kubectl config use-context k8s

#Task
监控 pod foo 的日志并:
提取与错误 RLIMIT_NOFILE相对应的日志行
将这些日志行写入 /opt/KUTR00101/foo
1
[root@k8s-master cka]# kubectl logs foo | grep "RLIMIT_NOFILE" > /opt/KUTR00101/foo

使用 sidecar 代理容器日志

1
2
3
4
5
6
7
8
9
10
11
12
13
#设置配置环境:
[student@node-1] $ kubectl config use-context k8s

#Context
将一个现有的 Pod 集成到 Kubernetes 的内置日志记录体系结构中(例如 kubectl logs)。
添加 streaming sidecar 容器是实现此要求的一种好方法。

#Task
使用busybox Image来将名为sidecar的sidecar容器添加到现有的Pod 11-factor-app中。
新的sidecar容器必须运行以下命令:
/bin/sh -c tail -n+1 -f /var/log/11-factor-app.log
使用挂载在/var/log的Volume,使日志文件11-factor-app.log可用于sidecar 容器。
除了添加所需要的volume mount以外,请勿更改现有容器的规格。
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
# 导出这个pod的yaml文件
[root@k8s-master cka]# kubectl get pod 11-factor-app -o yaml > varlog.yaml
# 备份yaml文件,防止改错了,回退。
[root@k8s-master cka]# cp varlog.yaml varlog-bak.yaml

# 修改varlog.yaml文件
[root@k8s-master cka]# vim varlog.yaml
spec:

。。。。。。
volumeMounts: #在原配置文件,这段后面添加
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-4l6w8
readOnly: true
- name: varlog #新加内容
mountPath: /var/log #新加内容
- name: sidecar #新加内容,注意 name 别写错了
image: busybox #新加内容
args: [/bin/sh, -c, 'tail -n+1 -f /var/log/11-factor-app.log'] #新加内容,注意 文件名 别写错了
volumeMounts: #新加内容
- name: varlog #新加内容
mountPath: /var/log #新加内容
- name: count-log-2
image: busybox
args: [/bin/sh, -c, 'tail -n+1 -f /var/log/2.log']
volumeMounts:
- name: varlog
mountPath: /var/log
volumes: #在原配置文件,灰色的这段后面添加。
- name: kube-api-access-sdk4p
projected:
defaultMode: 420
sources:
- serviceAccountToken:
expirationSeconds: 3607
path: token
- configMap:
items:
- key: ca.crt
path: ca.crt
name: kube-root-ca.crt
- downwardAPI:
items:
- fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
path: namespace
- name: varlog #新加内容,注意找好位置。
emptyDir: {} #新加内容
# 删除原先的pod
[root@k8s-master cka]# kubectl delete pod 11-factor-app
[root@k8s-master cka]# kubectl get pod 11-factor-app
# 新建这个pod
[root@k8s-master cka]# kubectl apply -f varlog.yaml
1
参考连接:http://kubernetes.io/zh/docs/concepts/cluster-administration/logging

升级集群

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#设置配置环境:
[student@node-1] $ kubectl config use-context mk8s

#Task
现有的Kubernetes 集群正在运行版本1.23.1。仅将master节点上的所有 Kubernetes控制平面和节点组件升级到版本1.23.2

确保在升级之前 drain master节点,并在升级后 uncordon master节点。
可以使用以下命令,通过ssh连接到master节点:
ssh master01
可以使用以下命令,在该master节点上获取更高权限:
sudo -i

另外,在主节点上升级kubelet和kubectl。
请不要升级工作节点,etcd,container 管理器,CNI插件, DNS服务或任何其他插件。
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
# cordon 停止调度,将node调为SchedulingDisabled。新pod不会被调度到该node,但在该node的旧pod不受影响
# drain 驱逐节点。首先,驱逐该node上的pod,并在其他节点重新创建。接着,将节点调为 SchedulingDisabled
[root@k8s-master cka]# kubectl cordon master01
[root@k8s-master cka]# kubectl drain master01 --ignore-daemonsets

# ssh到master节点,并切换到root下
ssh master01
sudo -i
# 下载软件
[root@k8s-master cka]# apt-get install kubeadm=1.23.2-00 -y
# 查看版本
[root@k8s-master cka]# kubeadm version
# 验证升级计划,提示时输入y
[root@k8s-master cka]# kubeadm upgrade apply v1.23.2 --etcd-upgrade=false

#升级kubelet
[root@k8s-master cka]# apt-get install kubelet=1.23.2-00 kubectl=1.23.2-00 -y
# 退出root,退回到student@master01
exit
# 退出master01,退回到student@node01
exit
# 恢复master01调度
[root@k8s-master cka]# kubectl uncordon master01
# 检查是否正常
[root@k8s-master cka]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane,master 2h v1.23.2
k8s-node1 Ready <none> 45d v1.23.1
k8s-node2 Ready <none> 45d v1.23.1
1
参考连接:http://kubernetes.io/zh/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade

备份还原 etcd

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 设置配置环境
此项目无需更改配置环境。但是,在执行此项目之前,请确保您已返回初始节点。
[student@master01] $ exit
(注意,从上文可知,etcd这道题真实考试为第4题,用的集群是真实考试时的上一题的集群,即真题第3题mk8s,所以无需再切换集群了)

# Task
首先,为运行在https://127.0.0.1:2379上的现有 etcd 实例创建快照并将快照保存到 /var/lib/backup/etcd-snapshot.db
为给定实例创建快照预计能在几秒钟内完成。 如果该操作似乎挂起,则命令可能有问题。用 CTRL + C 来取消操作,然后重试。
然后还原位于/data/backup/etcd-snapshot-previous.db的现有先前快照。
提供了以下TLS证书和密钥,以通过etcdctl连接到服务器。

CA 证书: /opt/KUIN00601/ca.crt
客户端证书: /opt/KUIN00601/etcd-client.crt
客户端密钥: /opt/KUIN00601/etcd-client.key
  • 以下这种做发只是为了考试不出错,其正确的etcd备份还原操作还是比较严谨的,这种方法是让考试发挥更大的分值而不出错 *
1
2
3
4
5
6
备份:
# 如果不使用export ETCDCTL_API=3,而使用ETCDCTL_API=3,则下面每条etcdctl命令前都要加ETCDCTL_API=3。
[root@k8s-master cka]# etcdctl --endpoints=https://127.0.0.1:2379 --cacert="/opt/KUIN00601/ca.crt" --cert="/opt/KUIN00601/etcd-client.crt" --key="/opt/KUIN00601/etcd-client.key" snapshot save /var/lib/backup/etcd-snapshot.db
还原:
# /data/backup/etcd-snapshot-previous.db的权限应该是只有root可读,所以需要使用sudo命令
[root@k8s-master cka]# sudo ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 --cacert="/opt/KUIN00601/ca.crt" --cert="/opt/KUIN00601/etcd-client.crt" --key="/opt/KUIN00601/etcd-client.key" snapshot restore /data/backup/etcd-snapshot-previous.db
  • 正确的etcd备份与还原
1
2
3
4
5
6
7
8
9
10
11
12
13
14
## 移除且备份 /etc/kubernetes/manifests 目录
[root@k8s-master cka]# sudo mv /etc/kubernetes/manifests /etc/kubernetes/manifests.bak

## 查看 kube-apiserver、etcd 镜像是否停止
[root@k8s-master cka]# docker ps|grep etcd && docker ps|grep kube-apiserver

## 备份现有 Etcd 数据
[root@k8s-master cka]# sudo mv /var/lib/etcd /var/lib/etcd.bak

##开始还原(还原时,可以不加证书和秘钥)
[root@k8s-master cka]# sudo ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 --cacert="/opt/KUIN00601/ca.crt" --cert="/opt/KUIN00601/etcd-client.crt" --key="/opt/KUIN00601/etcd-client.key" snapshot restore /data/backup/etcd-snapshot-previous.db --data-dir=/var/lib/etcd/

## 恢复 Kube-Apiserver 与 Etcd 镜像
[root@k8s-master cka]# sudo mv /etc/kubernetes/manifests.bak /etc/kubernetes/manifests

节点维护

1
2
3
4
5
#设置配置环境:
[student@node-1] $ kubectl config use-context ek8s

#Task
将名为 node02 的 node 设置为不可用,并重新调度该 node 上所有运行的 pods。
1
2
3
4
5
[root@k8s-master cka]# kubectl cordon node02
[root@k8s-master cka]# kubectl drain node02 --ignore-daemonsets --delete-emptydir-data --force

#检查node2是否还有pod,忽略daemonset
[root@k8s-master cka]# kubectl get pod -A -o wide | grep node2

排查集群中故障节点

1
2
3
4
5
6
7
8
9
10
11
# 设置配置环境:
[student@node-1] $ kubectl config use-context wk8s

# Task
名为node02的Kubernetes worker node处于NotReady状态。
调查发生这种情况的原因,并采取相应的措施将node恢复为Ready状态,确保所做的任何更改永久生效。

可以使用以下命令,通过ssh连接到node02节点:
ssh node02
可以使用以下命令,在该节点上获取更高权限:
sudo -i
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# ssh到master节点,并切换到root下
[student@node-1] $ ssh node02
[root@k8s-master cka]# sudo -i
# 查看服务状态,发现没启动
[root@k8s-master cka]# systemctl status kubelet
# 重启服务
[root@k8s-master cka]# systemctl restart kubelet
# 设置开机自启动
[root@k8s-master cka]# systemctl enable kubelet
# 退出root,退回到student@node02
exit
# 退出node02,退回到student@node01
exit
在检查节点,确保节点都已Ready状态
[root@k8s-master cka]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready control-plane,master 126d v1.23.0
k8s-node1 Ready <none> 45d v1.23.0
k8s-node2 Ready <none> 45d v1.23.0