Kubernetes Q&A
Kubernetes Q&A
kubernetes 集群规模,使用的版本以及部署方式,master节点跑了什么组件,每个组件的作用?
规模:规模不要超过1000个节点,节点过多的话建议使用多集群的管理方式。
版本:关于版本问题个人有一个建议,那就是按照基数版本或者偶数版本持续升级,例如 1.12-->1.14-->1.16;或者1.13-->1.15-->1.17这样进行升级。尤其是生成环境,不建议频繁的更改和升级。
部署:个人比较推荐使用kubeadm进行部署,结合ansbile进行自动化部署和升级。当然如果本身有一定的go语言开发能力,而且对k8s需要进行源码编译和定制的化,使用二进制部署更佳。
Master:一般master回跑etcd集群、ApiServer、ControllerManager、Scheduler,master节点本身也属于集群中,当然也会跑Kubelet以及Kube-Proxy。
Scheduler工作的原理
根据调度算法将pod调度至最合适的工作节点
- Predicates(预选)--- 输入的是所有节点,输出是满足预选条件的节点。kube-scheduler根据预选策略过滤掉不满足策略的Nodes。如果某节点的资源不足或者不满足预选策略的条件;例如Node的label必须与Pod的selector一致时,则无法通过预选。
- Pirorities(优选)--- 输入是预选阶段筛选出的节点,优选会根据优先策略为通过预选的Nodes进行打分排名,选择得分最高的Node。例如,资源越富裕、负载越小的Node可能具有越高的排名。
Scheduler: 是一个策略丰富、拓扑感知、工作负载特定的功能,调度器显著影响可用性、性能和容量。调度器需要考虑个人和集体资源的资源要求、服务质量要求、硬件/软件/政策约束、亲和力和反亲和力规范、数据局部性、负载间干扰、完成期限等。
kube-scheduler给一个pod做调度选择包含两个步骤:
- 过滤:过滤阶段会将所有满足pod调度需求的node选出来。例如,
PodFitsResources
过滤函数会检查候选Node的可用资源能否满足Pod的资源请求。在过滤后,得出一个node列表,里面包含了所有可调度节点,通常情况下,这个node列表包含不止一个node。如果这个列表是空的,代表这个pod不可被调度。 - 打分: 打分阶段,调度器会为pod从所有可调度节点中选取一个最合适的node。根据当前启用的打分规则,调度器会给每一个可调度节点进行打分。最后kube-scheduler会将pod调度到得分最高的node上。如果存在多个得分最高的node,kube-scheduler会从中随机选取一个。
apiserver工作原理,多少节点对外提供服务,负责均衡高可以用如何实现?
一般情况下,3台apiserver已经够用,如果集群规模较大,apiserver和etcd节点都需要进行扩容。
关于负载:
apiserver服务是一个无状态服务,可以使用Nginx+Keepalived、HAProxy+Keepalived以及云厂商的LB。
受限于云厂商不支持vrrp协议,也可以选择Nginx Local Proxy 这种方式,此种方式不再受限于你的SDN网络环境。也可以避免单节点故障。
关于此种部署方式可参考青木的博客https://qingmu.io/2019/05/17/Deploy-a-highly-available-cluster-with-kubeadm/
contorller-manager和etcd通信吗?
不通信,controller-manager和 scheduler他们都是和kube-apiserver通信,然后kube-apiserver再和etcd通信。将数据存储在etcd集群中。
headless service(无头服务)使用场景
- 不使用ClusterIP,他直接解析到关联的POD
- 当部署有状态应用(statefulset)的副本集时,必须使用headless service
- headless service 的对应的每一个Endopoints,即每一个Pod,都会有对应的DNS域名解析,这样Pod之间就可以互相访问。
k8s集群使用的网络方案,pod如何与node进行网络通信?
k8s网络通信
- 容器间通信: 同一个pod内的多个容器间通信,通过lo
- pod间通信: pod IP <---> pod IP
- Pod与service通信。通过ipvs和iptables进行地址转换
- Service与集群外部客户端的通信 使用Ingress或NodePort
CNI: containers network interface 容器网络接口插件
解决方案:虚拟网桥 多路复用(MACVlan) 硬件交换(SR-IOV)
flannel支持多种后端:
(1): vxlan 包括vxlan 和 Diretrouting
(2)Host-gw: host gateway
(3)UDP
flannel的配置参数:
Network: flannel使用CIDR格式的网络地址,用于为pod配置网络功能 10.244.0.0/16
Subnetlen: 把network切分子网供各个节点使用时,使用多长的掩码进行切分,默认为24位。
Subnetmin: 指定子网从哪一个子网开始 10.244.10.0/24
SubnetMax: 指定子网在哪一个结束 10.244.100.0、24
Backend: vxlan, host-gw, udp
Flannel: 一般情况下使用vxlan技术为各节点创建一个可以互通的Pod网络,使用的端口为UDP8472(需要开放该端口,如公有云AWS等)。flanneld第一次启动时,从etcd获取配置的Pod的网段信息,为本节点分配一个未使用的地址段,然后创建flanneld.1的网络接口,flannel将分配给自己的Pod网段信息写入/run/flannel/subnet.env
文件,docker后续会使用这个文件中的环境变量设置docker0网桥 ,从而从这个地址段为本节点的所有pod容器分配IP。
Calico:在宿主机部署calico作为虚拟路由器,基于BGP协议,生成路由表;容器通过veth pair到达宿主机的网络名称空间上。支持网络策略,且性能较好,复杂度较高。
k8s集群节点需要关机维护,应该怎么操作?
# 驱逐node节点上的pod,并忽略daemonset
$ kubectl drain k8s-node01 --force --ignore-daemonsets
# 关机
$ init 0
Pod的控制器类型,crd需要定义什么?
- Pod控制器: deployment, ReplicationController, StatefulSet, DaemonSet, CronJob, Job
- CRD(CustomResourceDefinition):自定义资源定义,在k8s中一切都可视为资源,kubernetes1.7之后增加了对CRD自定义资源二次开发能力来扩展 kubernetes api,通过CRD我们可以向API中增加新资源类型,而不需要修改kubernetes源码来创建自定义的API server,该功能大大提高了kubernetes的扩展能力。当你创建一个新的CRD时,kubernetes api服务器将为你指定每个版本创建一个新的RESTful资源路径,我们可以根据该api路径来创建一些我们自定义的类型资源。CRD可以是命名空间的,也可以是集群范围的,由CRD的作用域中所指定的,与现有的内置对象一样,删除名称空间将删除该名称空间中的所有自定义对象。CRD本身是没有名称空间的,所有名称空间都可以使用。
存活性监测好就绪性监测的实现方式
readiness probe, liveness probe:HTTP请求 TCP链接 命令行等
Pod如何平滑升级
minReadySeconds: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 30%
maxUnavailable: 30%
k8s内核及文件系统需要哪些设置
- 开启网桥模式
- 禁止使用swap空间
- 开启OOM
- 不检查物理内存是否够用
- 关闭ipv6防止出发docker bug
- 设置系统时区
- 设置HostNmae
- tcp_tw_recycle关闭与k8s的NAT冲突
- 升级内核到4.4+
存储卷的使用方式
- 动态存储使用 storageclass
- 静态存储使用 persistentvolume
对外服务的pod暴露方式有哪些
- hostNetwork: 在pod中使用该配置,在这种pod中运行的应用程序可以直接看到pod启动的主机的网络接口
- hostPort: 直接将容器的端口与所调度的节点上的端口路由,这样用户就可以通过主机的IP来访问Pod
- NodePort:是k8s里一个广泛应用的服务暴露方式。k8s中的service默认情况都是使用ClusterIP这种类型,会产生一个只能在内部访问的ClusterIP,如果想能够直接访问service,需要将service type修改为nodePort。同时给service指定一个nodeport值(30000-32767),用
--service-node-port-range
定义。 - loadBalancer: 只能在service上定义,是公有云提供的负载均衡器。
- Ingress: ingress controller是由k8s管理的负载均衡容器,它一般包含一个nginx 或 Haproxy负载均衡器和一个控制器守护进程。
Traefik实现原理
Traefik 作为一种边缘路由器,能够动态感知后端服务实例变化,进行动态调整并转发配置,会与apiserver进行交互,发现k8s集群内部容器状态变化。
APIServer详解
apiserver对外提供增删改查etcd中资源配置数据,worker节点kubelet同master节点的apiserver进行交互,master节点的scheduler和controller manager组件也需要同api server进行交互以获取和修改对应资源的状态。
apiserver三层认证
kubernetes提供了多种认证方式,比如客户端证书、静态tokern、静态密码文件、ServiceAccountTokens等等。你可以同时使用一种或多种认证方式。只要通过任何一个都被认作认证通过。
- 客户端证书认证:也叫做TLS双向认证,也就是服务器客户端互相验证证书的正确性,在都正确的情况下协调通信加密方案。为了使用这个方案,api-server需要用
-client-ca-file
选项来开启. - 静态token: 当我们有非常多的node节点时,手动为每个node节点配置TLS认证比较麻烦,这时就可以用到引导token的认证方式,前提是需要在api-server 开启
experimental-bootstrap-token-auth
特性,客户端的doken信息与预先定义的token匹配认证通过后,自动为node颁发证书。当然引导token是一种机制,可以用到各种场景中。 - Service Account Tokens 认证: 有些情况下,我们希望pod内部访问api-server,获取集群的信息,甚至对集群进行改动。针对这种情况,kubernetes提供了一种特殊的认证方式,Service Account。Service Account主要包含了三个内容: namespace token和CA。namespace指定了pod所在的namespace ,CA用于验证apiserver的证书,token用作身份验证。他们都通过mount的方式保存在pod的文件系统中。
Kubernetes授权
在kubernetes1.6以及之后的版本中,新增了角色访问控制机制(Role-Based Acess, RBAC)让集群管理员可以针对特定使用者或服务账号角色,进行更精准的资源访问控制。在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。在一个组织中,角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色。
Kubernetes 准入控制
(AdmissionControl)准入控制本质上为一段准入代码,在对kubernetes api的请求过程中,顺序为:先经过认证&授权,然后执行准入操作,最后对目标对象进行操作。这个准入代码在api-server中,而且必须被编译到二进制文件中才能被执行。
在对集群进行请求时,每个准入控制代码都按照一定顺序执行。如果有一个准入控制拒绝了此次请求,那么整个请求的结果将会立即返回,并提示用户相应的EROOR信息。常用的控制代码如下:
- AlwaysAdmit: 允许所有请求
- AlwaysDeny: 禁止所有请求,多用于测试环境
- ServiceAccount: 它将serviceAccounts实现了自动化,它会辅助ServiceAccount做一些事情,比如pod没有ServiceAccount属性,它会自动添加一个default,并确保POD的ServiceAccount始终存在。
- LimitRanger: 它会观察所有的请求,确保没有违反已经定义好的约束条件,这系统条件定义在namespace中的LimitRanger对象中。如果在kubernetes中使用LimitRanger对象,则必须使用这个插件。
- NamespaceExists: 它会观察所有的请求,如果请求尝试创建一个不存在的namespace,则这个请求被拒绝。
Controller Manager
Controller Manager
: 以守护进程的形式运行着kubernetes几个核心的控制循环(也就是控制器),包括deployment
、replicaset
、namespace
、serviceaccount
、node
等等,通过调用Api Server的 list watch接口来监控自己负责的资源的配置变化。
ETCD 分布式的K-V存储系统
- HTTP Server(Grpc Server):主要处理client(客户端)的操作请求以及节点间的数据同步和心跳保持。
- raft状态机:通过对raft一致性协议的实现来保证etcd集群的高可用性。
- store:负责Etcd中事务操作的逻辑,是api server的命令的具体实现。
- wal存储:负责具体的数据持久存储操作。它分为两部分,entry负责实际的日志数据存储(在etcd里数据的存储都是带版本号的,对于同一个键值可能会有多个版本的记录存在,所以数据实际的存储方式即通过事务日志进行存储,而在内存里则存有键和版本号的映射关系以方便查询)。Snapshot则是对日志数据的状态存储以防止过多的数据存在。
etcd集群的备份
$ ETCDCTL_API=3 etcdctl --cacert="${CACERT}" --cert="${CERT}" --key="${KEY}" \
--endpoints=${ENDPOINTS} \
snapshot save /data/etcd_backup_dir/etcd-snapshot-`date +%Y%m%d`.db