每次还原初始化快照后,开机后等5分钟,ssh登录node01(11.0.1.112)检查一下所有的pod,确保都为Running,再开始练习。
kubectl get pod -A
设置配置环境:
[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。
考点:RBAC授权模型的理解。
没必要参考网址,使用-h帮助更方便。
kubectl create clusterrole -h
kubectl create rolebinding -h
kubectl create clusterrole deployment-clusterrole --verb=create --resource=deployments,statefulsets,daemonsets
kubectl -n app-team1 create serviceaccount cicd-token
# 题目中写了“限于namespace app-team1中”,则创建rolebinding。没有写的话,则创建clusterrolebinding。
kubectl -n app-team1 create rolebinding cicd-token-rolebinding --clusterrole=deployment-clusterrole --serviceaccount=app-team1:cicd-token
# rolebinding后面的名字cicd-token-rolebinding随便起的,因为题目中没有要求,如果题目中有要求,就不能随便起了。
检查(考试时,可以不检查的)
kubectl -n app-team1 describe rolebinding cicd-token-rolebinding
设置配置环境:
[candidate@node-1] $ kubectl config use-context k8s
Task
通过 pod label name=cpu-loader,找到运行时占用大量 CPU 的 pod,
并将占用 CPU 最高的 pod 名称写入文件 /opt/KUTR000401/KUTR00401.txt(已存在)。
考点:kubectl top --l 命令的使用
没必要参考网址,使用-h帮助更方便。
kubectl top pod -h
考试时务必执行,切换集群。模拟环境中不需要执行。
# 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
设置配置环境:
[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 的创建
参考官方文档,拷贝yaml文件内容,并修改。
这里要注意,模拟题和真题截图里都有提到echo这个namespace,但是和真题的截图比较,你会发现,两个echo出现的位置不同,一个作为访问者,一个作为
被访问者。
所以不要搞混了。他们其实只是个名字而已,叫什么都无所谓,但要分清访问和被访问。
podSelector:每个 NetworkPolicy 都包括一个 podSelector
, 它对该策略所适用的一组 Pod 进行选择。示例中的策略选择带有 " role (作用) =db" 标签的 Pod。 空的 podSelector
选择名字空间下的所有 Pod。
开始操作
查看所有ns的标签label
kubectl get ns --show-labels
如果访问者的namespace没有标签label,则需要手动打一个。如果有一个独特的标签label,则也可以直接使用。
kubectl label ns echo project=echo
编写一个yaml文件
vim networkpolicy.yaml
#注意 :set paste,防止yaml文件空格错序。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-port-from-namespace
namespace: my-app
spec:
podSelector:
matchLabels: {}
policyTypes:
- Ingress
ingress:
- from:
- namespaceSelector:
matchLabels:
project: echo
ports:
- protocol: TCP
port: 9000
检查
kubectl describe networkpolicy -n my-app
设置配置环境:
[candidate@node-1] $ kubectl config use-context k8s
Task
请重新配置现有的deployment front-end 以及添加名为http的端口规范来公开现有容器 nginx 的端口80/tcp。
创建一个名为front-end-svc的新service,以公开容器端口http。
配置此service,以通过各个Pod所在的节点上的 NodePort 来公开他们。
# kubectl config use-context k8s
开始操作
检查deployment信息,并记录SELECTOR的Lable标签,这里是app=front-end
kubectl get deployment front-end -o wide
参考官方文档,按照需要edit deployment,添加端口信息
kubectl edit deployment front-end
#注意 :set paste,防止yaml文件空格错序。
spec:
containers:
- image: vicuu/nginx:hello
imagePullPolicy: IfNotPresent
name: nginx #找到此位置。下文会简单说明一下yaml文件的格式,不懂yaml格式的,往下看。
ports: #添加这4行
- name: http
containerPort: 80
protocol: TCP
暴露对应端口
kubectl expose deployment front-end --type=NodePort --port=80 --target-port=80 --name=front-end-svc
#注意考试中需要创建的是NodePort,还是ClusterIP。如果是ClusterIP,则应为--type=ClusterIP
#--port是service的端口号,--target-port是deployment里pod的容器的端口号。
暴露服务后,检查一下service的selector标签是否正确,这个要与deployment的selector标签一致的。
kubectl get svc front-end-svc -o wide
kubectl get deployment front-end -o wide
设置配置环境:
[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
vim ingress.yaml
#注意 :set paste,防止yaml文件空格错序。
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
labels:
app.kubernetes.io/component: controller
name: nginx-example
annotations:
ingressclass.kubernetes.io/is-default-class: "true"
spec:
controller: k8s.io/ingress-nginx
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ping
namespace: front-end
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx-example #这里调用上面新建的ingressClassName 为nginx-example
rules:
- http:
paths:
- path: /hello
pathType: Prefix
backend:
service:
name: hello
port:
number: 80
最后curl检查
通过get ingress 查看ingress 的内外IP,然后通过提供的 curl 测试 ingress 是否正确。
另一种方法
kubectl create ingress ping --rule=/hello=hello:5678 --class=nginx --annotation=nginx.ingress.kubernetes.io/rewrite-target=/ -n ing-internal
设置配置环境:
[candidate@node-1] $ kubectl config use-context k8s
Task
将 deployment presentation 扩展至 4个 pods
kubectl scale deployment -h
先检查一下现有的pod数量(可不检查)
kubectl get deployments presentation -o wide
kubectl get pod -l app=presentation
扩展成4个
kubectl scale deployment presentation --replicas=4
设置配置环境:
[candidate@node-1] $ kubectl config use-context k8s
Task
按如下要求调度一个 pod:
名称:nginx-kusc00401
Image:nginx
Node selector:disk=ssd
考点:nodeSelect属性的使用
开始操作
先检查一个是否有这个pod,应该是没有创建的,所以需要创建
kubectl get pod -A|grep nginx-kusc00401
# 确保node有这个labels,考试时,检查一下就行,应该已经提前设置好了labels。
kubectl get nodes --show-labels|grep 'disk=ssd'
node02 添加标签
kubectl label nodes node02 disk=ssd
cat pod_nginx_ssd.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: app
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disk: ssd
kubectl get pod nginx -o wide
[candidate@node-1] $ kubectl config use-context k8s
Task
检查有多少 nodes 已准备就绪(不包括被打上 Taint:NoSchedule 的节点),
并将数量写入 /opt/KUSC00402/kusc00402.txt
考点:检查节点角色标签,状态属性,污点属性的使用
kubectl -h
# grep的-i 是忽略大小写,grep -v是排除在外,grep -c是统计查出来的条数。
kubectl describe nodes | grep -i Taints | grep -vc NoSchedule
echo "查出来的数字" > /opt/KUSC00402/kusc00402.txt
其实你直接使用如下命令,就能一眼看出来,几个没有的。
kubectl describe nodes | grep -i Taints
设置配置环境:
[candidate@node-1] $ kubectl config use-context k8s
Task
按如下要求调度一个Pod:
名称:kucc8
app containers: 2
container 名称/images:
⚫ nginx
⚫ consul
# kubectl config use-context k8s
可以参考上一题“调度pod到指定节点”的yaml配置文件。
开始操作
vim pod-kucc.yaml
#注意 :set paste,防止yaml文件空格错序。
apiVersion: v1
kind: Pod
metadata:
name: nginx-consul
labels:
env: app
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
- name: consul
image: consul
imagePullPolicy: IfNotPresent
kubectl get pod nginx-consul
Task
创建名为 app-config 的 persistent volume,容量为 1Gi,访问模式为 ReadWriteMany。
volume 类型为 hostPath,位于 /srv/app-config
考点:hostPath类型的pv
https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/configure-persistent-volume-storage/
直接从官方复制合适的案例,修改参数,然后设置 hostPath 为 /srv/app-config 即可。
开始操作
vim pv.yaml
#注意 :set paste,防止yaml文件空格错序。
[root@bt cka]# cat pv_config_app.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: app-config
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
hostPath:
path: "/srv/app-config"
kubectl get pv
# RWX是ReadWriteMany,RWO是ReadWriteOnce。
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配置,修改参数,不确定的地方就是用 kubectl 的 explain 帮助。
开始操作
vim pvc.yaml
#注意 :set paste,防止yaml文件空格错序。
[root@bt cka]# cat pvc_storgae.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pv-volume
spec:
storageClassName: nfs-client
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Mi
创建PVC
kubectl apply -f pvc.yaml
检查
kubectl get pvc
vim pvc-pod.yaml
#注意 :set paste,防止yaml文件空格错序
apiVersion: v1
kind: Pod
metadata:
name: web-server
spec:
volumes:
- name: task-pv-storage #绿色的两个name要一样。
persistentVolumeClaim:
claimName: pv-volume #这个要使用上面创建的pvc名字
containers:
- name: nginx
image: nginx:1.16
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: task-pv-storage #绿色的两个name要一样。
创建
kubectl apply -f pvc-pod.yaml
检查
kubectl get pod web-server
改大小,并记录过程。
# 将storage: 10Mi改为storage: 70Mi (模拟环境里会报错,下面有解释。)
# 注意是修改上面的spec:里面的storage:
kubectl edit pvc pv-volume --record
#模拟环境是nfs存储,操作时,会有报错忽略即可。考试时用的动态存储,不会报错的。
模拟环境使用的是nfs做后端存储,是不支持动态扩容pvc的(:wq保存退出时,会报错)。
所以最后一步修改为70Mi,只是操作一下即可。换成ceph做后端存储,可以,但是集群资源太少,无法做ceph。
[candidate@node-1] $ kubectl config use-context k8s
Task
监控 pod foo 的日志并:
提取与错误 RLIMIT_NOFILE相对应的日志行
将这些日志行写入 /opt/KUTR00101/foo
考点:kubectl logs命令
kubectl logs foo | grep "RLIMIT_NOFILE" > /opt/KUTR00101/foo
检查
cat /opt/KUTR00101/foo
[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两个容器共享存储卷
https://kubernetes.io/zh-cn/docs/concepts/cluster-administration/logging/
通过 kubectl get pod -o yaml 的方法备份原始 pod 信息,删除旧的pod 11-factor-app
copy 一份新 yaml 文件,添加 一个名称为 sidecar 的容器
新建 emptyDir 的卷,确保两个容器都挂载了 /var/log 目录
新建含有 sidecar 的 pod,并通过 kubectl logs 验证
apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: leagcy-app
image: busybox
args:
- /bin/sh
- -c
- >
i=0;
while true;
do
echo "$i: $(date)" >> /var/log/legacy-app.log;
i=$((i+1));
sleep 1;
done
volumeMounts:
- name: varlog
mountPath: /var/log
- name: sidecar
image: busybox
args: [/bin/sh, -c, 'tail -n+1 -F /var/log/legacy-app.log']
volumeMounts:
- name: varlog
mountPath: /var/log
volumes:
- name: varlog
emptyDir: {}
验证:
kubectl exec counter-log -c sidecar -- tail -f /var/log/legacy-app.log
Task
现有的Kubernetes 集群正在运行版本1.25.1。仅将master节点上的所有 Kubernetes控制平面和节点组件升级到版本1.25.2。
确保在升级之前 drain master节点,并在升级后 uncordon master节点。
可以使用以下命令,通过ssh连接到master节点:
ssh master01
可以使用以下命令,在该master节点上获取更高权限:
sudo -i
另外,在主节点上升级kubelet和kubectl。
请不要升级工作节点,etcd,container 管理器,CNI插件, DNS服务或任何其他插件。
(注意,考试敲命令时,注意要升级的版本,根据题目要求输入具体的升级版本!!!)
考点:如何离线主机,并升级控制面板和升级节点
1、切换环境
kubectl config use-context mk8s
2、配置
#升级kueadm
kubectl cordon master01
kubectl drain mk8s-master-0 --ignore=daemonsets
连接master机器 提权
ssh mk8s-master-0
sudo -i
升级kubeadm
apt-get update
apt-cache show kubeadm|grep 1.25.2
apt install kubeadm=1.25.2 -y
kubeadm upgrade plan
#这里可以先查下的:apt-cache show|grep kubeadm
#kubeadm upgrade install v1.20.1 #。。。淦,这个写错了。。。。。。。是apply,并且要加上--ectd-ugrade=false。。。。。。题目要求不升级 etcd; 注意下这2个版本号写法的区别。。。。
kubeadm upgrade apply v1.20.1 --etcd-upgrade=false
#升级kubelt 和 kubectl
apt install kubelet=1.20.1-00 kubectl=1.20.1-00 -y
systemctl restart kubelet #这里要重启下kubelt的,切记。。。
exit
exit
kubectl uncordon mk8s-master-0
3、验证
kubectl get node -owide
kubectl --version
kubelet --version
此项目无需更改配置环境。但是,在执行此项目之前,请确保您已返回初始节点。
[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
考点:etcd的备份和还原命令
# 备份
ETCDCTL_API=3 etcdctl snapshot save /data/backup/etcd-snapshot.db --endpoints=https://127.0.0.1:2379 --cacert=/opt/KUIN00601/ca.crt --cert=/opt/KUIN00601/etcd-client.crt --key=/opt/KUIN00601/etcd-client.key
# 恢复
systemctl stop etcd
systemctl cat etcd # 确认下数据目录(--data-dir值)
mv /var/lib/etcd /var/lib/etcd.bak
ETCDCTL_API=3 etcdctl snapshot restore /data/backup/etcd-snapshot-previous.db --data-dir=/var/lib/etcd
chown -R etcd:etcd /var/lib/etcd
systemctl start etcd
名为node02的Kubernetes worker node处于NotReady状态。
调查发生这种情况的原因,并采取相应的措施将node恢复为Ready状态,确保所做的任何更改永久生效。
可以使用以下命令,通过ssh连接到node02节点:
ssh node02
可以使用以下命令,在该节点上获取更高权限:
sudo -i
过 get nodes 查看异常节点,登录节点查看 kubelet 等组件的 status 并判断原因。
真实考试时,这个异常节点的kubelet服务没有启动导致的,就这么简单。
执行初始化这道题的脚本a.sh,模拟node02异常。
(考试时,不需要执行的!考试时切到这道题的集群后,那个node就是异常的。)
1、切换环境
kubectl config use-context wk8s #考试时切到这道题的集群后,那个 node 就是异常的。 真实考试时,这个异常节点的 kubelet 服务没有启动导致的,就这么简单。
2、配置
kubectl get node #查看Not Ready的node节点
ssh wk8s-node-0
sudo -i
systemctl status kubelet
systemctl start kubelet
systemctl enable kubelet
exit #退出root用户
exit #退出故障节点
3、验证
kubectl get node
#jounarlctl -u kubelet 查看kubelet日志
Task
将名为 node02 的 node 设置为不可用,并重新调度该 node 上所有运行的 pods。
考点:cordon和drain 命令的使用
1、切换环境
kubectl config use-context ek8s
2、配置
kubectl cordon ek8s-node-1 #设置次节点为不可调度s
kubectl drain ek8s-node-1 --ignore-daemonsets #设置次节点为不可调度,并且排空次节点
#如果上面命令报错就加上一个 --delete-local-data --force
kubectl drain ek8s-node-1 --ignore-daemonsets --delete-local-data --force
kubectl drain ek8s-node-1 --ignore-daemonsets --delete-emptydir-data --force
3、验证
kubectl get node