K8S CKA 学习笔记 (全)
K8S CKA学习笔记
一、环境
ssh登录node01(11.0.1.112),使用candidate帐号做题,密码为123,在node01上可以免密切换到其他节点,如 ssh master01 或 ssh node02,candidate帐号也可以免密切换到root,如 sudo -i
11.0.1.112
root/123456
切换到candidate帐号
su candidate
虚拟机和宿主机共享目录:
candidate@node01:~$ sudo -i
root@node01:~# find / -name macshare
/mnt/hgfs/macshare
root@node01:~#
/mnt/hgfs/macshare
查看目录:
candidate@node01:~/k8sYaml$ pwd
/home/candidate/k8sYaml
candidate@node01:~/k8sYaml$ ls -l
total 32
-rw-r--r-- 1 candidate candidate 391 Feb 16 10:02 ingress-05.yaml
-rw-r--r-- 1 candidate candidate 52 Feb 16 10:02 namespace-dev.yaml
-rw-r--r-- 1 candidate candidate 333 Feb 16 10:02 networkpolicy.yaml
-rw-r--r-- 1 candidate candidate 176 Feb 16 10:02 nodeSelect-07.yaml
-rw-r--r-- 1 candidate candidate 210 Feb 16 10:02 pod-kucc-09.yaml
-rw-r--r-- 1 candidate candidate 233 Feb 16 10:02 pv-10.yaml
-rw-r--r-- 1 candidate candidate 195 Feb 16 10:02 pvc-11.yaml
-rw-r--r-- 1 candidate candidate 311 Feb 16 10:02 pvc-pod-11.yaml
candidate@node01:~/k8sYaml$
在vim中复制,可使用 :set paste
命令,要不然格式会乱。
二、学习路线
效率最高 学习路线
<1> 先从百度网盘下载所有资料。
<2> 根据《Windows模拟环境激活方法.pdf》或《苹果MAC模拟环境激活方法.pdf》操作。
<3> 观看”赠送的CKA题库讲解视频“,了解如何做题,学习kubectl -h的使用方法,不用死记硬背命令。
<4> 根据《CKA 1.24 题库(配合模拟环境使用).pdf》,以及在官网搜索关键字的方法,结合视频,在【模拟环境】里实操练习。
所有题目做完后,恢复“CKA初始化”的快照,即可重复练习。
使用模拟环境的时候,笔记本不能睡眠待机、断网,虚拟机不要关机、重启、挂起,这些都可能会导致认证失败(可能)。
不用模拟环境的时候,回退关机状态的快照。
如果你时间比较琐碎,比如做到第5题没时间继续做了,建议直接回退初始化快照。等下次有空了,则从初始化快照开机,接着继续做第6题。
<5> 参考《K8S 考试流程(报名、约考、注意).pdf》,报名、预约考试。
考前可微信联系我,确认近期考试情况,以及是否变题等。
5、
注意:
<1> 每道题会提示你执行相应命令来切换k8s集群(kubectl config use-context xxx),如果没有切换集群,则会导致此题不得分。
<2> 有些题需要ssh到其他机器,或者sudo -i切换到root下,操作完成后,记得exit退回到初始的candidate@node-1或者candidate@node-1终端下。
<3> 考试前30分钟,点击“启动考试”。
<4> 新版考试平台,不能用自己的浏览器书签了。每道题给了几个链接可以参考,或者到K8S官网自己搜关键字。
<5> 考试需要身份证和第二有效证件。第二证件需要有你姓名的拼音,所以第二证件一般就是信用卡或者护照。
<6> yaml文件里的空格是有严格要求的,不要多,不要少,否则创建时会报错。vi编辑文件 先输入 :set paste 转换一下格式 再按 i ,再粘贴。
<7> 考试时,左边是考题,右边是Ubuntu桌面版。左边的考题里的蓝色字体,左键点一下选中,就自动复制了,就可以在右边shell终端里粘贴了。
6、
其他:
默认有两次考试机会,如果运气不好,赶上换新题了,为了给第二次补考留后路,最好将题目和yaml文件拍下来。
可以使用手机,从侧面拍摄电脑屏幕,因为摄像头仅能照到你的的半身照。
然后我可以针对新题,给你再免费做套模拟环境和解题答案。
以及可以根据提供新题的内容价值,提供折扣或者红包50至200不等!
三、真题练习
1、权限控制
命令补全:
source <(kubectl copletion bash)
创建集群角色:
# 查看命令帮助
kubectl create clusterrole -h
Usage:
kubectl create clusterrole NAME --verb=verb --resource=resource.group [--resource-name=resourcename]
[--dry-run=server|client|none] [options]
# 创建集群
# --verb=create 设置权限,创建的权限
# --resource=deployments,statefulsets,daemonsets # 设置资源,必须加s
kubectl create clusterrole deployment-clusterrole --verb=create
查看config配置:
kubectl config view
考题
设置配置环境:
[candidate@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。
答案:
# ①、创建clusterRole
kubectl create clusterrole deployment-clusterrole --verb=create --resource=deployments,statefulsets,daemonsets
# ②、创建 ServiceAccount
kubectl create serviceaccount cicd-token -n app-team1
# ③、绑定
# 注意这里:clusterrolebinding -> rolebinding,之前搞错了,写成 clusterrolebinding 了,也不是 user,而是serviceaccount
# 题目中写了“限于 namespace app-team1 中”,则创建 rolebinding。没有写的话,则创 clusterrolebinding。
# kubectl create clusterrolebinding deployment-clusterrole-binding --clusterrole=deployment-clusterrole --user=cicd-token -n app-team1
Usage:
kubectl create rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname]
[--serviceaccount=namespace:serviceaccountname] [--dry-run=server|client|none] [options]
# 注意,--serviceaccount=app-team1:cicd-token 前边有加命名空间 app-team1:cicd-token
kubectl create rolebinding cicd-token-rolebinding --clusterrole=deployment-clusterrole --serviceaccount=app-team1:cicd-token -n app-team1
# ④、检查
kubectl describe rolebinding cicd-token-rolebinding -n app-team1
2、查看pod的CPU
考题
设置配置环境:
[candidate@node-1] $ kubectl config use-context k8s
Task
通过 pod label name=cpu-loader,找到运行时占用大量 CPU 的 pod,
并将占用 CPU 最高的 pod 名称写入文件 /opt/KUTR000401/KUTR00401.txt(已存在)。
答案:
#Usage:
# kubectl top pod [NAME | -l label] [options]
# ①、根据标签获取占用CPU的pod列表 kubectl top pod -l
kubectl top pod -l name=cpu-loader --sort-by=cpu -A
# ②、输出占用最大量的CPU到pod名称文件
echo "redis-test" > /opt/KUTR000401/KUTR00401.txt
3、配置网络策略NetworkPolicy(重)
考题
设置配置环境:
[candidate@node-1] $ kubectl config use-context hk8s
Task
在现有的 namespace my-app 中创建一个名为 allow-port-from-namespace 的新 NetworkPolicy。
确保新的 NetworkPolicy 允许 namespace echo 中的 Pods 连接到 namespace my-app 中的 Pods 的 9000 端口。
进一步确保新的 NetworkPolicy:
不允许对没有在监听 端口 9000 的 Pods 的访问
不允许非来自 namespace echo 中的 Pods 的访问
解析:
双重否定就是肯定,所以最后两句话的意思就是:
-
仅允许端口为 9000 的 pod 方法。
-
仅允许 echo 命名空间中的 pod 访问。
考点:
NetworkPolicy 的创建
答案
知识点:
Pod 有两种隔离: 出口的隔离和入口的隔离。它们涉及到可以建立哪些连接。 这里的“隔离”不是绝对的,而是意味着“有一些限制”。 另外的,“非隔离方向”意味着在所述方向上没有限制。这两种隔离(或不隔离)是独立声明的, 并且都与从一个 Pod 到另一个 Pod 的连接有关。
要允许从源 Pod 到目的 Pod 的连接,源 Pod 的出口策略和目的 Pod 的入口策略都需要允许连接。 如果任何一方不允许连接,建立连接将会失败。
ingress规则(入口规则):允许外部的pod(三种形式)连接到该隔离pod;
egress规则(出口规则):允许隔离pod链接到 IP 下 5978 TCP 端口的连接;
参考链接:
https://kubernetes.io/zh-cn/docs/concepts/services-networking/network-policies/
策略文件名称:service/networking/networkpolicy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
操作步骤:
# ①、查看所有ns的
kubectl get ns -A
# ②、查看所有ns的标签
kubectl get ns --show-labels
# ③、如果没有打标签,则手动打一个。如果有一个独特的标签label,则也可以直接使用。
kubectl label ns echo project=echo # 给命名空间为echo的打一个标签为 project=echo
# ④、查看官网,拷贝demo进行修改,注意 :set paste 复制,防止yaml文件空格错误
vim networkpolicy-03.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-port-from-namespace-v2
namespace: my-app
spec:
podSelector:
matchLabels: {}
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
project: echo
ports:
- protocol: TCP
port: 9000
# ⑤、执行
kubectl apply -f networkpolicy-03.yaml
# ⑥、检查
kubectl describe networkpolicy -n my-app
4、暴露服务 service
考题
设置配置环境:
[candidate@node-1] $ kubectl config use-context k8s
Task
请重新配置现有的 deployment front-end 以及添加名为 http 的端口规范来公开现有容器 nginx 的端口 80/tcp。 创建一个名为 front-end-svc 的新 service,以公开容器端口 http。
配置此 service,以通过各个 Pod 所在的节点上的 NodePort 来公开他们。
考点:将现有的 deploy 暴露成 nodeport 的 service。
答案
参考链接
https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/deployment/
Pod 中的端口定义是有名字的,你可以在 Service 的 targetPort
属性中引用这些名称。 例如,我们可以通过以下方式将 Service 的 targetPort
绑定到 Pod 端口:
示例:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app.kubernetes.io/name: proxy
spec:
containers:
- name: nginx
image: nginx:stable
ports:
- containerPort: 80
name: http-web-svc
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app.kubernetes.io/name: proxy
ports:
- name: name-of-service-port
protocol: TCP
port: 80
targetPort: http-web-svc
操作
# ①、查看deployment信息,并记录SELECOTOR 的label标签,这里是 app=front-end
> kubectl get deployment front-end -o wide
# ②、更新deployment,添加端口信息
> kubectl edit deployment front-end
# 编辑内容:
spec:
containers:
- image: vicuu/nginx:hello
imagePullPolicy: IfNotPresent
name: nginx
ports: # 添加这行
- containerPort: 80
name: http
protocol: TCP
resources: {}
# ③、暴露对应端口
# Create a service for an nginx deployment, which serves on port 80 and connects to the containers on port 8000
# kubectl expose deployment nginx --port=80 --target-port=8000
# Usage:
# kubectl expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UDP|SCTP] [--target-port=number-or-name] [--name=name] [--external-ip=external-ip-of-service] [--type=type] [options]
kubectl expose deployment front-end --type=NodePort --port=80 --target-port=80 --name=front-end-svc
# ④、检查(正式环境有可能会出现这样的问题)
# 暴露服务后,检查service 标签是否正确,这个要与 deployment 的selector 标签一致的。
kubectl get deployment front-end -o wide
kubectl get svc front-end-svc -o wide
# ⑤、如果暴露服务后,发现 service 的selector标签是空的 <none>,则需要进行编辑此 Service,手动添加标签。
kubectl edit svc front-end-svc
# 加入标签:
spec:
clusterIP: 10.108.131.235
clusterIPs:
- 10.108.131.235
externalTrafficPolicy: Cluster
internalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
ports:
- nodePort: 30846
port: 80
protocol: TCP
targetPort: 80
selector: # 添加
app: front-end # 添加
sessionAffinity: None
type: NodePort
# ⑥、最后curl 检查
kubectl get svc -o wide
curl nodeIP:nodePort
candidate@node01:~/k8sYaml/v2$ curl 11.0.1.112:30846
Hello World ^_^
扩展:
以下是 type: NodePort
服务的一个示例清单,它指定了一个 NodePort 值(在本例中为 30007)。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
type: NodePort
selector:
app.kubernetes.io/name: MyApp
ports:
# 默认情况下,为了方便起见,`targetPort` 被设置为与 `port` 字段相同的值。
- port: 80
targetPort: 80
# 可选字段
# 默认情况下,为了方便起见,Kubernetes 控制平面会从某个范围内分配一个端口号(默认:30000-32767)
nodePort: 30007
5、创建Ingress(修改官网示例)
考题
设置配置环境:
[candidate@node-1] $ kubectl config use-context k8s
Task
如下创建一个新的 nginx Ingress 资源:
名称: ping
Namespace: ing-internal
使用服务端口 5678 在路径 /hello 上公开服务 hello
可以使用以下命令检查服务 hello 的可用性,该命令应返回 hello:
curl -kL <INTERNAL_IP>/hello
答案
Ingress.yaml
# 参考官方ingress demo
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx-example
rules:
- http:
paths:
- path: /testpath
pathType: Prefix
backend:
service:
name: test
port:
number: 80
操作:
# ①、复制官网ingress 示例,进行修改,注意题干,需要加入命名空间
# ②、编辑ingress.yaml 文件
# ③、部署
kubectl apply -f ingress-05.yaml
# ④、验证
# kubectl get ingress -n ing-internal
candidate@node01:~/k8sYaml$ kubectl get ingress -n ing-internal
NAME CLASS HOSTS ADDRESS PORTS AGE
ping-v2 <none> * 80 27s
# 通过以上打印,ingress获取不到IP,需要加上下边这行:
# kubernetes.io/ingress.class: "nginx"
# 添加之后再查看:
candidate@node01:~/k8sYaml$ kubectl get ingress -n ing-internal
NAME CLASS HOSTS ADDRESS PORTS AGE
ping-v2 <none> * 10.109.97.166 80 23m
# ⑤、测试
# curl -kL <INTERNAL_IP>/hello
curl -kL 10.109.97.166/hello
candidate@node01:~/k8sYaml$ curl -kL 10.109.97.166/hello
Hello World ^_^
Ingress-05.yaml文件
candidate@node01:~/k8sYaml/v2$ cat ingress-05.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ping-v2
namespace: ing-internal
annotations:
kubernetes.io/ingress.class: "nginx" # 【注意】1.23以上需要这行,否则ingress 服务获取不到IP
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /hello
pathType: Prefix
backend:
service:
name: hello
port:
number: 5678
6、扩容 deployment 副本数量
考题
设置配置环境:
[candidate@node-1] $ kubectl config use-context k8s
Task
将 deployment presentation 扩展至 4 个 pods
答案
# 参考命令
# kubectl scale deployment -h
# kubectl scale [--resource-version=version] [--current-replicas=count] --replicas=COUNT (-f FILENAME | TYPE NAME)[options]
# ①、查看deployment
kubectl get deployment
# ②、查看pod
kubectl get pods -l app=presentation
root@node01:~# kubectl get pods -l app=presentation
NAME READY STATUS RESTARTS AGE
presentation-5f64bd874c-68z8p 1/1 Running 7 (7m45s ago) 218d
# ③、扩展
kubectl scale deployment presentation --replicas=4
# ④、查看扩展的pod
root@node01:~# kubectl get pods -l app=presentation
NAME READY STATUS RESTARTS AGE
presentation-5f64bd874c-68z8p 1/1 Running 7 (9m14s ago) 218d
presentation-5f64bd874c-6v7sw 1/1 Running 0 6s
presentation-5f64bd874c-6vp8f 1/1 Running 0 6s
presentation-5f64bd874c-98w94 1/1 Running 0 6s
root@node01:~#
candidate@node01:~$ kubectl get deployment presentation -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
presentation 4/4 4 4 218d nginx vicuu/nginx:hello app=presentation
candidate@node01:~$
7、调度pod到指定节点
考题
设置配置环境:
[candidate@node-1] $ kubectl config use-context k8s
Task
按如下要求调度一个 pod: 名称:nginx-kusc00401 Image:nginx
Node selector:disk=ssd
答案
参考
操作
# ①、查看集群节点标签,确保node有这个labe
kubectl get nodes --show-labels | grep 'disk=ssd'
# ②、添加集群节点标签(如果该节点不存在该标签,则需要手动添加)
kubectl label nodes node01 disk=ssd
# ③、检查是否有这个pod,如果没有,则需要创建
kubectl get pods -A | grep nginx-kusc00401
# ④、创建pod(拷贝官网案例,修改pod名称和镜像,删除多余的部分即可)
vim pod-disk-ssd-07.yaml
# ⑤、部署pod
kubectl apply -f pod-disk-ssd-07.yaml
# ⑥、验证pod是否调度到 node1上
> kubectl get pod nginx-kusc00401 -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-kusc00401 1/1 Running 0 3m25s 10.244.196.178 node01 <none> <none>
官网案例:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
修改后的:
pod-disk-ssd-07.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-kusc00401
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disk: ssd
8、查看可用节点数量
考题
设置配置环境:
[candidate@node-1] $ kubectl config use-context k8s
Task
检查有多少 nodes 已准备就绪(不包括被打上 Taint:NoSchedule 的节点),
并将数量写入 /opt/KUSC00402/kusc00402.txt
考点:检查节点角色标签,状态属性,污点属性的使用
答题
# ①、通过kubectl describe nodes 获取节点详细信息,然后再过滤出有污点的
candidate@node01:~/k8sYaml$ kubectl describe nodes | grep -i Taints
Taints: node-role.kubernetes.io/control-plane:NoSchedule
Taints: <none>
Taints: <none>
candidate@node01:~/k8sYaml$
# 可以看出master有 NoScheduler,2个node节点没有
# 参数说明: gerp 的 -i是忽略大小写,grep -v 是排除在外, grep -c 是统计查出来的条数
kubectl describe nodes | grep -i Taints | grep -vc NoSchedule
# ②、输出到文件
echo 2 > /opt/KUSC00402/kusc00402.txt
9、创建多容器的pod
考题
设置配置环境:
[candidate@node-1] $ kubectl config use-context k8s
Task
按如下要求调度一个 Pod: 名称:kucc8
app containers: 2
container 名称/images:
nginx
consul
答案
# ①、参考官网示例,编写pod yaml示例
vim pod-kucc8-09.yaml
# ②、部署
kubectl apply -f pod-kucc8-09.yaml
# ③、验证pod
kubectl get pod kucc8
candidate@node01:~/k8sYaml$ kubectl get pod kucc8
NAME READY STATUS RESTARTS AGE
kucc8 2/2 Running 0 33m
candidate@node01:~/k8sYaml$ vim pod-kucc8-09.yaml
apiVersion: v1
kind: Pod
metadata:
name: kucc8
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
- name: consul
image: consul
imagePullPolicy: IfNotPresent
10、创建PV
考题
设置配置环境:
[candidate@node-1] $ kubectl config use-context hk8s
Task
创建名为 app-config 的 persistent volume,容量为 1Gi,访问模式为 ReadWriteMany。
volume 类型为 hostPath,位于 /srv/app-config
答案
# ①、解题思路,直接参考官网 存储卷 hostPath 配置示例,进行修改
# https://kubernetes.io/zh-cn/docs/concepts/storage/persistent-volumes/
# https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/configure-persistent-volume-storage/
# ②、根据官网示例进行修改
vim pv-10.yaml
# ③、创建
kubectl apply -f pv-10.yaml
# ④、检查
candidate@node01:~/k8sYaml$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
app-config 1Gi RWX Retain Available 2m27s
pv01 10Mi RWO Retain Available csi-hostpath-sc 218d
candidate@node01:~/k8sYaml$
pv-10.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: app-config
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
hostPath:
path: "/srv/app-config"
扩展
卷(Volume)
Kubernetes 支持很多类型的卷。 Pod 可以同时使用任意数目的卷类型。 临时卷类型的生命周期与 Pod 相同,但持久卷可以比 Pod 的存活期长。 当 Pod 不再存在时,Kubernetes 也会销毁临时卷;不过 Kubernetes 不会销毁持久卷。 对于给定 Pod 中任何类型的卷,在容器重启期间数据都不会丢失。
使用卷时, 在 .spec.volumes
字段中设置为 Pod 提供的卷,并在 .spec.containers[*].volumeMounts
字段中声明卷在容器中的挂载位置。 容器中的进程看到的文件系统视图是由它们的容器镜像 的初始内容以及挂载在容器中的卷(如果定义了的话)所组成的。 其中根文件系统同容器镜像的内容相吻合。 任何在该文件系统下的写入操作,如果被允许的话,都会影响接下来容器中进程访问文件系统时所看到的内容。
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: registry.k8s.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
# 宿主上目录位置
path: /data
# 此字段为可选
type: Directory
持久卷(PV)
持久卷(PersistentVolume,PV) 是集群中的一块存储,可以由管理员事先制备, 或者使用存储类(Storage Class)来动态制备。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样, 也是使用卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。
11、创建PVC
考题
设置配置环境:
[candidate@node-1] $ kubectl config use-context ok8s
Task
创建一个新的 PersistentVolumeClaim: 名称: pv-volume
Class: csi-hostpath-sc
容量: 10Mi
创建一个新的 Pod,来将 PersistentVolumeClaim 作为 volume 进行挂载:
名称:web-server
Image:nginx:1.16
挂载路径:/usr/share/nginx/html
配置新的 Pod,以对 volume 具有 ReadWriteOnce 权限。
最后,使用 kubectl edit 或 kubectl patch 将 PersistentVolumeClaim 的容量扩展为 70Mi,并记录此更改。
考点: pvc 的创建 class 属性的使用,--record 记录变更
答案
# ①、参考官方示例,创建 pvc
# https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/configure-persistent-volume-storage/
# 新建pvc-10.yaml文件
candidate@node01:~/k8sYaml$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
app-config 1Gi RWX Retain Available 2m27s
pv01 10Mi RWO Retain Available csi-hostpath-sc 218d
candidate@node01:~/k8sYaml$ vim pvc-11.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pv-volume-claim
spec:
# 这个PV 官方已经建好了,可参考上述PV打印,访问模式为 RWO,STORAGECLASS 为 csi-hostpath-sc,所以这里不需要自己再建PV
storageClassName: csi-hostpath-sc
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Mi
kubectl apply -f pvc-11.yaml
# ②、检查pvc
candidate@node01:~/k8sYaml$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pv-volume-claim Bound pv01 10Mi RWO csi-hostpath-sc 5m12s
# ③、创建pod,关联pvc
vim pvc-pod-11.yaml
# ④、创建
kubectl apply -f pvc-pod-11.yaml
# ⑤、检查pod
candidate@node01:~/k8sYaml$ kubectl get pod web-server
NAME READY STATUS RESTARTS AGE
web-server 1/1 Running 0 10m
# ⑥、更改pvc大小,并记录过程。
# 模拟环境是 nfs 存储,操作时,会有报错忽略即可。考试时用的动态存储,不会报错的。
kubectl edit pvc pv-volume-claim --record
pvc-11.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pv-volume-claim
spec:
storageClassName: csi-hostpath-sc
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Mi
pvc-pod-11.yaml
apiVersion: v1
kind: Pod
metadata:
name: web-server
spec:
volumes:
- name: pv-storage
persistentVolumeClaim:
claimName: pv-volume-claim
containers:
- name: pvc-container
image: nginx:1.16
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: pv-storage
12、查看pod日志
考题
设置配置环境:
[candidate@node-1] $ kubectl config use-context k8s
Task
监控 pod foo 的日志并:
提取与错误 RLIMIT_NOFILE 相对应的日志行
将这些日志行写入 /opt/KUTR00101/foo
考点:kubectl logs 命令
答案
# ①、查看 pod foo,确认该pod是否存在
kubectl get pods
# ②、记录
kubectl logs foo | grep "RLIMIT_NOFILE" > /opt/KUTR00101/foo
# ③、检查
candidate@node01:~/k8sYaml$ cat /opt/KUTR00101/foo
2023/02/21 03:16:26 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
13、使用sidecar代理容器日志
考题
设置配置环境:
[candidate@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 以外,请勿更改现有容器的规格。
考题翻译成白话,就是:
添加一个名为 sidecar 的边车容器(使用 busybox 镜像),加到已有的 pod 11-factor-app 中。
确保 sidecar 容器能够输出 /var/log/11-factor-app.log 的信息。
使用 volume 挂载 /var/log 目录,确保 sidecar 能访问 11-factor-app.log 文件
答案
# ①、查看pod是否存在
kubectl get pod 11-factor-app
# ②、导出这个 pod 的yaml文件
kubectl get pod 11-factor-app -o yaml > varlog-13.yaml
# ③、备份yaml文件,防止改错了,回退
cp varlog-13.yaml varlog-13-bak.yaml
# ④、修改 varlog-13.yaml 文件
vim varlog.yaml # (完整请看后边)
# ⑤、删除原先的pod
kubectl delete pod 11-factor-app
# ⑥、查看删除
kubectl get pod 11-factor-app
# ⑦、新建pod
kubectl apply -f varlog-13.yaml
# ⑧、检查
candidate@node01:~/k8sYaml$ kubectl get pod 11-factor-app
NAME READY STATUS RESTARTS AGE
11-factor-app 2/2 Running 0 92s
# ⑨、检查边车
kubectl logs 11-factor-app sidecar
# kubectl exec 11-factor-app -c sidecar -- tail -f /var/log/11-factor-app.log
# kubectl exec 11-factor-app -c count -- tail -f /var/log/11-factor-app.log
varlog-13.yaml
candidate@node01:~/k8sYaml$ cat varlog-13.yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
cni.projectcalico.org/containerID: 7012305bd7cd526854df8779fac2460e18e7006b99fbc3272270d5c1fdb8defd
cni.projectcalico.org/podIP: 10.244.196.175/32
cni.projectcalico.org/podIPs: 10.244.196.175/32
creationTimestamp: "2022-07-17T10:25:09Z"
name: 11-factor-app
namespace: default
resourceVersion: "67724"
uid: cc165dff-c835-47de-8b03-2d9a59ab8028
spec:
containers:
- args:
- /bin/sh
- -c
- |
i=0; while true; do
echo "$(date) INFO $i" >> /var/log/11-factor-app.log;
i=$((i+1));
sleep 1;
done
image: busybox
imagePullPolicy: IfNotPresent
name: count
resources: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: kube-api-access-7m2k4
readOnly: true
- name: varlog # 新加
mountPath: /var/log # 新加
- name: sidecar # 新加
image: busybox # 新加
args: [/bin/sh, -c, 'tail -n+1 -f /var/log/11-factor-app.log'] # 新加
volumeMounts: # 新加
- name: varlog # 新加
mountPath: /var/log # 新加
dnsPolicy: ClusterFirst
enableServiceLinks: true
nodeName: node01
preemptionPolicy: PreemptLowerPriority
priority: 0
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
volumes: # 新加
- name: varlog # 新加
emptyDir: {} # 新加
- name: kube-api-access-7m2k4
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
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2022-07-17T10:25:09Z"
status: "True"
type: Initialized
- lastProbeTime: null
lastTransitionTime: "2023-02-21T03:15:23Z"
status: "True"
type: Ready
- lastProbeTime: null
lastTransitionTime: "2023-02-21T03:15:23Z"
status: "True"
type: ContainersReady
- lastProbeTime: null
lastTransitionTime: "2022-07-17T10:25:09Z"
status: "True"
type: PodScheduled
containerStatuses:
- containerID: containerd://ed4f3790c180bc98064e64582451a629c15a806a80e342c7f2829980a3547bc6
image: docker.io/library/busybox:latest
imageID: sha256:62aedd01bd8520c43d06b09f7a0f67ba9720bdc04631a8242c65ea995f3ecac8
lastState:
terminated:
containerID: containerd://0d7c9f4c0be1c2360b470e9644b550e9153807d7487a7c38df9acc83969b745b
exitCode: 255
finishedAt: "2023-02-21T03:14:24Z"
reason: Unknown
startedAt: "2022-08-26T07:19:27Z"
name: count
ready: true
restartCount: 7
started: true
state:
running:
startedAt: "2023-02-21T03:15:23Z"
hostIP: 11.0.1.112
phase: Running
podIP: 10.244.196.175
podIPs:
- ip: 10.244.196.175
qosClass: BestEffort
startTime: "2022-07-17T10:25:09Z"
candidate@node01:~/k8sYaml$
14、升级集群
考题
设置配置环境:
[candidate@node-1] $ kubectl config use-context mk8s
Task
现有的 Kubernetes 集群正在运行版本 1.24.2。仅将 master 节点上的所有 Kubernetes 控制平面和节点组件升级到版本 1.24.3。
确保在升级之前 drain master 节点,并在升级后 uncordon master 节点。
可以使用以下命令,通过 ssh 连接到 master 节点:
ssh master01
可以使用以下命令,在该 master 节点上获取更高权限: sudo -i
另外,在主节点上升级 kubelet 和 kubectl。
请不要升级工作节点,etcd,container 管理器,CNI 插件, DNS 服务或任何其他插件。
答案
# ①、理清思路,需要搞清楚升级步骤,需要升级哪些组件,参考官网哪一章节
# ②、查看集群节点
kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01 Ready control-plane 222d v1.24.2
node01 Ready <none> 222d v1.24.2
node02 Ready <none> 222d v1.24.2
# cordon 停止调度,将 node 调为 SchedulingDisabled。新 pod 不会被调度到该 node,但在该 node 的旧 pod 不受影响。
# drain 驱逐节点。首先,驱逐该 node 上的 pod,并在其他节点重新创建。接着,将节点调为 SchedulingDisabled。
# 所以 kubectl cordon master01 这条,可写可不写。但我一向做事严谨,能复杂,就绝不简单了事。所以就写了。
# ③、停止调度cordon
kubectl cordon master01
# ④、将节点标记为不可调度并驱逐所有负载,准备节点的维护
# 参考官网命令:https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade/
kubectl drain master01 --ignore-daemonsets
# kubectl get nodes
root@master01:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01 Ready,SchedulingDisabled control-plane 222d v1.24.2
node01 Ready <none> 222d v1.24.2
node02 Ready <none> 222d v1.24.2
# ⑤、ssh到master01节点,切换到root账号
ssh master01
sudo -i
# ⑥、查看是否有更新资源,然后进行更新
apt-get update
> apt-cache show kubeadm | grep 1.24.3
Version: 1.24.3-00
Filename: pool/kubeadm_1.24.3-00_amd64_a185bea971069e698ed5104545741e561a7c629ebb5587aabc0b2abc9bf79af7.deb
# 7.1 安装kubeadm,再进行更新
apt-get install kubeadm=1.24.3-00
# 7.2 查看升级后的kubeadm版本号
kubeadm version
# 7.3 验证升级计划,此命令检查你的集群是否可被升级,并取回你要升级的目标版本。 命令也会显示一个包含组件配置版本状态的表格。
# 记住:在kubeadm 新版安装后执行此命令
kubeadm upgrade plan
# 7.4 排除etcd,升级其他的,提示时,输入y
kubeadm upgrade apply v1.24.3 --etcd-upgrade=false
# ⑧、升级kubelet
apt-get install -y kubelet=1.24.3-00
kubelet version
# ⑨、升级kubectl
apt-get install -y kubectl=1.24.3-00
kubectl version
# ⑩、退出master,退回到 node01,这里输入两个 exit
root@master01:~# exit
logout
candidate@master01:~$ exit
logout
Connection to master01 closed.
candidate@node01:~$
# 11、恢复 master01 的调度
kubectl uncordon master01
# 12、检查
candidate@node01:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01 Ready,SchedulingDisabled control-plane 222d v1.24.3
node01 Ready <none> 222d v1.24.2
node02 Ready <none> 222d v1.24.2
candidate@node01:~$ kubectl uncordon master01
node/master01 uncordoned
candidate@node01:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01 Ready control-plane 222d v1.24.3
node01 Ready <none> 222d v1.24.2
node02 Ready <none> 222d v1.24.2
candidate@node01:~$
15、备份还原etcd
考题
设置配置环境
此项目无需更改配置环境。但是,在执行此项目之前,请确保您已返回初始节点。
[candidate@master01] $ exit #注意,这个之前是在 master01 上,所以要 exit 退到 node01,如果已经是 node01 了,就不要再 exit 了。
Task
首先,为运行在 https://11.0.1.111:2379 上的现有 etcd 实例创建快照并将快照保存到 /var/lib/backup/etcd-snapshot.db (注意,真实考试中,这里写的是 https://127.0.0.1:2379)
为给定实例创建快照预计能在几秒钟内完成。 如果该操作似乎挂起,则命令可能有问题。用 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
答案
# ①、查看官方文档,熟悉相关命令,如 ETCDCTL_API=3, etcdctl -h 等;
ETCDCTL_API=3 etcdctl -h
# 列出 etcdctl 可用的各种选项。例如,你可以通过指定端点、证书等来制作快照,如下所示:
# ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
# --cacert=<trusted-ca-file> --cert=<cert-file> --key=<key-file> \
# snapshot save <backup-file-location>
# ②、设置(导出)系统环境变量
export ETCDCTL_API=3
# ③、备份快照,https://11.0.1.111:2379 为master 节点IP
etcdctl --endpoints=https://11.0.1.111: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
# ④、检查快照(非必须)
> etcdctl snapshot status /var/lib/backup/etcd-snapshot.db -wtable
Deprecated: Use `etcdutl snapshot status` instead.
+----------+----------+------------+------------+
| HASH | REVISION | TOTAL KEYS | TOTAL SIZE |
+----------+----------+------------+------------+
| 7fcee8f3 | 73156 | 2586 | 16 MB |
+----------+----------+------------+------------+
# ⑤、还原,注意:这里还原的非刚才上边导出来的快照,是官方提供的快照
# ETCDCTL_API=3 etcdctl --endpoints 10.2.0.9:2379 snapshot restore snapshotdb # 示例
# 根据题目,查看要还原的快照文件
# ls -l /data/backup/etcd-snapshot-previous.db
# 需要加证书及认证(需要加sudo权限)
sudo ETCDCTL_API=3 etcdctl --endpoints=https://11.0.1.111: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
16、排查集群中故障节点
考题
设置配置环境:
[candidate@node-1] $ kubectl config use-context wk8s
Task
名为 node02 的 Kubernetes worker node 处于 NotReady 状态。
调查发生这种情况的原因,并采取相应的措施将 node 恢复为 Ready 状态,确保所做的任何更改永久生效。
可以使用以下命令,通过 ssh 连接到 node02 节点:
ssh node02
可以使用以下命令,在该节点上获取更高权限:
sudo -i
说明:没必要参考网址,记住先 restart 再 enable 就行。
答案:
# ①、查看集群节点状态,通过 get nodes 查看异常节点,登录节点查看 kubelet 等组件的 status 并判断原因。 真实考试时,这个异常节点的 kubelet 服务没有启动导致的,就这么简单。
> kubectl get nodes
AME STATUS ROLES AGE VERSION
master01 Ready control-plane 222d v1.24.2
node01 Ready <none> 222d v1.24.2
node02 Ready <none> 222d v1.24.2
# ②、制造node02异常(考试时不需要,那个node就是异常的)
# 在 candidate@node01 上执行,执行完 a.sh 脚本后,等 3 分钟,node02 才会挂掉。
sh /opt/sh/a.sh
# ③、查看节点状态
candidate@node01:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01 Ready control-plane 222d v1.24.2
node01 Ready <none> 222d v1.24.2
node02 NotReady <none> 222d v1.24.2 【挂掉了】
# ④、确定是node02挂了,切换到 node2节点
ssh node02
sudo -i
# ⑤、查看 kubelet组件状态
systemctl status kubelet
# ⑥、启动服务,并设置为开机启动
systemctl start kubelet
systemctl enable kubelet
# ⑦、查看状态
> systemctl status kubelet
> kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01 Ready control-plane 222d v1.24.2
node01 Ready <none> 222d v1.24.2
node02 Ready <none> 222d v1.24.2
17、节点维护
考题
设置配置环境:
[candidate@node-1] $ kubectl config use-context ek8s
Task
将名为 node02 的 node 设置为不可用,并重新调度该 node 上所有运行的 pods。
考点: cordon 和 drain 命令的使用
答案
# ①、查看节点
> kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01 Ready control-plane 222d v1.24.2
node01 Ready <none> 222d v1.24.2
node02 Ready <none> 222d v1.24.2
# ②、将node02设置为不可用
kubectl cordon node02
# ③、查看状态
candidate@node01:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01 Ready control-plane 222d v1.24.2
node01 Ready <none> 222d v1.24.2
node02 Ready,SchedulingDisabled <none> 222d v1.24.2
# ④、驱逐节点
kubectl drain node02 --ignore-daemonsets
# 但如果执行后,有跟测试环境一样的报错(如下截图),则需要加上--delete-emptydir-data --force,会强制将 pod 移除。
# kubectl drain node02 --ignore-daemonsets --delete-emptydir-data --force
# ⑤、检查
kubectl get node
kubectl get pods -A -o wide | grep node02
# 正常已经没有 pod 在 node02 上了。但测试环境里的 ingress、flannel、kube-proxy 是 daemonsets 模式的,所以显示还在 node02 上,忽略即可。
18、yaml格式说明
相关文章:
k8s官方文档
为者常成,行者常至
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)