k8s面试题大全,保姆级的攻略哦(二)
目录
三十六、pod的定义中有个command和args参数,这两个参数不会和docker镜像的entrypointc冲突吗?
三十七、标签及标签选择器是什么,如何使用?
三十八、service是如何与pod关联的?
三十九、service的域名解析格式、pod的域名解析格式
四十、service的类型有哪几种?
四十一、一个应用pod是如何发现service的,或者说,pod里面的容器用于是如何连接service的?
四十二、如何创建一个service代理外部的服务,或者换句话来说,在k8s集群内的应用如何访问外部的服务,如数据库服务,缓存服务等?
四十三、service、endpoint、kube-proxy三种的关系是什么?
四十四、无头service和普通的service有什么区别,无头service使用场景是什么?
四十五、deployment怎么扩容或缩容?
四十六、deployment的更新升级策略有哪些?
四十七、deployment的滚动更新策略有两个特别主要的参数,解释一下它们是什么意思?
四十八、deployment更新的命令有哪些?
四十九、简述一下deployment的更新过程 (经常问)
五十、deployment的回滚使用什么命令
五十一、讲一下都有哪些存储卷,作用分别是什么?
五十二、pv的访问模式有哪几种
五十三、pv的回收策略有哪几种?
五十四、在pv的生命周期中,一般有几种状态
五十五、怎么使一个node脱离集群调度,比如要停机维护但又不能影响业务应用?
五十六、pv存储空间不足怎么扩容?
五十七、k8s生产中遇到什么特别影响深刻的问题吗,问题排查解决思路是怎么样的?(重点)
五十八、什么是Kubernetes的Service Account,它有什么用途?
五十九、Kubernetes如何管理持久化存储?
六十、Kubernetes如何实现访问控制和权限管理?
六十一、如何确保Kubernetes集群的安全性?
六十二、在Kubernetes中,你如何管理持久化存储?
六十三、描述Kubernetes的亲和性和反亲和性规则,并解释它们如何影响Pod的调度
六十四、Kubernetes中的Ingress是什么,它如何工作?
六十五、Kubernetes的自动伸缩(Autoscaling)是如何工作的?
六十七、Kubernetes中的DaemonSet是什么,它通常用于什么场景?
六十八、Kubernetes中的StatefulSet和Deployment有什么区别?
六十九、Kubernetes中的ConfigMap和Secret如何用于应用程序配置?
七十、Kubernetes中的准入控制器(Admission Controllers)是什么,它们如何影响集群的行为?
七十一、Kubernetes中的CNI是什么,它在集群中的作用是什么?
七十二、Kubernetes中的Ingress是什么?它如何与Service一起工作?
七十三、Kubernetes中的服务发现是如何工作的?
三十六、pod的定义中有个command和args参数,这两个参数不会和docker镜像的entrypointc冲突吗?
不会。
在pod中定义的command参数用于指定容器的启动命令列表,如果不指定,则默认使用Dockerfile打包时的启动命令,args参数用于容器的启动命令需要的参数列表;
特别说明:
kubernetes中的command、args其实是实现覆盖dockerfile中的ENTRYPOINT的功能的。当:
1、如果command和args均没有写,那么使用Dockerfile的配置;
2、如果command写了但args没写,那么Dockerfile默认的配置会被忽略,执行pod容器指定的command;
3、如果command没写但args写了,那么Dockerfile中的ENTRYPOINT的会被执行,使用当前args的参数;
4、如果command和args都写了,那么Dockerfile会被忽略,执行pod当前定义的command和args。
三十七、标签及标签选择器是什么,如何使用?
标签是键值对类型,标签可以附加到任何资源对象上,主要用于管理对象,查询和筛选。标签常被用于标签选择器的匹配度检查,从而完成资源筛选;一个资源可以定义一个或多个标签在其上面。
标签选择器,标签要与标签选择器结合在一起,标签选择器允许我们选择标记有特定标签的资源对象子集,如pod,并对这些特定标签的pod进行查询,删除等操作。
标签和标签选择器最重要的使用之一在于,在deployment中,在pod模板中定义pod的标签,然后在deployment定义标签选择器,这样就通过标签选择器来选择哪些pod是受其控制的,service也是通过标签选择器来关联哪些pod最后其服务后端pod。
三十八、service是如何与pod关联的?
答案:通过标签选择器。每一个由deployment创建的pod都带有标签,这样,service就可以定义标签选择器来关联哪些pod是作为其后端了,就是这样,service就与pod关联在一起了。
三十九、service的域名解析格式、pod的域名解析格式
service的DNS域名表示格式为<servicename>.<namespace>.svc.<clusterdomain>,servicename是service的名称,namespace是service所处的命名空间,clusterdomain是k8s集群设置的域名后缀,一般默认为 cluster.local,一般的,我们不会去改k8s集群设置的域名后缀,同时,当pod要链接的svc处于pod当前命名空间时,可以省略<namespace>以及后面的.svc不写,这样,就可以有下面三种方式来表示svc的域名:
#查看k8s集群设置的域名后缀
grep -i clusterDomain /opt/kubernetes/config/kubelet-config.yml #二进制安装的k8s集群,可以这样查看
grep -i clusterDomain /etc/kubernetes/kubelet.conf #kubeadm安装的k8s集群,各个节点的kubelet.conf文件中的字段clusterDomain
grep -i clusterDomain /var/lib/kubelet/config.yaml #kubeadm安装的k8s集群,各个节点的config.yaml文件中的字段clusterDomain
kubectl -n kube-system get cm coredns -oyaml #coredns cm里面也可以看到
kubectl exec -it busybox -- cat /etc/resolv.conf #直接看pod里面的resolv.conf文件亦可
svc-nginx.default.svc.cluster.local #完整的写法
svc-nginx.default #带命名空间写法,省略了后面的.svc.<clusterdomain>
svc-nginx #如果pod与svc在同一个命名空间,可以将命名空间省略不写,换句话说链接的是当前命名空间的svc#于是,svc域名+svc的端口,我们就可以在pod里面访问svc对应的应用了,如下
wget http://svc-deployment-nginx.default.svc.cluster.local:80 #完整的写法
wget http://svc-deployment-nginx.default:80 #带命名空间写法
wget http://svc-deployment-nginx:80 #如果pod与svc在同一个命名空间,可以将命名空间省略不写
pod的DNS域名格式为:<pod-ip>.<namespace>.pod.<clusterdomain> ,其中,pod-ip需要使用-将ip之间的点替换掉,namespace为pod所在的命名空间,clusterdomain是k8s集群设置的域名后缀,一般默认为 cluster.local ,如果没有改变k8s集群默认的域名后缀,则可以省略该后缀不写。除此之外,其他的均不可省略,这一点与svc域名有所不同。
演示如下:
#进入default命名空间的busybox pod里面,测试下载文件
kubectl -n default exec -it deployment-busybox-567674bd67-lmrgw -- sh
wget 10-244-166-167.helm.pod.cluster.local:80 #可以正常下载,这里下载的是helm命名空间里的IP为10.244.166.167的pod
wget 10-244-166-167.helm.pod:80 #可以正常下载,这里把k8s集群设置的域名后缀默认省略了
wget 10-244-166-143.default.pod:80 #可以正常下载,这里下载的是default命名空间里的IP为10.244.166.143的pod
wget 10-244-166-143.default:80 #报错了,错误写法,说明不能省略pod关键字
wget 10-244-166-143:80 #报错了,错误写法,说明不能省略命名空间和pod关键字
对于deployment、daemonsets等创建的无状态的pod,还还可以通过<pod-ip>.<deployment-name>.<namespace>.svc.<clusterdomain> 这样的域名访问。(这点存疑,一直测试失败,不指定是书中写错了还是什么)
对于StatefulSet创建的pod,statefulset.spec.serviceName字段解释如下:
[root@matser ~]# kubectl explain statefulset.spec.serviceName
KIND: StatefulSet
VERSION: apps/v1
FIELD: serviceName <string>
DESCRIPTION:serviceName is the name of the service that governs this StatefulSet. Thisservice must exist before the StatefulSet, and is responsible for thenetwork identity of the set. Pods get DNS/hostnames that follow thepattern: pod-specific-string.serviceName.default.svc.cluster.local where"pod-specific-string" is managed by the StatefulSet controller.
也就是说StatefulSet创建的pod,其pod的域名为:pod-specific-string.serviceName.default.svc.cluster.local,而pod-specific-string就是pod的名称。
例如:redis-sts-0.redis-svc.default.svc.cluster.local:6379,redis-sts-1.redis-svc.default.svc.cluster.local:6379,redis-sts-2.redis-svc.default.svc.cluster.local:6379,redis-sts-3.redis-svc.default.svc.cluster.local:6379,redis-sts-4.redis-svc.default.svc.cluster.local:6379,redis-sts-5.redis-svc.default.svc.cluster.local:6379,pod里面的后端应用程序就可以拿这串字符串去连接Redis集群了。
四十、service的类型有哪几种?
service的类型一般有4种,分别是:
ClusterIP:表示service仅供集群内部使用,默认值就是ClusterIP类型
NodePort:表示service可以对外访问应用,会在每个节点上暴露一个端口,这样外部浏览器访问地址为:任意节点的IP:NodePort就能连上service了
LoadBalancer:表示service对外访问应用,这种类型的service是公有云环境下的service,此模式需要外部云厂商的支持,需要有一个公网IP地址
ExternalName:这种类型的service会把集群外部的服务引入集群内部,这样集群内直接访问service就可以间接的使用集群外部服务了
一般情况下,service都是ClusterIP类型的,通过ingress接入的外部流量。
四十一、一个应用pod是如何发现service的,或者说,pod里面的容器用于是如何连接service的?
答:有两种方式,一种是通过环境变量,另一种是通过service的dns域名方式。
1、环境变量:当pod被创建之后,k8s系统会自动为容器注入集群内有效的service名称和端口号等信息为环境变量的形式,这样容器应用直接通过取环境变量值就能访问service了,如,每个pod都会自动注入了api-server的svc:curl http://${KUBERNETES_SERVICE_HOST}:{KUBERNETES_SERVICE_PORT}
2、DNS方式:使用dns域名解析的前提是k8s集群内有DNS域名解析服务器,默认k8s中会有一个CoreDNS作为k8s集群的默认DNS服务器提供域名解析服务器;service的DNS域名表示格式为<servicename>.<namespace>.svc.<clusterdomain>,servicename是service的名称,namespace是service所处的命名空间,clusterdomain是k8s集群设置的域名后缀,一般默认为 cluster.local ,这样容器应用直接通过service域名就能访问service了,如wget http://nginx-svc.default.svc.cluster.local:80,另外,service的port端口如果定义了名称,那么port也可以通过DNS进行解析,格式为:_<portname>._<protocol>.<servicename>.<namespace>.svc.<clusterdomain>
四十二、如何创建一个service代理外部的服务,或者换句话来说,在k8s集群内的应用如何访问外部的服务,如数据库服务,缓存服务等?
答:可以通过创建一个没有标签选择器的service来代理集群外部的服务。
1、创建service时不指定selector标签选择器,但需要指定service的port端口、端口的name、端口协议等,这样创建出来的service因为没有指定标签选择器就不会自动创建endpoint;
2、手动创建一个与service同名的endpoint,endpoint中定义外部服务的IP和端口,endpoint的名称一定要与service的名称一样,端口协议也要一样,端口的name也要与service的端口的name一样,不然endpoint不能与service进行关联。
完成以上两步,k8s会自动将service和同名的endpoint进行关联,这样,k8s集群内的应用服务直接访问这个service就可以相当于访问外部的服务了。
四十三、service、endpoint、kube-proxy三种的关系是什么?
service:在kubernetes中,service是一种为一组功能相同的pod提供单一不变的接入点的资源。当service被建立时,service的IP和端口不会改变,这样外部的客户端(也可以是集群内部的客户端)通过service的IP和端口来建立链接,这些链接会被路由到提供该服务的任意一个pod上。通过这样的方式,客户端不需要知道每个单独提供服务的pod地址,这样pod就可以在集群中随时被创建或销毁。
endpoint:service维护一个叫endpoint的资源列表,endpoint资源对象保存着service关联的pod的ip和端口。从表面上看,当pod消失,service会在endpoint列表中剔除pod,当有新的pod加入,service就会将pod ip加入endpoint列表;但是正在底层的逻辑是,endpoint的这种自动剔除、添加、更新pod的地址其实底层是由endpoint controller控制的,endpoint controller负责监听service和对应的pod副本的变化,如果监听到service被删除,则删除和该service同名的endpoint对象,如果监听到新的service被创建或者修改,则根据该service信息获取得相关pod列表,然后创建或更新service对应的endpoint对象,如果监听到pod事件,则更新它所对应的service的endpoint对
kube-proxy:kube-proxy运行在node节点上,在Node节点上实现Pod网络代理,维护网络规则和四层负载均衡工作,kube-proxy会监听api-server中从而获取service和endpoint的变化情况,创建并维护路由规则以提供服务IP和负载均衡功能。简单理解此进程是Service的透明代理兼负载均衡器,其核心功能是将到某个Service的访问请求转发到后端的多个Pod实例上。
四十四、无头service和普通的service有什么区别,无头service使用场景是什么?
答:无头service没有cluster ip,在定义service时将 service.spec.clusterIP:None,就表示创建的是无头service。
普通的service是用于为一组后端pod提供请求连接的负载均衡,让客户端能通过固定的service ip地址来访问pod,这类的pod是没有状态的,同时service还具有负载均衡和服务发现的功能。普通service跟我们平时使用的nginx反向代理很相似。
但是,试想这样一种情况,有6个redis pod ,它们相互之间要通信并要组成一个redis集群,不在需要所谓的service负载均衡,这时无头service就是派上用场了,无头service由于没有cluster ip
kube-proxy就不会处理它也就不会对它生成规则负载均衡,无头service直接绑定的是pod 的ip。无头service仍会有标签选择器,有标签选择器就会有endpoint资源。
使用场景:无头service一般用于有状态的应用场景,如Kaka集群、Redis集群等,这类pod之间需要相互通信相互组成集群,不在需要所谓的service负载均衡。
四十五、deployment怎么扩容或缩容?
答:直接修改pod副本数即可,可以通过下面的方式来修改pod副本数:
1、直接修改yaml文件的replicas字段数值,然后kubectl apply -f xxx.yaml来实现更新;
2、使用kubectl edit deployment xxx 修改replicas来实现在线更新;
3、使用kubectl scale --replicas=5 deployment/deployment-nginx命令来扩容缩容。
四十六、deployment的更新升级策略有哪些?
答:deployment的升级策略主要有两种。
1、Recreate 重建更新:这种更新策略会杀掉所有正在运行的pod,然后再重新创建的pod;
2、rollingUpdate 滚动更新:这种更新策略,deployment会以滚动更新的方式来逐个更新pod,同时通过设置滚动更新的两个参数maxUnavailable、maxSurge来控制更新的过程。
四十七、deployment的滚动更新策略有两个特别主要的参数,解释一下它们是什么意思?
答:deployment的滚动更新策略,rollingUpdate 策略,主要有两个参数,maxUnavailable、maxSurge。
maxUnavailable:最大不可用数,maxUnavailable用于指定deployment在更新的过程中不可用状态的pod的最大数量,maxUnavailable的值可以是
一个整数值,也可以是pod期望副本的百分比,如25%,计算时向下取整。
maxSurge:最大激增数,maxSurge指定deployment在更新的过程中pod的总数量最大能超过pod副本数多少个,maxUnavailable的值可以是一个整数
值,也可以是pod期望副本的百分比,如25%,计算时向上取整。
四十八、deployment更新的命令有哪些?
答:可以通过三种方式来实现更新deployment。
1、直接修改yaml文件的镜像版本,然后kubectl apply -f xxx.yaml来实现更新;
2、使用kubectl edit deployment xxx 实现在线更新;
3、使用kubectl set image deployment/nginx busybox=busybox nginx=nginx:1.9.1 命令来更新。
四十九、简述一下deployment的更新过程 (经常问)
deployment是通过控制replicaset来实现,由replicaset真正创建pod副本,每更新一
deployment,都会创建新的replicaset,下面来举例deployment的更新过程:假设要升级一个nginx-deployment的版本镜像为nginx:1.9,deployment的定义滚动更新参数如下:
replicas: 3
deployment.spec.strategy.type: RollingUpdate
maxUnavailable:25%
maxSurge:25%通过计算我们得出,3*25%=0.75,maxUnavailable是向下取整,则maxUnavailable=0,maxSurge是向上取整,则maxSurge=1,所以我们得出在整个deployment升级镜像过程中,不管旧的pod和新的pod是如何创建消亡的,pod总数最大不能超过3+maxSurge=4个,最大pod不可用数3-maxUnavailable=3个。现在具体讲一下deployment的更新升级过程:
使用`kubectl set image deployment/nginx nginx=nginx:1.9 --record` 命令来更新;
1、deployment创建一个新的replaceset,先新增1个新版本pod,此时pod总数为4个,不能再新增了,再新增就超过pod总数4个了;旧=3,新=1,总=4;
2、减少一个旧版本的pod,此时pod总数为3个,这时不能再减少了,再减少就不满足最大pod不可用数3个了;旧=2,新=1,总=3;
3、再新增一个新版本的pod,此时pod总数为4个,不能再新增了;旧=2,新=2,总=4;
4、减少一个旧版本的pod,此时pod总数为3个,这时不能再减少了;旧=1,新=2,总=3;
5、再新增一个新版本的pod,此时pod总数为4个,不能再新增了;旧=1,新=3,总=4;
6、减少一个旧版本的pod,此时pod总数为3个,更新完成,pod都是新版本了;旧=0,新=3,总=3;
五十、deployment的回滚使用什么命令
在升级deployment时kubectl set image 命令加上 --record 参数可以记录具体的升级历史信息,使用kubectl rollout history deployment/deployment-nginx 命令来查看指定的deployment升级历史记录,如果需要回滚到某个指定的版本,可以使用kubectl rollout undo deployment/deployment-nginx --to-revision=2 命令来实现。
五十一、讲一下都有哪些存储卷,作用分别是什么?
卷 | 作用 | 常用场景 |
---|---|---|
emptyDir | 用于存储临时数据的简单空目录 | 一个pod中的多个容器需要共享彼此的数据 ,emptyDir的数据随着容器的消亡也会销毁 |
hostPath | 用于将目录从工作节点的文件系统挂载到pod中 | 不常用,缺点是,pod的调度不是固定的,也就是当pod消失后deployment重新创建一个pod,而这pod如果不是被调度到之前pod的节点,那么该pod就不能访问之前的数据 |
configMap | 用于将非敏感的数据保存到键值对中,使用时可以使用作为环境变量、命令行参数arg,存储卷被pods挂载使用 | 将应用程序的不敏感配置文件创建为configmap卷,在pod中挂载configmap卷,可是实现热更新 |
secret | 主要用于存储和管理一些敏感数据,然后通过在 Pod 的容器里挂载 Volume 的方式或者环境变量的方式访问到这些 Secret 里保存的信息了,pod会自动解密Secret 的信息 | 将应用程序的账号密码等敏感信息通过secret卷的形式挂载到pod中使用 |
secret | 主要用于存储和管理一些敏感数据,然后通过在 Pod 的容器里挂载 Volume 的方式或者环境变量的方式访问到这些 Secret 里保存的信息了,pod会自动解密Secret 的信息 | 将应用程序的账号密码等敏感信息通过secret卷的形式挂载到pod中使用 |
projected | 这是一种特殊的卷,用于将上面这些卷一次性的挂载给pod使用 | 将上面这些卷一次性的挂载给pod使用 |
pvc | pvc是存储卷声明 | 通常会创建pvc表示对存储的申请,然后在pod中使用pvc |
网络存储卷 | pod挂载网络存储卷,这样就能将数据持久化到后端的存储里 | 常见的网络存储卷有nfs存储、glusterfs 卷、ceph rbd存储卷 |
五十二、pv的访问模式有哪几种
pv的访问模式有3种,如下:
ReadWriteOnce,简写:RWO 表示,只仅允许单个节点以读写方式挂载;
ReadOnlyMany,简写:ROX 表示,可以被许多节点以只读方式挂载;
ReadWriteMany,简写:RWX 表示,可以被多个节点以读写方式挂载;
五十三、pv的回收策略有哪几种?
主要有2中回收策略:retain 保留、delete 删除。
Retain:保留,该策略允许手动回收资源,当删除PVC时,PV仍然存在,PV被视为已释放,管理员可以手动回收卷。
Delete:删除,如果Volume插件支持,删除PVC时会同时删除PV,动态卷默认为Delete,目前支持Delete的存储后端包括AWS EBS,GCE PD,Azure Disk,OpenStack Cinder等。
Recycle:回收,如果Volume插件支持,Recycle策略会对卷执行rm -rf清理该PV,并使其可用于下一个新的PVC,但是本策略将来会被弃用,目前只有NFS和HostPath支持该策略。(这种策略已经被废弃,不用记)
五十四、在pv的生命周期中,一般有几种状态
pv一共有4中状态,分别是:
创建pv后,pv的的状态有以下4种:Available(可用)、Bound(已绑定)、Released(已释放)、Failed(失败)
Available,表示pv已经创建正常,处于可用状态;
Bound,表示pv已经被某个pvc绑定,注意,一个pv一旦被某个pvc绑定,那么该pvc就独占该pv,其他pvc不能再与该pv绑定;
Released,表示pvc被删除了,pv状态就会变成已释放;
Failed,表示pv的自动回收失败;
五十五、怎么使一个node脱离集群调度,比如要停机维护但又不能影响业务应用?
要使一个节点脱离集群调度可以使用kubectl cordon <node-name> 命令使节点不可调度,该命令其实背后原理就是给节点打上node-status.kubernets.io/unschedulable污点,这样新的pod如果没有容忍将不会调度到该节点,但是已经存在于该节点的pod仍然可以继续在该节点上运行不受影响,除非pod消忙了被重新调度了。如果需要恢复节点重新调度,可以使用kubectl uncordon <node-name> 命令恢复节点可调度。
如果节点是要停机维护,则可以对节点上的pod 进行驱逐:使用kubectl drain <node-name>命令用于将节点上的pod驱逐出去,以便对节点进行维护。
kubectl drain 命令的语法如下:
kubectl drain <node-name>
--ignore-daemonsets 参数用于忽略由DaemonSet控制器管理的Pods,不加该参数会报错;
--delete-local-data 参数用于在节点上删除所有本地数据,包括PersistentVolume和PersistentVolumeClaim等资源;
--force 参数强制删除pod,默认删除的是ReplicationController, ReplicaSet, Job, DaemonSet 或者StatefulSet创建的Pod,如果有静态pod,则需要设置强制执行删除的参数--force。
kubectl drain 命令背后原理其实还是首先将指定的节点标记为不可调,从而阻止新 pod 分配到节点上(实质上是 kubectl cordon),然后删除pod。
综上所述,要停机维护:
1、kubectl cordon node01 #设置节点不可调度
2、kubectl drain node01 --ignore-daemonsets --force #驱逐pod
3、kubectl uncordon node01 #恢复节点调度
五十六、pv存储空间不足怎么扩容?
一般的,我们会使用动态分配存储资源,在创建storageclass时指定参数 allowVolumeExpansion:true,表示允许用户通过修改pvc申请的存储空间自动完成pv的扩容,当增大pvc的存储空间时,不会重新创建一个pv,而是扩容其绑定的后端pv。这样就能完成扩容了。但是allowVolumeExpansion这个特性只支持扩容空间不支持减少空间。
五十七、k8s生产中遇到什么特别影响深刻的问题吗,问题排查解决思路是怎么样的?(重点)
(此问题被问到的概率高达90%,所以可以自己准备几个自己在生产环境中遇到的问题进行讲解)
答:前端的lb负载均衡服务器上的keepalived出现过脑裂现象。
1、当时问题现象是这样的,vip同时出现在主服务器和备服务器上,但业务上又没受到影响;
2、这时首先去查看备服务器上的keepalived日志,发现有日志信息显示凌晨的时候备服务器出现了vrrp协议超时,所以才导致了备服务器接管了vip;查看主服务器上的keepalived日志,没有发现明显的报错信息,继续查看主服务器和备服务器上的keepalived进程状态,都是running状态的;查看主服务器上检测脚本所检测的进程,其进程也是正常的,也就是说主服务器根本没有成功执行检测脚本(成功执行检查脚本是会kill掉keepalived进程,脚本里面其实就是配置了检查nginx进程是否存活,如果检查到nginx不存活则kill掉keepalived,这样来实现备服务器接管vip);
3、排查服务器上的防火墙、selinux,防火墙状态和selinux状态都是关闭着的;
4、使用tcpdump工具在备服务器上进行抓取数据包分析,分析发现,现在确实是备接管的vip,也确实是备服务器也在对外发送vrrp心跳包,所以现在外部流量应该都是流入备服务器上的vip;
5、怀疑:主服务器上设置的vrrp心跳包时间间隔太长,以及检测脚本设置的检测时间设置不合理导致该问题;
6、修改vrrp协议的心跳包时间间隔,由原来的2秒改成1秒就发送一次心跳包;检测脚本的检测时间也修改短一点,同时还修改检测脚本的检测失败的次数,比如连续检测2次失败才认定为检测失败;
7、重启主备上的keepalived,现在keepalived是正常的,主服务器上有vip,备服务器上没有vip;
8、持续观察:第二天又发现keepalived出现过脑裂现象,vip又同时出现在主服务器和备服务器上,又是凌晨的时候备服务器显示vrrp心跳包超时,所以才导致备服务器接管了vip;
9、同样的时间,都是凌晨,vrrp协议超时;很奇怪,很有理由怀疑是网络问题,询问第三方厂家上层路由器是否禁止了vrrp协议,第三方厂家回复,没有禁止vrrp协议;
10、百度、看官方文档求解;
11、百度、看官网文档得知,keepalived有2种传播模式,一种是组播模式,一种是单播模式,keepalived默认在组播模式下工作,主服务器会往主播地址224.0.0.18发送心跳包,当局域网内有多个keepalived实例的时候,如果都用主播模式,会存在冲突干扰的情况,所以官方建议使用单播模式通信,单播模式就是点对点通行,即主向备服务器一对一的发送心跳包;
12、将keepalived模式改为单播模式,继续观察,无再发生脑裂现象。问题得以解决。
答:测试环境二进制搭建etcd集群,etcd集群出现2个leader的现象。
1、问题现象就是:刚搭建的k8s集群,是测试环境的,搭建完成之后发现,使用kubectl get nodes 显示没有资源,kubectl get namespace 一会能正常显示全部的命名空间,一会又显示不了命名空间,这种奇怪情况。
2、当时经验不是很足,第一点想到的是不是因为网络插件calico没装导致的,但是想想,即使没有安装网络插件,最多是node节点状态是notready,也不可能是没有资源发现呀;
3、然后想到etcd数据库,k8s的资源都是存储在etcd数据库中的;
4、查看etcd进程服务的启动状态,发现etcd服务状态是处于running状态,但是日志有大量的报错信息,日志大概报错信息就是集群节点的id不匹配,存在冲突等等报错信息;
5、使用etcdctl命令查看etcd集群的健康状态,发现集群是health状态,但是居然显示有2个leader,这很奇怪(当初安装etcd的时候其实也只是简单看到了集群是健康状态,然后没注意到有2个leader,也没太关注etcd服务进程的日志报错信息,以为etcd集群状态是health状态就可以了)
6、现在etcd出现了2个leader,肯定是存在问题的;
7、全部检测一遍etcd的各个节点的配置文件,确认配置文件里面各个参数配置都没有问题,重启etcd集群,报错信息仍未解决,仍然存在2个leader;
8、尝试把其中一个leader节点踢出集群,然后再重新添加它进入集群,仍然是报错,仍然显示有2个leader;
9、尝试重新生成etcd的证书,重新颁发etcd的证书,问题仍然存在,仍然显示有2个leader;日志仍是报错集群节点的id不匹配,存在冲突;
10、计算etcd命令的MD5值,确保各个节点的etcd命令是相同的,确保在scp传输的时候没有损耗等等,问题仍未解决;
11、无解,请求同事,架构师介入帮忙排查问题,仍未解决;
12、删除全部etcd相关的文件,重新部署etcd集群,etcd集群正常了,现在只有一个leader,使用命令kubectl get nodes 查看节点,也能正常显示了;
13、最终问题的原因也没有定位出来,只能怀疑是环境问题了,由于是刚部署的k8s测试环境,etcd里面没有数据,所以可以删除重新创建etcd集群,如果是线上环境的etcd集群出现这种问题,就不能随便删除etcd集群了,必须要先进行数据备份才能进行其他方法的处理。
五十八、什么是Kubernetes的Service Account,它有什么用途?
Service Account是Kubernetes中用于访问API服务器的身份凭证。每个Service Account都与一个或多个Secret相关联,这些Secret包含用于身份验证的令牌(token)和证书。
Service Account的主要用途是为运行在集群中的Pod提供API访问权限。与常规用户账户不同,Service Account与特定的命名空间相关联,并且只能在该命名空间内访问资源。这使得Service Account成为管理Pod对API服务器访问权限的便捷方式。
五十九、Kubernetes如何管理持久化存储?
通过Persistent Volumes (PV) 和 Persistent Volume Claims (PVC)。PV代表集群中的一块存储资源,而PVC是用户对存储的请求。Kubernetes自动或手动匹配PV和PVC,实现存储资源的动态分配和回收。
六十、Kubernetes如何实现访问控制和权限管理?
使用Role-Based Access Control (RBAC),通过角色和角色绑定来控制用户或服务账户对资源的操作权限,确保最小权限原则。
Role(角色):Role 定义了一组操作权限的集合,可以授予指定命名空间内的用户或用户组。Role 只能用于授予命名空间内资源的权限,如 Pod、Service、Deployment 等。
RoleBinding(角色绑定):RoleBinding 将 Role 与用户或用户组之间进行绑定,指定了哪些用户或用户组具有特定的权限。一个 RoleBinding 可以将多个用户或用户组与一个 Role 相关联。
ClusterRole(集群角色):ClusterRole 类似于 Role,但作用范围更广泛,可以授予集群范围内资源的权限,如节点、命名空间、PersistentVolume 等。ClusterRole 不限于单个命名空间。
ClusterRoleBinding(集群角色绑定):ClusterRoleBinding 将 ClusterRole 与用户或用户组之间进行绑定,指定了哪些用户或用户组具有特定的集群级别权限。一个 ClusterRoleBinding 可以将多个用户或用户组与一个 ClusterRole 相关联。
六十一、如何确保Kubernetes集群的安全性?
安全措施包括:使用安全网络策略限制Pod间通信,加密通信(如TLS),使用安全的容器运行时,定期安全扫描,管理好Secrets和ConfigMaps,以及启用网络策略和Pod安全策略等。
六十二、在Kubernetes中,你如何管理持久化存储?
在Kubernetes中,管理持久化存储通常使用PersistentVolumes (PV) 和 PersistentVolumeClaims (PVC)。PV是集群中一块可用的网络存储,而PVC是用户存储需求的声明。PVC和PV之间的关系是通过匹配PVC的需求与PV的属性来实现的。
用户通过创建PVC来请求特定大小和访问模式的存储,而集群管理员则负责创建PV,这些PV可以绑定到PVC上以满足用户的存储需求。此外,还可以使用StorageClass来实现动态的存储供应,即当PVC被创建时,会自动根据StorageClass的定义来创建PV。
六十三、描述Kubernetes的亲和性和反亲和性规则,并解释它们如何影响Pod的调度
Kubernetes的亲和性和反亲和性规则用于影响Pod的调度
亲和性 (Affinity):指定Pod倾向于被调度到哪些Node上。这可以通过节点亲和性(基于Node的标签)或Pod亲和性(基于其他Pod的标签)来实现。例如,你可能希望将某些Pod调度到具有特定硬件或特定版本操作系统的节点上。
反亲和性 (Anti-Affinity):指定Pod不应该被调度到哪些Node上。这通常用于确保Pod之间的高可用性。例如,你可以设置反亲和性规则,使得同一服务的Pod不会被调度到同一个节点上,从而防止节点故障导致服务中断。
六十四、Kubernetes中的Ingress是什么,它如何工作?
Ingress是Kubernetes的一个API对象,用于管理外部对集群服务的HTTP和HTTPS访问。它提供了一个外部URL路由到集群内部服务的方式,可以基于域名、路径等规则进行路由。
Ingress控制器负责实现Ingress对象定义的路由规则。当Ingress对象被创建时,Ingress控制器会读取该对象的配置,并根据配置设置路由规则。常见的Ingress控制器有Nginx Ingress Controller、Traefik等。这些控制器会将Ingress规则转换为Nginx、HAProxy或其他负载均衡器的配置,以实现HTTP和HTTPS路由。
六十五、Kubernetes的自动伸缩(Autoscaling)是如何工作的?
Kubernetes支持两种自动伸缩机制:水平伸缩(Horizontal Pod Autoscaling, HPA)和垂直伸缩(Vertical Pod Autoscaling, VPA)。
水平伸缩(HPA):根据Pod的资源使用情况(如CPU、内存)或自定义指标(如应用特定的性能指标)自动增加或减少Pod的副本数量。HPA控制器会定期查询API服务器以获取Pod的资源使用情况,并根据配置的策略进行伸缩操作。
垂直伸缩(VPA):根据Pod的资源使用情况自动调整Pod的资源请求(requests)和限制(limits)。VPA控制器会分析Pod的历史资源使用情况,并预测其未来的资源需求,然后更新Pod的YAML配置文件以实现垂直伸缩。
六十七、Kubernetes中的DaemonSet是什么,它通常用于什么场景?
DaemonSet确保在集群中的每个节点上运行一个Pod的副本。当节点加入集群时,DaemonSet会为其调度一个Pod。当节点从集群中移除时,DaemonSet也会清理该节点上的Pod。DaemonSet通常用于运行集群级别的守护进程,例如存储守护进程、日志收集器、网络插件等。
六十八、Kubernetes中的StatefulSet和Deployment有什么区别?
StatefulSet用于管理有状态的应用程序,例如数据库、分布式存储系统等。StatefulSet提供了稳定的网络标识符、稳定的存储和有序的部署、扩展和删除。与Deployment不同,StatefulSet中的Pod不是完全可替换的,每个Pod都有一个唯一的标识。而Deployment主要用于管理无状态的应用程序,它提供了滚动更新、回滚和扩展等功能。
六十九、Kubernetes中的ConfigMap和Secret如何用于应用程序配置?
ConfigMap和Secret都是Kubernetes中用于存储应用程序配置信息的资源对象。ConfigMap用于存储非敏感的配置信息,如配置文件、环境变量等。Secret则用于存储敏感的配置信息,如密码、密钥等。这些信息可以被挂载到Pod中的容器文件系统中,或者以环境变量的形式注入到容器中,供应用程序使用。
七十、Kubernetes中的准入控制器(Admission Controllers)是什么,它们如何影响集群的行为?
准入控制器是Kubernetes API服务器中的一段代码,用于拦截发送到API服务器的请求,在它们持久化到存储之前进行更改或拒绝。这些控制器允许集群管理员定义并强制执行自定义的策略,以确保请求满足集群的安全性和业务规则。例如,准入控制器可以用于限制对资源的访问、验证Pod的安全配置或实施配额。
七十一、Kubernetes中的CNI是什么,它在集群中的作用是什么?
CNI(容器网络接口)是一个规范,用于定义容器如何连接到网络。在Kubernetes集群中,CNI允许使用各种网络插件来实现Pod之间的网络通信。这些插件负责设置网络接口、分配IP地址、配置路由等。通过使用CNI,Kubernetes可以支持多种网络解决方案,包括Flannel、Calico等。
七十二、Kubernetes中的Ingress是什么?它如何与Service一起工作?
Ingress是Kubernetes的一个API对象,用于管理集群外部对集群内部服务的HTTP和HTTPS路由。Ingress提供了一种集中定义路由规则的方式,使得来自集群外部的请求能够被正确地转发到集群内部的服务上。Ingress需要配合Ingress Controller一起使用,Ingress Controller是一个负责监听Ingress对象并据其配置转发规则的组件。Service是Kubernetes中的另一个API对象,用于为Pod提供稳定的网络访问地址。Ingress通常会将请求转发到某个Service上,再由Service将请求分发到具体的Pod上。
七十三、Kubernetes中的服务发现是如何工作的?
Kubernetes通过DNS和Service资源对象来实现服务发现。当Pod启动时,它会向集群的DNS服务器注册自己的IP地址和主机名。然后,其他Pod可以通过服务名来访问该Pod,DNS服务器会将服务名解析为对应的Pod IP地址。此外,Kubernetes还提供了Service对象来抽象Pod的集合,并为它们提供负载均衡和发现功能。管理员可以创建Service对象来定义服务的名称、端口和选择器等属性,并将它们与Pod关联起来。其他Pod可以通过Service的名称和端口来访问该服务。