首页 > 数据库 > 数据库开发技术 > Kubernetes CKA 证书备考笔记
绝大部分题都是有在 minikube 的环境上操作过,只有部分比如升级集群受限于环境问题没有实地操作。
1.保存常用文档进书签,如果有 Alfred 启用浏览器书签 workflow。效果见下图2.kubectl 自动补全 echo "source <(kubectl completion bash)" >> ~/.bashrc; source ~/.bashrc3.每道题开始前要切换 context 和 namespace,直接复制题目里的命令即可4.必要的 alias5.善用 --dry-run=client -o yaml 避免手动敲太多6.善用 kubectl explain [resource[.field]]7.看懂题目最重要,输出正确的结果更重要(重要的事讲三遍)8.看懂题目最重要,输出正确的结果更重要(重要的事讲三遍)9.看懂题目最重要,输出正确的结果更重要(重要的事讲三遍)
书签地址:K8s-CKA-CAKD-Bookmarks.html[1]
在默认命名空间中创建一个名为 dev-sa 的服务帐户,dev-sa 可以在 dev 命名空间中创建以下组件:
Deployment、StatefulSet、DaemonSet
•role•sa•rolebinding•auth can-i
参考文档: https://kubernetes.io/docs/reference/access-authn-authz/rbac/#command-line-utilities
$ kubectl create sa dev-sa$ kubectl create role dev-role --verb=create --resource=deployment,statefulset,daemonset#检查$ kubectl describe role dev-roleName: dev-roleLabels: <none>Annotations: <none>PolicyRule:Resources Non-Resource URLs Resource Names Verbs--------- ----------------- -------------- -----daemonsets.apps [] [] [create]deployments.apps [] [] [create]statefulsets.apps [] [] [create]$ kubectl create rolebinding dev --serviceaccount default:dev-sa --role dev-role#检查$ kubectl auth can-i create deployment --as system:serviceaccount:default:dev-sayes$ kubectl auth can-i create statefulset --as system:serviceaccount:default:dev-sayes$ kubectl auth can-i create daemonset --as system:serviceaccount:default:dev-sayes$ kubectl auth can-i create pod --as system:serviceaccount:default:dev-sano
创建一个pod名称日志,容器名称
log-pro使用imagebusybox,在/log/data/output.log输出重要信息。然后另一个容器名称log-cus使用 imagebusybox,在/log/data/output.log加载output.log并打印它。 请注意,此日志文件只能在 pod 内共享。
•pod•volume: emptyDir
参考文档: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir
kubectl run log --image busybox --dry-run=client -o yaml > log.yaml修改 log.yaml
apiVersion: v1kind: Podmetadata:creationTimestamp: nulllabels:run: logname: logspec:containers:- command:- sh- -c- echo important information > /log/data/output.log; sleep 1dimage: busyboxname: log-proresources: {}imagePullPolicy: IfNotPresentvolumeMounts:- mountPath: /log/dataname: log- command:- sh- -c- tail -f /log/data/output.logimage: busyboxname: log-cusimagePullPolicy: IfNotPresentvolumeMounts:- mountPath: /log/dataname: logdnsPolicy: ClusterFirstrestartPolicy: Alwaysvolumes:- name: logemptyDir: {}status: {}
执行创建 kubectl apply -f log.yaml
检查
$ kubectl logs log -c log-cusimportant information
只有命名空间
mysql的 pod 只能被另一个命名空间internal的 pod 通过 8080 端口进行访问
•NetworkPolicy•Ingress
参考文档: https://kubernetes.io/docs/concepts/services-networking/network-policies/#the-networkpolicy-resource
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:name: cka-networknamespace: target #目的命名空间spec:podSelector: {}policyTypes:- Ingress #策略影响入栈流量ingress:- from: #允许流量的来源- namespaceSelector:matchLabels:ns: source #源命名空间的 labelports:- protocol: TCPport: 8080 #允许访问的端口
统计这个集群中没有污染的就绪节点,并输出到文件
/root/cka/readyNode.txt。
•Node•Taint(污点)
参考文档:https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/
# Ready 状态的数量$ kubectl get node | grep -w Ready | wc -l# 查看含有 Taint 的数量,需要排除掉这些$ kubectl describe node | grep Taints | grep -i NoSchedule | wc -l
将占用CPU资源最多的pod名称输出到文件
/root/cka/name.txt
•kubectl top 命令•metrics
如果是 minikube 环境,报错 error: Metrics API not available,可以执行 minikube addons enable metrics-server 命令开启 metrics server。
通过 kubectl top 命令找到 cpu 最高的 pod,将其名字写入 /root/cka/name.txt。
$ kubectl top pod# 或者$ kubectl top pod | sort -k 2 -n
有 pod 名称
pod-nginx,创建服务名称service-nginx,使用nodePort暴露pod。 然后创建一个 pod 使用 imagebusybox来nslookuppodpod-nginx和 serviceservice-nginx。
•service with nodePort•kubectl expose•kubectl run
参考文档:https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/
使用 kubectl expose 创建 service。
# 创建 servicekubectl expose pod pod-nginx --name service-nginx --type NodePort --target-port 80# 创建 podkubectl run busybox --image busybox:latest --command sleep 1h
获取 pod 的 ip 地址,pod 的 dns lookup 需要用用到 ip。
$ kubectl get po -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESbusybox 1/1 Running 0 2m17s 172.17.0.5 cka <none> <none>pod-nginx 1/1 Running 0 59m 172.17.0.4 cka <none> <none>
执行 nslookup
$ kubectl exec busybox -it -- nslookup 172.17.0.44.0.17.172.in-addr.arpa name = 172-17-0-4.service-nginx.default.svc.cluster.local.$ kubectl exec busybox -it -- nslookup service-nginxServer: 10.96.0.10Address: 10.96.0.10#53Name: service-nginx.default.svc.cluster.localAddress: 10.110.253.70
将命名空间
dev中的 Deploymentscale-deploy缩放到三个 pod 并记录下来。
参考文档:https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#scaling-a-deployment
•deployment scale up•kubectl scale
kubectl scale 的使用,需要参数 --record 进行记录(将操作命令记录到 deployment 的 kubernetes.io/change-cause annotation 中)。
$ kubectl scale deployment scale-deploy --replicas 3 --record备份 etcd 并将其保存在主节点上的
/root/cka/etcd-backup.db。
最后恢复备份。
•etcd 的备份及恢复
参考文档:https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/#backing-up-an-etcd-cluster
Kubernetes 的所有数据都记录在 etcd 中,对 etcd 进行备份就是对集群进行备份。
连接 etcd 需要证书,证书可以从 apiserver 获取,因为 apiserver 需要连接 etcd。新版本的 apiserver 都是以 static pod 的方式运行,证书是通过 volume 挂载到 pod 中的。
比如 minikube 环境,证书是从 node 节点的 /var/lib/minikube/certs 挂载进去的。
要先 ssh 到 master 节点上。命令的执行非常快,如果长时间没结束,那就说名有问题了。
#备份$ ETCDCTL_API=3 etcdctl snapshot save /root/cka/etcd-backup.db \--endpoints=https://127.0.0.1:2379 \--cacert=/var/lib/minikube/certs/etcd/ca.crt \--cert=/var/lib/minikube/certs/apiserver-etcd-client.crt \--key=/var/lib/minikube/certs/apiserver-etcd-client.key
由于只说了 restore,所以就执行 restore 的命令,默认会恢复到当前目录的 default.etcd 下。
#恢复$ ETCDCTL_API=3 etcdctl snapshot restore /root/cka/etcd-backup.db \--endpoints=https://127.0.0.1:2379 \--cacert=/var/lib/minikube/certs/etcd/ca.crt \--cert=/var/lib/minikube/certs/apiserver-etcd-client.crt \--key=/var/lib/minikube/certs/apiserver-etcd-client.key
将master节点版本从 1.20.0 升级到 1.21.0,确保 master 节点上的 pod 重新调度到其他节点,升级完成后,使 master 节点可用。
•drain•cordon
参考文档:https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-upgrade/#upgrading-control-plane-nodes
受限于环境,没有实地操作。
# 将节点设置为不可调度$ kubectl cordon master# 驱逐 master 节点上的 pod$ kubectl drain master --ignore-daemonsets# 进行升级$ apt-mark unhold kubelet kubectl && \apt-get update && apt-get install -y kubelet=1.21.0-00 kubectl=1.21.0-00 && \apt-mark hold kubelet kubectl# 重新启动kubelet$ systemctl daemon-reload$ systemctl restart kubelet# 将节点设置为可调度$ kubectl uncordon master
现在 node01 还没有准备好,请找出根本原因并使其准备好,然后创建一个确保它在 node01 上运行的 pod。
•节点故障排查
这种问题大概率问题出在 kubelet 上
ssh node01systemctl status kubeletsystemctl restart kubelet# 再检查node状态
插播一个故障,本地安装 2 个节点的 minikube 集群时,第二个节点持续 NotReady。使用 systemctl status kubelet 看到 unable to update cni config: no networks found in /etc/cni/net.mk。
检查该目录确实没有文件,从 master 节点复制到该节点后重启 kubelet 解决。
集群中有一个持久卷名称
dev-pv,创建一个持久卷声明名称dev-pvc,确保这个持久卷声明会绑定持久卷,然后创建一个 pod 名称test-pvc,将这个 pvc 挂载到 path/tmp/data,使用 nginx 镜像。
•PersistentVolume•PersistentVolumeClaim•Mount Volume
参考文档:https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/#create-a-persistentvolume
创建 pvc 前先获取 pv的信息
$ kubectl get pv dev-pv -o yaml创建 pv
$ cat > pvc.yaml <<EOFapiVersion: v1kind: PersistentVolumeClaimmetadata:name: dev-pvcspec:accessModes:- ReadWriteOnceresources:requests:storage: 1GiEOF$ kubectl apply -f pvc.yaml
创建 pod 的 manifest,记得使用 kubectl run --dry-run=client -o yaml
kubectl run test-pvc --image nginx --dry-run=client -o yaml > test-pvc.yaml修改之后得到最终的 pod yaml
apiVersion: v1kind: Podmetadata:creationTimestamp: nulllabels:run: test-pvcname: test-pvcspec:volumes:- name: datapersistentVolumeClaim:claimName: dev-pvccontainers:- image: nginxname: test-pvcresources: {}volumeMounts:- name: datamountPath: /tmp/datadnsPolicy: ClusterFirstrestartPolicy: Always
理论上只要 pod 能运行,就说明成功。也可以进一步确认挂载是否成功,在 pod 的 /tmp/data 中 touch 个文件,然后到节点的目录中查看是有该文件。
创建一个名为
deploy-important的 Deployment,标签为id=very-important(pod 也应该有这个标签)和命名空间 dev 中的 3 个副本。 它应该包含两个容器,第一个名为container1并带有镜像,第二个名为 container2 的图像为kubernetes/pause。
在一个工作节点上应该只运行该部署的一个 Pod。 我们有两个工作节点:
cluster1-worker1和cluster1-worker2。 因为 Deployment 有三个副本,所以结果应该是在两个节点上都有一个 Pod 正在运行。 不会调度第三个 Pod,除非添加新的工作节点。
•deployment•pod label•replicas•multi container pod•pod anti affinity
官方文档参考:https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#never-co-located-in-the-same-node
先创建模板
$ kubectl create deployment deploy-important --image nginx --replicas 3 --dry-run=client -o yaml > deploy-important.yaml修改后的 yaml
apiVersion: apps/v1kind: Deploymentmetadata:creationTimestamp: nulllabels:app: deploy-importantid: very-importantname: deploy-importantspec:replicas: 3selector:matchLabels:app: deploy-importantid: very-importantstrategy: {}template:metadata:creationTimestamp: nulllabels:app: deploy-importantid: very-importantspec:affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: idoperator: Invalues:- very-importanttopologyKey: kubernetes.io/hostnamecontainers:- image: nginxname: container1resources: {}- image: kubernetes/pausename: container2status: {}
minikube 上测试只能调度一个 pod,符合预期
$ kgpoNAME READY STATUS RESTARTS AGEdeploy-important-659d54fc47-6cp8r 0/2 Pending 0 3h10mdeploy-important-659d54fc47-92z4d 2/2 Running 0 3h10mdeploy-important-659d54fc47-c6llc 0/2 Pending 0 3h10m
在
secret命名空间下,使用镜像busybox:1.31.1创建一个名为secret-pod的 pod,并保证 pod 运行一段时间
有个名为
sercret1.yaml的 Secret 文件,在secret命名空间下创建 Secret,并以只读的方式挂在到 Pod 的/tmp/secret1目录 创建一个新的 Secretsecret2包含user=user1和pass=1234,分别以缓解变量APP_USER和APP_PASS输入到 Pod 中
•secret•toleration•taints
参考文档: https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets https://kubernetes.io/docs/concepts/configuration/secret/#using-secrets-as-environment-variables
创建 namespace
$ kubectl create ns secret创建 pod 模板
$ kubectl run secret-pod --image busybox:1.31.1 --dry-run=client -o yaml --command -- sleep 1d > secret-pod.yaml修改 secret1.yaml,使用 secret namespace
apiVersion: v1data:halt: IyEvYmluL2Jhc2g=kind: Secretmetadata:creationTimestamp: "2021-05-15T07:48:02Z"name: secret1namespace: secrettype: Opaque
创建 secret2
$ kubectl create secret generic secret2 --from-literal user=user1 --from-literal pass=1234修改模板
apiVersion: v1kind: Podmetadata:creationTimestamp: nulllabels:run: secret-podname: secret-podspec:containers:- command:- sleep- 1dimage: busybox:1.31.1name: secret-podenv:- name: APP_USERvalueFrom:secretKeyRef:name: secret2key: user- name: APP_PASSvalueFrom:secretKeyRef:name: secret2key: passresources: {}volumeMounts:- mountPath: /tmp/secret1name: secdnsPolicy: ClusterFirstrestartPolicy: Alwaysvolumes:- name: secsecret:secretName: secret1status: {}
检查结果:
$ kubectl exec secret-pod -- cat /tmp/secret1/halt#!/bin/bash$ kubectl exec secret-pod -- env | grep 'APP_'APP_USER=user1APP_PASS=1234
在
cluster3-master1上的default命名空间中创建一个名为my-static-pod的静态 Pod。 使用镜像nginx:1.16-alpine并分配 10m CPU 和 20Mi 内存的资源。
Then create a NodePort Service named static-pod-service which exposes that static Pod on port 80 and check if it has Endpoints and if its reachable through the cluster3-master1 internal IP address. You can connect to the internal node IPs from your main terminal. 然后创建一个名为
static-pod-service的 NodePort Service,该服务在端口 80 上公开该静态 Pod,并检查它是否具有端点以及是否可以通过cluster3-master1内部 IP 地址访问它。
•static pod•resource•nodeport service•endpoints
参考文档:
•https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/•https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#meaning-of-memory
创建pod模板
$ kubectl run my-static-pod --image nginx:1.16-alpine --dry-run=client -o yaml > static-pod.yaml修改模板,增加资源配置
apiVersion: v1kind: Podmetadata:creationTimestamp: nulllabels:run: my-static-podname: my-static-podspec:containers:- image: nginx:1.16-alpinename: my-static-podresources:requests:cpu: "10m"memory: "20Mi"dnsPolicy: ClusterFirstrestartPolicy: Alwaysstatus: {}
ssh 到主机,找到 kubelet 配置文件的位置 ps -ef | grep kubelet
查看配置文件(minikube:/var/lib/kubelet/config.yaml)中 staticPodPath 配置的就是静态 pod 的 manifest 的位置(minikube:/etc/kubernetes/manifests)
将 static-pod.yaml 放到正确的文件夹中,然后重启 kubelet
$ systemctl restart kubelet检查pod是否正确运行
创建 node port
$ kubectl expose pod my-static-pod --name static-pod-service --type NodePort --port 80检查是否创建成功
$ kubectl get svcNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEstatic-pod-service NodePort 10.97.248.99 <none> 80:31938/TCP 68s
获取 node 的 ip
$ kubectl get node -o wideNAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIMEcka Ready master 10h v1.18.8 192.168.64.3 <none> Buildroot 2020.02.10 4.19.171 docker://20.10.4
在 minikube 的环境下可直接通过 minikube ip 获取
测试
$ http 192.168.64.3:31938 --headersHTTP/1.1 200 OKAccept-Ranges: bytesConnection: keep-aliveContent-Length: 612Content-Type: text/htmlDate: Sat, 15 May 2021 08:35:11 GMTETag: "5d52db33-264"Last-Modified: Tue, 13 Aug 2019 15:45:55 GMTServer: nginx/1.16.1
在命名空间
default中创建图像httpd:2.4.41-alpine的单个 Pod。Pod 应命名为pod1,容器名为pod1-container。在不给任何节点添加新标签的前提下,将该 pod 调度到主节点上。
•Taint•Label•Tolerance
参考文档:https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/
#找出master节点(一般考试只有一个节点)$ kubectl get node#找到 master 节点的 taints,需要在 pod 的 .spec.tolerations 排除掉$ kubectl describe node xxxx | grep -w Taints#找到 master 节点的 labels$ kubectl describe node xxxx | grep -w Labels -A10
创建pod模板
$ kubectl run pod1 --image httpd:2.4.41-alpine --dry-run=client -o yaml > pod1.yaml修改模板: 这里假设主节点的 Taint 为 node-role.kubernetes.io/master=:NoSchedule
# minikube 集群名为 cka,主节点同名$ kubectl describe node cka | grep -i taintTaints: node-role.kubernetes.io/master:NoSchedule
最终的 pod 如下
apiVersion: v1kind: Podmetadata:creationTimestamp: nulllabels:run: pod1name: pod1spec:containers:- image: httpd:2.4.41-alpinename: pod1resources: {}dnsPolicy: ClusterFirsttolerations:- key: node-role.kubernetes.io/mastereffect: NoSchedulenodeSelector:node-role.kubernetes.io/master: ""restartPolicy: Alwaysstatus: {}
最后检查下是否调度到主节点上:
$ kubectl get pod -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESpod1 1/1 Running 0 102s 10.244.0.3 cka <none> <none>
所有命名空间中都有各种 Pod。 将命令写入 /opt/course/5/find_pods.sh,其中列出所有按 AGE 排序的 Pod(metadata.creationTimestamp)。
将第二个命令写入 /opt/course/5/find_pods_uid.sh,其中列出按字段 metadata.uid 排序的所有 Pod。对这两个命令都使用 kubectl 排序。
•kubectl 命令的使用,主要是 --all-namespaces (缩写 -A) 和 --sort-by
$ cat > /opt/course/5/find_pods.sh <<EOFkubectl get pod -A --sort-by '.metadata.creationTimestamp'EOF
$ cat > /opt/course/5/find_pods_uid.sh <<EOFkubectl get pod -A --sort-by '.metadata.uid'EOF
创建一个名为
safari-pv的新PersistentVolume。它应该具有 2Gi 的容量、accessModeReadWriteOnce、hostPath/Volumes/Data并且没有定义storageClassName。
接下来在命名空间
project-tiger中创建一个名为safari-pvc的新PersistentVolumeClaim。 它应该请求 2Gi 存储,accessModeReadWriteOnce并且不应定义storageClassName。 PVC 应该正确绑定到 PV。
最后在命名空间
project-tiger中创建一个新的 Deploymentsafari,它将该卷挂载到/tmp/safari-data。该 Deployment 的 Pod 应该是镜像 httpd:2.4.41-alpine。
•pv•pvc•pod 使用 pvc•deployment•mount PVC volume
参考文档:
•https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/#create-a-persistentvolume•https://kubernetes.io/docs/tasks/configure-pod-container/configure-persistent-volume-storage/#create-a-persistentvolumeclaim•https://kubernetes.io/docs/concepts/storage/persistent-volumes/#claims-as-volumes
创建 pv
apiVersion: v1kind: PersistentVolumemetadata:name: safari-pvlabels:type: localspec:capacity:storage: 2GiaccessModes:- ReadWriteOncehostPath:path: "/Volumes/Data"
创建 pvc
apiVersion: v1kind: PersistentVolumeClaimmetadata:name: safari-pvcspec:accessModes:- ReadWriteOnceresources:requests:storage: 2Gi
检查是否绑定成功
$ kubectl get pvcNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEsafari-pvc Bound pvc-d4c15825-2de3-470f-8ed0-9519cacaad21 2Gi RWO standard 24s
创建 deployment 模板
$ kubectl create deployment safari --image httpd:2.4.41-alpine --dry-run=client -o yaml最终的yaml
apiVersion: apps/v1kind: Deploymentmetadata:creationTimestamp: nulllabels:app: safariname: safarispec:replicas: 1selector:matchLabels:app: safaristrategy: {}template:metadata:creationTimestamp: nulllabels:app: safarispec:containers:- image: httpd:2.4.41-alpinename: httpdresources: {}volumeMounts:- mountPath: /tmp/safari-dataname: datavolumes:- name: datapersistentVolumeClaim:claimName: safari-pvcstatus: {}
可以通过 kubectl 上下文从主终端访问多个集群。将所有这些上下文名称写入 /opt/course/1/contexts。
接下来在 /opt/course/1/context_default_kubectl.sh 中写一个显示当前上下文的命令,该命令应该使用kubectl。
最后在 /opt/course/1/context_default_no_kubectl.sh 中写入第二个执行相同操作的命令,但不使用 kubectl。
kubectl config 相关命令的使用
kubectl config get-contexts -o name > /opt/course/1/contextscat > /opt/course/1/context_default_kubectl.sh <<EOFkubectl config current-contextEOFchmod +x /opt/course/1/context_default_kubectl.sh
cat ~/.kube/config | grep current-context | awk '{print $2}'命名空间
project-c13中有两个名为o3db-*的 Pod。 C13 管理层要求将 Pod 缩减为一个副本以节省资源。 记录动作。
•scale•deploy•statefulset
参考文档: https://kubernetes.io/zh/docs/tasks/run-application/scale-stateful-set/ https://kubernetes.io/zh/docs/concepts/workloads/controllers/deployment/#scaling-a-deployment
kubectl scale <resource> xxx --replicas=1scale 命令需要确认资源类型:deployment/statefulset
在命名空间
default中执行以下操作。为nginx:1.16.1-alpine创建一个名为ready-if-service-ready的 Pod。配置一个LivenessProbe,它只是运行true。还要配置一个ReadinessProbe来检查urlhttp://service-am-i-ready:80是否可达,可以使用wget -T2 -O- http://service-am-i-ready:80。 启动 Pod 并确认它因为ReadinessProbe而没有准备好。
创建第二个名为
am-i-ready的 Pod 镜像nginx:1.16.1-alpine,标签id:cross-server-ready。已经存在的服务service-am-i-ready现在应该有第二个 Pod 作为端点。
•probe•pod
参考文档: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
kubectl run ready-if-service-ready --image nginx:1.16.1-alpine --dry-run=client -o yaml > ready-if-service-ready.yamlkubectl run am-i-ready --image nginx:1.16.1-alpine --labels id=cross-server-ready --dry-run=client -o yaml > am-i-ready.yaml
添加 probes
apiVersion: v1kind: Podmetadata:creationTimestamp: nulllabels:run: ready-if-service-readyname: ready-if-service-readyspec:containers:- image: nginx:1.16.1-alpinename: ready-if-service-readyresources: {}livenessProbe:exec:command:- echo- hireadinessProbe:exec:command:- wget- -T2- -O-- http://service-am-i-ready:80dnsPolicy: ClusterFirstrestartPolicy: Alwaysstatus: {}
使用
ssh cluster1-master1ssh 进入主节点。检查 master 组件 kubelet、kube-apiserver、kube-scheduler、kube-controller-manager 和 etcd 如何在 master 节点上启动/安装。还要找出 DNS 应用的名称以及它是如何在主节点上启动/安装的。
将结果写入文件 /opt/course/8/master-components.txt。该文件的结构应如下所示:
# /opt/course/8/master-components.txtkubelet: [TYPE]kube-apiserver: [TYPE]kube-scheduler: [TYPE]kube-controller-manager: [TYPE]etcd: [TYPE]dns: [TYPE] [NAME]
Choices of [TYPE] are: not-installed, process, static-pod, pod
Kubernetes components 的安装方式
当前比较的组件都是以static pod的形式运行的,而 static pod 都是由 Kubelet 管理的,所以从 kubelet 处入手。
以 minikube 为例:
$ ps -ef | grep -w kubeletroot 140597 1 2 May15 ? 00:36:00 /var/lib/minikube/binaries/v1.18.8/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=cka --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.64.3$ systemctl is-active kubeletactive#kubelet: process
根据前面进程中的信息,查看 /var/lib/kubelet/config.yaml中的内容。可以得到:
etcd: static-pod kube-apiserver: static-pod kube-controller-manager: static-pod
$ cat /var/lib/kubelet/config.yaml | grep -i staticpodstaticPodPath: /etc/kubernetes/manifestsls /etc/kubernetes/manifestsetcd.yaml kube-apiserver.yaml kube-controller-manager.yaml kube-scheduler.yaml
最后上下dns,查看下pod,得知 dns: pod
$ kubectl get pod -A | grep dnskube-system coredns-66bff467f8-6k2br 1/1 Running 0 32h
最后将上面的结果写入到 /opt/course/8/master-components.txt,不能前功尽弃。
使用
ssh cluster2-master1ssh 进入主节点。暂时停止kube-scheduler,这意味着可以在之后再次启动它。
为镜像
httpd:2.4-alpine创建一个名为manual-schedule的 Pod,确认它已启动但未在任何节点上调度。
现在您是调度程序并拥有所有权力,在节点
cluster2-master1上手动调度该 Pod。 确保它正在运行。
再次启动
kube-scheduler并通过在镜像httpd:2.4-alpine创建第二个名为manual-schedule2的 Pod 并检查它是否在cluster2-worker1上运行来确认其运行正常。
•kubernetes 组件的运行方式•创建 pod•pod 调度
kube-scheduler 是以 static pod 的方式运行,因此我们需要 ssh 到节点上,将 scheduler 的 yaml 移出(记住不要删掉,还要还原回去),重启 kubelet
$ ps -ef | grep -w kubeletroot 140597 1 2 May15 ? 00:36:00 /var/lib/minikube/binaries/v1.18.8/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=cka --kubeconfig=/etc/kubernetes/kubelet.conf --node-ip=192.168.64.3$ cat /var/lib/kubelet/config.yaml | grep -i staticpodstaticPodPath: /etc/kubernetes/manifests$ ls /etc/kubernetes/manifestsetcd.yaml kube-apiserver.yaml kube-controller-manager.yaml kube-scheduler.yaml$ mv /etc/kubernetes/manifests/kube-scheduler.yaml /etc/kubernetes$ systemctl restart kubelet
检查下 schedule pod 没有运行,然后尝试创建 pod,并查看 pod 处于 pending 状态,即没有 kube-scheduler 为其调度。
$ kubectl run manual-schedule --image httpd:2.4-alpine$ kubectl get pod | grep manual-schedulemanual-schedule 0/1 Pending 0 16s
手动调度,即为 pod 指定一个 nodeName,我的 minikube 只有一个 node 名为 cka,修改pod:
$ kubectl get pod manual-schedule -o yaml > manual-schedule.yaml添加 nodeName 之后
apiVersion: v1kind: Podmetadata:creationTimestamp: "2021-05-16T07:27:16Z"labels:run: manual-schedulename: manual-schedulenamespace: devresourceVersion: "84805"selfLink: /api/v1/namespaces/dev/pods/manual-scheduleuid: c4b592f6-1e07-4911-a7fe-867d813c7a55spec:containers:- image: httpd:2.4-alpineimagePullPolicy: IfNotPresentname: manual-scheduleresources: {}terminationMessagePath: /dev/termination-logterminationMessagePolicy: FilevolumeMounts:- mountPath: /var/run/secrets/kubernetes.io/serviceaccountname: default-token-v7f28readOnly: truednsPolicy: ClusterFirstnodeName: cka #node name hereenableServiceLinks: truepriority: 0restartPolicy: AlwaysschedulerName: default-schedulersecurityContext: {}serviceAccount: defaultserviceAccountName: defaultterminationGracePeriodSeconds: 30tolerations:- effect: NoExecutekey: node.kubernetes.io/not-readyoperator: ExiststolerationSeconds: 300- effect: NoExecutekey: node.kubernetes.io/unreachableoperator: ExiststolerationSeconds: 300volumes:- name: default-token-v7f28secret:defaultMode: 420secretName: default-token-v7f28status:phase: PendingqosClass: BestEffort
强制更新 pod(运行时只能修改部分内容):
$ kubectl replace -f manual-schedule.yaml --forcepod "manual-schedule" deletedpod/manual-schedule replaced
再次检查
$ kubectl get pod | grep manual-schedulemanual-schedule 1/1 Running 0 15s
恢复 kube-scheduler 的运行:
$ mv /etc/kubernetes/kube-scheduler.yaml /etc/kubernetes/manifests$ systemctl restart kubelet
检查是否运行
$ kubectl get pod -A | grep kube-schedulerkube-system kube-scheduler-cka 1/1 Running 0 66s
创建第二个pod,并检查是否在运行(running)状态
$ kubectl run manual-schedule2 --image httpd:2.4-alpinepod/manual-schedule2 createdkubectl get pod manual-schedule2NAME READY STATUS RESTARTS AGEmanual-schedule2 1/1 Running 0 6s
对在
cluster3-master1上运行的 etcd 进行备份,并将其保存在主节点上的/tmp/etcd-backup.db。
然后在集群中创建一个你喜欢的 Pod。
最后恢复备份,确认集群仍在工作并且创建的 Pod 不再与我们在一起。
•etc 的作用:存储集群的状态信息,包括 pod 信息•etc 的备份和恢复
参考文档: https://kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/#backing-up-an-etcd-cluster
etcd的命令执行,记得设置API的版本 ETCDCTL_API=3
操作 etcd 需要 endpoints、cacert、cert、key。Kubernetes 的所有组件与 etcd 的数据交互都是通过 api-server 完成的,我只需要找到 api-server 的运行命令就行,两种方式:到 master 主机查看 api-server 的进程;或者去 api-server 的 pod 查看 .spec.containers[].command
#ssh to master$ ps -ef | grep kube-apiserver$ kubectl get pod -n kube-system kube-apiserver-cka -o jsonpath='{.spec.containers[].command}'
etcd 备份,命令直接从 Kubernetes 官方文档复制再修改
#ssh to master$ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \--cacert=/var/lib/minikube/certs/etcd/ca.crt --cert=/var/lib/minikube/certs/apiserver-etcd-client.crt --key=/var/lib/minikube/certs/apiserver-etcd-client.key \snapshot save /tmp/etcd-backup.dbSnapshot saved at /tmp/etcd-backup.db
创建 pod
$ kubectl run sleep1d --image busybox --command -- sleep 1d#检查 pod 运行情况$ kubectl get podNAME READY STATUS RESTARTS AGEsleep1d 1/1 Running 0 10s
恢复 etcd 的备份,复制前面的命令并修改,恢复备份到 /var/lib/etcd-backup
$ ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/var/lib/minikube/certs/etcd/ca.crt --cert=/var/lib/minikube/certs/apiserver-etcd-client.crt --key=/var/lib/minikube/certs/apiserver-etcd-client.key snapshot restore /tmp/etcd-backup.db --data-dir /var/lib/etcd-backup2021-05-16 08:09:17.797061 I | mvcc: restore compact to 853472021-05-16 08:09:17.803208 I | etcdserver/membership: added member 8e9e05c52164694d [http://localhost:2380] to cluster cdf818194e3a8c32
修改 etcd 的配置, /etc/kubernetes/manifests/etcd.yaml
volumes:- hostPath:path: /var/lib/minikube/certs/etcdtype: DirectoryOrCreatename: etcd-certs- hostPath:path: /var/lib/etcd-backup #原来是/var/lib/minikube/etcdtype: DirectoryOrCreatename: etcd-datastatus: {}
保存后重启kubelet
$ systemctl restart kubelet检查pod是否存在:
$ kubectl get pod sleep1dError from server (NotFound): pods "sleep1d" not found
发生了一起安全事件,入侵者能够从一个被黑的后端 Pod 访问整个集群。
为了防止这种情况,在命名空间
project-snake中创建一个名为np-backend的NetworkPolicy。它应该只允许backend-*Pods:
连接到端口
1111上的db1-*Pod 连接到端口2222上的db2-*Pod 在策略中使用 Pod 的应用程序标签。
实施后,例如,端口 3333 上从
backend-*Pod 到vault-*Pod 的连接应该不再有效。
•NetworkPolicy
参考文档: https://kubernetes.io/docs/concepts/services-networking/network-policies
为 backend-* pod 设置 egress 的 NetworkPolicy,只允许其访问 db1-* 的 1111 端口和 db2-* 的 2222 端口,策略中使用 app label 来进行匹配。
从 Kubernetes 官网文档中复制一段yaml配置进行修改。
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:name: np-backendnamespace: project-snakespec:podSelector:matchLabels:app: backendpolicyTypes:- Egressegress:- to:- podSelector:matchLabels:app: db1ports:- protocol: TCPport: 1111- to:- podSelector:matchLabels:app: db2ports:- protocol: TCPport: 2222
假设 backend pod 的 app label 为 backend,db1 的 为 db1,db2 的为 db2。
创建环境:
$ kubectl run backend --image nginx --labels app=backend$ kubectl run db1 --image nginx --labels app=db1$ kubectl run db2 --image nginx --labels app=db2$ kubectl run vault --image nginx --labels app=vault$ kubectl get pod -L appNAME READY STATUS RESTARTS AGE APPbackend 1/1 Running 0 13s backenddb1 1/1 Running 0 66s db1db2 1/1 Running 0 71s db2vault 1/1 Running 0 79s vault
由于我们用的 nginx 镜像,将前面的 NetworkPolicy 端口修改一下:
apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata:name: np-backendspec:podSelector:matchLabels:app: backendpolicyTypes:- Egressegress:- to:- podSelector:matchLabels:app: db1ports:- protocol: TCPport: 80- to:- podSelector:matchLabels:app: db2ports:- protocol: TCPport: 80
检查一下:
$ kubectl get networkpolicyNAME POD-SELECTOR AGEnp-backend app=backend 31s
测试下网络:
#获取pod ip$ kubectl get pod -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESbackend 1/1 Running 0 3m15s 172.17.0.7 cka <none> <none>db1 1/1 Running 0 4m8s 172.17.0.6 cka <none> <none>db2 1/1 Running 0 4m13s 172.17.0.3 cka <none> <none>vault 1/1 Running 0 4m21s 172.17.0.4 cka <none> <none>
节点
cluster2-worker1已使用 kubeadm 和 TLS 引导添加到集群中。 找到cluster2-worker1的 “Issuer” 和 “Extended Key Usage” 值: kubelet 客户端证书,用于向外连接到 kube-apiserver 的证书。 kubelet 服务器证书,用于来自 kube-apiserver 的传入连接。 将信息写入文件/opt/course/23/certificate-info.txt。
•kubelet 的功能:连接 api-server;接受来自 api-server 的响应。两种情况都需要 TLS
kubelet 连接 apiserver 的方式在配置文件中,先找出配置文件的保存位置。
# ssh 到节点上,查看 kubelet 的启动命令$ ps -ef | grep kubeletroot 3935 1 1 12:54 ? 00:00:23 /var/lib/minikube/binaries/v1.20.0/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --cni-conf-dir=/etc/cni/net.mk --config=/var/lib/kubelet/config.yaml --container-runtime=docker --hostname-override=cka-m02 --kubeconfig=/etc/kubernetes/kubelet.conf --network-plugin=cni --node-ip=192.168.64.9docker 13653 13616 0 13:22 pts/0 00:00:00 grep kubelet
#kubelet 连接 api server 的信息, client cert 的配置所在 /var/lib/kubelet/pki/kubelet-client-current.pemcat /var/lib/kubelet/config.yaml#kubelet 的启动信息, servert cert 的配置所在 /var/lib/minikube/certs/ca.crtcat /etc/kubernetes/kubelet.conf
$ openssl x509 -noout -text -in /var/lib/kubelet/pki/kubelet-client-current.pem | grep -i issuerIssuer: CN = minikubeCA$ openssl x509 -noout -text -in /var/lib/kubelet/pki/kubelet-client-current.pem | grep -i -A1 extendedX509v3 Extended Key Usage:TLS Web Client Authentication$ openssl x509 -noout -text -in /var/lib/minikube/certs/ca.crt | grep -i issuerIssuer: CN = minikubeCA$ openssl x509 -noout -text -in /var/lib/minikube/certs/ca.crt | grep -i -A1 extendedX509v3 Extended Key Usage:TLS Web Client Authentication, TLS Web Server Authentication
最后记得将信息写入到 /opt/course/23/certificate-info.txt
检查 kube-apiserver 服务器证书在
cluster2-master1上的有效期。使用 openssl 或 cfssl 执行此操作。将到期日期写入/opt/course/22/expiration。
同时运行正确的 kubeadm 命令以列出到期日期并确认两种方法显示相同的日期。
将更新 apiserver 服务器证书的正确 kubeadm 命令写入
/opt/course/22/kubeadm-renew-certs.sh。
•api-server•openssl•kubeadm
参考文档:https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-certs/#check-certificate-expiration
通过 kube-apiserver pod 的启动命令,或者 ssh 到 master 来查看命令参数,tls-cert-file=/var/lib/minikube/certs/apiserver.crt
$ openssl x509 -noout -text -in /var/lib/minikube/certs/apiserver.crt | grep -i valid -A2ValidityNot Before: May 13 22:33:43 2021 GMTNot After : May 14 22:33:43 2022 GMT
将 May 14 22:33:43 2022 GMT 写入 /opt/course/22/expiration
通过 kubeadm 来检查
$ kubeadm certs check-expiration | grep -i apiserver#macos 无法安装 kubeadm#minikube 无法使用 kubeadm 检查
将 kubeadm certs renew apiserver 写入 /opt/course/22/kubeadm-renew-certs.sh
你的同事说节点
cluster3-worker2运行的是较旧的 Kubernetes 版本,甚至不属于集群的一部分。将 kubectl 和 kubeadm 更新为在cluster3-master1上运行的确切版本。然后将此节点添加到集群中,您可以为此使用kubeadm。
•kubeadm 升级集群
参考文档:
检查node
$ kubectl get nodes检查当前组件版本
$ ssh cluster3-worker2$ kubeadm version$ kubectl version --shortClient Version: vx.xx.xServer Version: vx.xx.x$ kubelet --version
#使用命令并升级各个组件,并重启 kubelet#如果启动失败,一般是需要token连接到api-server,需要ssh到master上运行 kubeadm create token --print-join-command#再ssh到 node上,执行打印的命令,重启kubelet并检查装填#最后检查node是否成功加入集群
在命名空间
project-tiger中创建一个名为Tigers-reunite的 Pod 镜像httpd:2.4.41-alpine,标签为pod=container和container=pod。找出 Pod 被安排在哪个节点上。ssh 进入该节点并找到属于该 Pod 的 docker 容器。
将容器的 docker ID 和这些正在运行的进程/命令写入
/opt/course/17/pod-container.txt。
最后,使用 docker 命令将主 Docker 容器(来自 yaml 中指定的那个)的日志写入
/opt/course/17/pod-container.log。
•docker 命令:ps、logs、inspect
创建 pod
$ kubectl run tigers-reunite --image httpd:2.4.41-alpine --labels pod=container,container=pod检查 pod 的信息
$ kubectl get pods --show-labelsNAME READY STATUS RESTARTS AGE LABELStigers-reunite 1/1 Running 0 34s container=pod,pod=container
获取pod所在的节点
$ kubectl get pod tigers-reunite -o jsonpath='{.spec.nodeName}'cka
ssh到节点上
docker ps | grep tigers-reunitee6ff69b437bc 54b0995a6305 "httpd-foreground" About a minute ago Up About a minute k8s_tigers-reunite_tigers-reunite_dev_53391212-911d-4275-a19d-e8f8b0f85a98_006d3ca65eb08 k8s.gcr.io/pause:3.2 "/pause" About a minute ago Up About a minute k8s_POD_tigers-reunite_dev_53391212-911d-4275-a19d-e8f8b0f85a98_0#使用docker inspect 或者 进入容器直接查看进程$ docker inspect e6ff69b437bc | grep -i 'cmd\|entrypoint' -A1"Cmd": ["httpd-foreground"--"Entrypoint": null,"OnBuild": null,$ docker inspect 06d3ca65eb08 | grep -i 'cmd\|entrypoint' -A1"Cmd": null,"Image": "k8s.gcr.io/pause:3.2",--"Entrypoint": ["/pause"
结果写入文件
e6ff69b437bc httpd-foreground06d3ca65eb08 pause
写日志到文件
docker logs e6ff69b437bc > /opt/course/17/pod-container.log[1] K8s-CKA-CAKD-Bookmarks.html: https://gist.github.com/addozhang/3ca950ce9b38930abfe7c5fb067e74de
原文作者:云原生指北;如有侵权,请联系管理员删除。