kubernetes相关知识----突击面试

目录

1、k8s架构及各组件的功能

2、deployments和Stateful Sets拉起的pod有什么不同,回收有什么不同?

3、pod滚动更新的策略

4、pod网络插件(flannel、openswitch、calico),为什么用覆盖网络,overlay underlay

1.Flannel

1) VxLAN: 

2) host-GW:

3) UDP:

2.Calico

Calico的工作流程

Calico的两种网络方式

Calico的优缺点

3.Openswitch

ovs架构

Docker0网络

网络划分

5、pod启动过程

6、POD删除过程

7、优雅退出方案(主动退出)

8、就绪探针、存活探针区别

9、informer机制

List-Watch 机制

informer模块

 Watch 是如何实现的

10、pod生命周期结合钩子

11、k8s声明式api

12、CRI  CNI  CSI

CRI(Container Runtime Interface):容器运行时接口,提供计算资源 

CNI(Container Network Interface):容器网络接口,提供网络资源

CSI(Container Storage Interface):容器存储接口,提供存储资源

13、qos分级,系统怎么打分

14、调度策略

15、为什么设计pod,pod有什么好处

16、CRD

17、operator编程实践

18、ingress(router)

19、iptables和ipvs的区别

20、权限管理

ServiceAccount

RBAC(基于角色的访问控制)

Role(角色)

ClusterRole(集群角色)

RoleBinding(角色绑定)和ClusterRoleBinding(集群角色绑定)

1、k8s架构及各组件的功能


Master节点主要包括API Server、Scheduler、Controller manager、etcd几大组件

Node节点主要包括kubelet、kube-proxy模块和pod对象

API Server :提供其他模块之间的数据交互和通信的枢纽,其他模块通过API Server查询或修改数据,只有API Server才直接和etcd进行交互。

Scheduler: 负责对集群内部的资源进行调度,相当于“调度室”。接收来自kube-apiserver创建Pods的任务,收到任务后它会通过预选策略和优选策略检索出所有符合该Pod要求的Node节点,开始执行Pod调度逻辑。调度成功后将Pod绑定到目标节点上。

预选策略(Predicate)
  1. 根据运行Pod的资源限制来排除不符合要求的Node
  2. 根据运行Pod时,是否要求共享宿主机的网络名称空间来判断,如: 某Pod启动要共享宿主机的网络名称空间,启动80端口,而某些Node的80已经被占用,那它就不符合,就也要不排除。
优选策略(Priority):
  此阶段会经过一系列函数,会把预选出来的节点的相关属性都输入到这些函数中,通过计算来获取每个节点的优先分值,然后在倒序排序,取得分最高者,作为运行Pod的节点,若计算后,发现有多个Node得分相同,此时将随机选取一个Node作为该Pod运行的Node。

Controller manager:负责集群内 Node、Namespace、Service、Token、Replication 等资源对象的管理,使集群内的资源对象维持在预期的工作状态。每一个 controller 通过 api-server 提供的 restful 接口实时监控集群内每个资源对象的状态,当发生故障,导致资源对象的工作状态发生变化,就进行干预,尝试将资源对象从当前状态恢复为预期的工作状态,常见的 controller 有 Namespace Controller、Node Controller、Service Controller、ServiceAccount Controller、Token Controller、ResourceQuote Controller、Replication Controller等。

Etcd:etcd在kubernetes集群是用来存放数据并通知变动的,它把关键数据都存放在etcd中。

Pod:Pod是Kubernetes最基本的操作单元。一个Pod代表着集群中运行的一个进程,它内部封装了一个或多个紧密相关的容器。

Kubelet:运行在每个计算节点上,kubelet 组件通过 api-server 提供的接口监测pod 的期望状态,并调用对应的接口达到这个状态。同时监视分配给该Node节点的 pods,周期性获取容器状态,定时汇报给api-server,再通过api-server通知各个组件。还负责镜像和容器清理工作

kube-proxy:kube-proxy 会作为 daemon(守护进程) 跑在每个节点上通过watch的方式监控着etcd中关于Pod的最新状态信息,它一旦检查到一个Pod资源被删除了或新建或ip变化了等一系列变动,它就立即将这些变动,反应在iptables 或 ipvs规则中,以便之后 再有请求发到service时,service收到请求后会根据kube-proxy制定好的策略来进行请求的转发,从而实现负载均衡。

2、deployments和Stateful Sets拉起的pod有什么不同,回收有什么不同?
Deployments部署无状态的服务

Stateful Sets部署有状态的服务

StatefulSet,Pod 部署时是按照 {0 …… N-1} 的序号顺序创建的。

StatefulSet 中的 Pod 拥有一个唯一的顺序索引和稳定的网络身份标识。

删除时按照与 Pod 序号索引相反的顺序每次删除一个 Pod。在删除下一个 Pod 前会等待上一个被完全关闭。

3、pod滚动更新的策略
在Deployment的YAML定义文件中,由spec.strategy.type字段指定Pod的滚动更新策略,它有两个可选值:

RollingUpdate (默认值):逐步创建新的Pod,同时逐步终止旧Pod,用新Pod替换旧Pod。

Recreate:在创建新Pod前,所有旧Pod必须全部终止

使用RollingUpdate策略时,还有两个选项可以让你微调更新过程:

maxSurge:在更新期间,允许创建超过期望状态定义的Pod数的最大值。

maxUnavailable:在更新期间,容忍不可访问的Pod数的最大值

Pod已经完全部署好了将会把Pod标记为Ready,创建中的Pod标记为NotReady,正在被删除的Pod标记为Terminating。

4、pod网络插件(flannel、openswitch、calico),为什么用覆盖网络,overlay underlay
K8s的网络大体可以分为两类,一类是覆盖网络,一类是直接路由。

覆盖网络就是在原始报文外再包一层四层协议(udp协议),通过主机网络进行路由转发。

直拉路由就是通过路由表控制下一跳的IP地址来实现。

Kubernetes系统上Pod网络的实现依赖于第三方插件,常见的有三种Flannel、Calico、Openvswitch

1.Flannel
flannel的工作方式有3种,默认是VXLAN模式。flanneld需要依赖etcd来保证集群IP分配不冲突的问题。

1) VxLAN: 
        VXLAN是Linux内核本身支持的一种网络虚拟化技术,是内核的一个模块,在内核态实现封装解封装,构建出覆盖网络,其实就是一个由各宿主机上的Flannel.1设备组成的虚拟二层网络。


2) host-GW:
        这种方式是宿主机内Pod通过虚拟网桥互联,然后将宿主机的物理网卡作为网关,当需要访问其它Node上的Pod时,只需要将报文发给宿主机的物理网卡,由宿主机通过查询本地路由表,来做路由转发,实现跨主机的Pod通信,这种模式带来的问题时,当k8s集群非常大时,会导致宿主机上的路由表变得非常巨大,而且这种方式,要求所有Node必须在同一个二层网络中,否则将无法转发路由。

3) UDP:
        核心就是通过TUN设备flannel0实现(TUN设备是工作在三层的虚拟网络设备,功能是:在操作系统内核和用户应用程序之间传递IP包)

相比两台宿主机直接通信,多出了flanneld的处理过程,这个过程,使用了flannel0这个TUN设备,仅在发出IP包的过程中就要经过了三次用户态到内核态的数据拷贝(linux的上下文切换代价比较大),所以性能非常差。

2.Calico
calico的基本组件有etcd、felix、BGP Client、BIDR(bgp route reflector).

Etcd:分布式键值存储,主要负责网络元数据一致性。

Felix:跑在每个节点上,主要负责配置路由及 ACLs(包过滤技术)等信息来确保 endpoint 的连通状态。

BIDR(bgp route reflector)主要负责把 Felix 写入 kernel 的路由信息分发到当前 Calico 网络

Calico的工作流程
Felix会监听ECTD中心的存储,从中获取事件。比如说用户在一台机器上创建一个pod,Felix会将其网卡、IP、MAC都设置好,然后在内核的路由表里面写一条,注明这个IP应该到这张网卡。然后通过标准BGP的路由协议扩散到整个其他的宿主机上,让外界都知道这个IP在这里,你们路由的时候得到这里来。

Calico的两种网络方式
1)IPIP
从字面来理解,就是把一个IP数据包又套在一个IP包里,即把 IP 层封装到 IP 层的一个 tunnel,它的作用其实基本上就相当于一个基于IP层的网桥!一般来说,普通的网桥是基于mac层的,根本不需 IP,而这个 ipip 则是通过两端的路由做一个 tunnel,把两个本来不通的网络通过点对点连接起来。ipip 的源代码在内核 net/ipv4/ipip.c 中可以找到。

2)BGP
边界网关协议(Border Gateway Protocol, BGP)是互联网上一个核心的去中心化自治路由协议。它通过维护IP路由表或‘前缀’表来实现自治系统(AS)之间的可达性,属于矢量路由协议。BGP不使用传统的内部网关协议(IGP)的指标,而使用基于路径、网络策略或规则集来决定路由。因此,它更适合被称为矢量性协议,而不是路由协议。BGP,通俗的讲就是讲接入到机房的多条线路(如电信、联通、移动等)融合为一体,实现多线单IP,BGP 机房的优点:服务器只需要设置一个IP地址,最佳访问路由是由网络上的骨干路由器根据路由跳数与其它技术指标来确定的,不会占用服务器的任何系统。

Calico的优缺点
IPIP网络:适用于互相访问的Pod不在同一个网段中,跨网段访问的场景,外层封装的IP能够解决跨网段的路由问题。流量需要tunl0设备封装,效率略低
BGP网络:适用于互相访问的Pod在同一个网段,原生hostGW,效率高。过多的 iptables 规则造成复杂性和不可调试性,同时也存在性能损耗。

3.Openswitch
OpenvSwitch简称OVS,OVS是一个高质量、多层的虚拟交换软件。它的目的是通过编程扩展支持大规模网络自动化,同时还支持标准的管理接口和协议。

简单来看,OVS由这三大部分构成

ovsdb-sever: OVS的数据库服务器,用来存储虚拟交换机的配置信息。它与manager和ovs-vswitchd交换信息使用了OVSDB(JSON-RPC)的方式。

ovs-vswitchd: OVS的核心部件,它和上层controller通信遵从openflow协议,它与ovsdb-server通信使用OVSDB协议,它和内核模块通过netlink通信,它支持多个独立的datapath(网桥),它通过更改flow table实现了绑定,和VLAN等功能。

ovs kernel module: OVS的内核模块,处理包交换和隧道,缓存flow,如果在内核的缓存中找到转发规则则转发,否则发向用户空间去处理。

ovs架构
在k8s、Docker场景下,主要是建立L3到L3的隧道,首先,为了避免Docker创建的docker0地址产生冲突,我们需要手动配置和指定下各个Node节点上docker0网桥的地址段分布。
其次,建立Open vSwitch的网桥ovs,然后使用ovs-vsctl命令给ovs网桥增加gre端口,添加gre端口时要将目标连接的NodeIP地址设置为对端的IP地址。对每一个对端IP地址都需要这么操作(对于大型网络,需要做自动化脚本来完成)。
最后,将ovs的网桥作为网络接口,加入Docker的网桥上。重启ovs网桥和Docker的网桥,并添加一个Docker的地址段到Docker网桥的路由规则项,就可以将两个容器的网络连接起来了。

容器内的应用访问另一个容器的地址时,数据包会通过容器内的默认路由发送给docker0网桥。ovs的网桥是作为docker0网桥的端口存在的,安会将数据发送给ovs网桥。ovs网络已经通过配置建立了和其他ovs网桥的GRE/VxLAN隧道,自然能将数据送达对端的Node,并送往docker0及Pod。

此模式是使用docker的网络,通过docker启动

通过openshift创建的POD是直连OVS的br0网桥的

Docker0网络
Docker启动的时候会在主机上自动创建一个docker0网桥,实际上是一个网桥,所有容器的启动如果在docker run的时候没有指定网络模式的情况下都会挂载到docker0网桥上。这样容器就可以和主机甚至是其他容器之间通讯了。

每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0桥接模式,使用的技术是veth-pair技术, 每启动一个容器,就会多了一块网卡。

(十四)Docker0网络详解_Bertram的博客-CSDN博客_docker0

docker0 网桥会默认使用172.17.0.0/16网段。

使用docker network ls可以查看docker的网络

网络划分
openshift在安装时会在/etc/ansible/hosts中设置两个参数

osm_cluster_network_cidr=10.1.0.0/16

osm_host_subnet_length=9(未显式定义,默认值为9)

osm_cluster_network_cidr 定义SDN网络CIDR,用于分配POD网络

osm_host_subnet_length 定义SDN分配主机子网时的长度

例如如上两参数,则:

可分配POD IP:10.1.0.1-10.1.255.254,可用IP数,2^(32-16)-2=65534个

可分配子网(集群node节点数)=2^(32-16-9)=128

每个节点可分配POD IP数 2^9=512个

openshift_portal_net:k8s的service 会在这个子网中创建,默认值为172.30.0.0/16

 具体配置参考:4.2. 配置集群变量 OpenShift Container Platform 3.11 | Red Hat Customer Portal

在openshift中,可以用命令oc get hostsubnet命令查看每个节点分配的网段

kubelet调用k8s的api接口获取节点网段,然后将参数传给CNI接口,CNI接口传给IPAM,IPAM通过local-host插件获取IP返回给CNI,然后给POD设置IP

节点已分配IP可在/var/lib/cni/networks/openshift-sdn目录下查看

5、pod启动过程
1、客户端提交创建请求,可以通过API Server的Restful API,也可以使用kubectl命令行工具。支持的数据类型包括JSON和YAML。

2、API Server处理用户请求,存储Pod数据到etcd。

3、调度器通过API Server查看未绑定的Pod。尝试为Pod分配主机。

4、过滤主机 (调度预选):调度器用一组规则过滤掉不符合要求的主机。比如Pod指定了所需要的资源量,那么可用资源比Pod需要的资源量少的主机会被过滤掉。

5、主机打分(调度优选):对第一步筛选出的符合要求的主机进行打分,在主机打分阶段,调度器会考虑一些整体优化策略,比如把容一个Replication Controller的副本分布到不同的主机上,使用最低负载的主机等。

6、选择主机:选择打分最高的主机,进行binding操作,结果存储到etcd中。

7、kubelet根据调度结果执行Pod创建操作: 绑定成功后,scheduler会调用APIServer的API在etcd中创建一个boundpod对象,描述在一个工作节点上绑定运行的所有pod信息。运行在每个工作节点上的kubelet也会定期与etcd同步boundpod信息,一旦发现应该在该工作节点上运行的boundpod对象没有更新,则调用Docker API创建并启动pod内的容器。

 kubelet 通过 API Server 监听 etcd 目录,同步 pod 列表。如果发现有新的 pod 绑定到本节点,则按照 pod 清单要求创建 pod,如果是发现 pod 被更新,则做出相应更改。读取到 pod 的信息之后,如果是创建和修改 pod 的任务,则做如下处理:
1、为该 pod 创建一个数据目录
2、从 API Server 读取该 pod 清单
3、为该 pod 挂载外部卷
4、下载 pod 所需的 Secret
5、检查已经运行在节点中 pod,如果该 pod 没有容器或者 Pause 容器没有启动,则先停止pod里所有的容器进程。
6、使用 pause 镜像为每个pod创建一个容器,该容器用于接管 Pod 中所有其他容器的网络。
7、为 pod 中的每个容器做如下处理:为容器计算一个 hash 值,然后用容器的名字去查询对于 docker 容器的 hash 值。若查找到容器,且两者的 hash 值不同,则停止 docker 中容器中进程,并停止与之关联的 pause 容器,若相同,则不做处理。若容器被终止了,且容器没有指定的重启策略,则不做任何处理调用 docker client 下载容器镜像,并启动容器。

图解kubernetes Pod创建流程大揭秘_Kubernetes中文社区

6、POD删除过程
大体流程如下:kubernetes源码分析-pod删除流程_hahachenchen789的博客-CSDN博客_k8s删除pod流程

7、优雅退出方案(主动退出)
        优雅停止(Graceful shutdown)这个说法来自于操作系统,我们执行关机之后都得 OS 先完成一些清理操作,而与之相对的就是硬中止(Hard shutdown),比如拔电源。

        到了分布式系统中,优雅停止就不仅仅是单机上进程自己的事了,往往还要与系统中的其它组件打交道。比如说我们起一个微服务,网关把一部分流量分给我们,这时:

假如我们一声不吭直接把进程杀了,那这部分流量就无法得到正确处理,部分用户受到影响。不过还好,通常来说网关或者服务注册中心会和我们的服务保持一个心跳,过了心跳超时之后系统会自动摘除我们的服务,问题也就解决了;这是硬中止,虽然我们整个系统写得不错能够自愈,但还是会产生一些抖动甚至错误;
假如我们先告诉网关或服务注册中心我们要下线,等对方完成服务摘除操作再中止进程,那不会有任何流量受到影响;这是优雅停止,将单个组件的启停对整个系统影响最小化;
        按照惯例,SIGKILL 是硬终止的信号,而 SIGTERM 是通知进程优雅退出的信号,因此很多微服务框架会监听 SIGTERM 信号,收到之后去做反注册等清理操作,实现优雅退出.

        除了把 Pod 从 k8s 的 Service 上摘下来以及进程内部的优雅退出之外,我们还必须做一些额外的事情,比如说从 k8s 外部的服务注册中心上反注册。这时就要用到 PreStop hook 了,k8s 目前提供了 Exec 和 HTTP 两种 PreStop hook,实际用的时候,需要通过 Pod的 .spec.containers[].lifecycle.preStop 字段为 Pod 中的每个容器单独配置,比如:

spec:
  contaienrs:
  - name: my-awesome-container
    lifecycle:
      preStop:
        exec:
          command: ["/bin/sh","-c","/pre-stop.sh"]
/pre-stop.sh 脚本里就可以写我们自己的清理逻辑,大体步骤如下:

1.用户删除 Pod
2.Pod 进入 Terminating 状态;
3.与此同时,k8s 会将 Pod 从对应的 service 上摘除;
4.与此同时,针对有 preStop hook 的容器,kubelet 会调用每个容器的 preStop hook,假如 preStop hook 的运行时间超出了 grace period(默认是 30 秒),kubelet 会发送 SIGTERM 并再等 2 秒;
5.与此同时,针对没有 preStop hook 的容器,kubelet 发送 SIGTERM
6.grace period 超出之后,kubelet 发送 SIGKILL 干掉尚未退出的容器
8、就绪探针、存活探针区别
就绪探针 Readiness Probe决定是否向POD发送流量

存活探针 Liveness Probe决定是否重启POD

9、informer机制
Etcd存储集群的数据信息,apiserver作为统一入口,任何对数据的操作都必须经过apiserver。客户端(kubelet/scheduler/controller-manager)通过list-watch监听apiserver中资源(pod/rs/rc等等)的create,update和delete事件,并针对事件类型调用相应的事件处理函数。

List-Watch 机制
那么list-watch具体是什么呢,顾名思义,list-watch有两部分组成,分别是list和watch。list非常好理解,就是调用资源的list API罗列资源,基于HTTP短链接实现;watch则是调用资源的watch API监听资源变更事件,基于HTTP 长链接实现

例如List 的API:GET /api/v1/pods

WATCH的API:GET /api/v1/watch/pods

informer模块
K8S的informer模块封装list-watch API,用户只需要指定资源,编写事件处理函数,AddFunc,UpdateFunc和DeleteFunc等。如下图所示,informer首先通过list API罗列资源,然后调用watch API监听资源的变更事件,并将结果放入到一个FIFO 队列,队列的另一头有协程从中取出事件,并调用对应的注册函数处理事件。Informer还维护了一个只读的Map Store缓存,主要为了提升查询的效率,降低apiserver的负载。

 Watch 是如何实现的
Watch通过HTTP 长链接接收apiserver发来的资源变更事件,主要实现方式是通过Chunked transfer encoding(分块传输编码)

当客户端调用watch API时,apiserver 在response的HTTP Header中设置Transfer-Encoding的值为chunked,表示采用分块传输编码,客户端收到该信息后,便和服务端该链接,并等待下一个数据块,即资源的事件信息。例如:

$ curl -i http://{kube-api-server-ip}:8080/api/v1/watch/pods?watch=yes
HTTP/1.1 200 OK
Content-Type: application/json
Transfer-Encoding: chunked
Date: Thu, 02 Jan 2019 20:22:59 GMT
Transfer-Encoding: chunked
 
{"type":"ADDED", "object":{"kind":"Pod","apiVersion":"v1",...}}
{"type":"ADDED", "object":{"kind":"Pod","apiVersion":"v1",...}}
{"type":"MODIFIED", "object":{"kind":"Pod","apiVersion":"v1",...}}
理解 K8S 的设计精髓之 List-Watch机制和Informer模块 - 知乎

10、pod生命周期结合钩子
k8s提供了生命周期钩子,也就是Pod Hook,Pod Hook 是由 kubelet 发起的,当容器中的进程启动前或者容器中的进程终止之前运行,这是包含在容器的生命周期之中。

Kubernetes 提供了两种钩子函数:

PostStart:这个钩子在容器创建后立即执行。但是,并不能保证钩子将在容器ENTRYPOINT之前运行,因为没有参数传递给处理程序。主要用于资源部署、环境准备等。不过需要注意的是如果钩子花费太长时间以至于不能运行或者挂起, 容器将不能达到running状态。(PostStart 可以在容器启动之后就执行。但需要注意的是,此 hook 和容器里的 ENTRYPOINT 命令的执行顺序是不确定的。)
PreStop:这个钩子在容器终止之前立即被调用。它是阻塞的,意味着它是同步的, 所以它必须在删除容器的调用发出之前完成。主要用于优雅关闭应用程序、通知其他系统等。如果钩子在执行期间挂起, Pod阶段将停留在running状态并且永不会达到failed状态,PreStop 则在容器被终止之前被执行,是一种阻塞式的方式。执行完成后,Kubelet 才真正开始销毁容器。
如果PostStart或者PreStop钩子失败, 它会杀死容器。所以我们应该让钩子函数尽可能的轻量。当然有些情况下,长时间运行命令是合理的, 比如在停止容器之前预先保存状态。

spec:
  contaienrs:
  - name: my-awesome-container
    lifecycle:
      preStop:
        exec:
          command: ["/bin/sh","-c","/pre-stop.sh"]
11、k8s声明式api
对于我们使用 Kubernetes API 对象的方式,一般会编写对应 API 对象的 YAML 文件交给 Kubernetes(而不是使用一些命令来直接操作 API)。所谓“声明式”,指的就是只需要提交一个定义好的 API 对象来“声明”(这个 YAML 文件其实就是一种“声明”),表示所期望的最终状态是什么样子就可以了。而如果提交的是一个个命令,去指导怎么一步一步达到期望状态,这就是“命令式”了。

一个 API 对象在 Etcd 里的完整资源路径,是由:Group(API组)、Version(API版本)和 Resource(API资源类型)三个部分组成的。

12、CRI  CNI  CSI
CRI(Container Runtime Interface):容器运行时接口,提供计算资源 
CRI中定义了容器和镜像的服务的接口,因为容器运行时与镜像的生命周期是彼此隔离的,因此需要定义两个服务。

RuntimeService:容器和Sandbox运行时管理
ImageService:提供了从镜像仓库拉取、查看、和移除镜像的RPC。


CNI(Container Network Interface):容器网络接口,提供网络资源
CNI是CNCF旗下的一个项目,由一组用于配置Linux容器的网络接口的规范和库组成,同时还包含了一些插件。CNI仅关心容器创建时的网络分配,和当容器被删除时释放网络资源。

CNI的接口中包括以下几个方法:添加网络、删除网络、添加网络列表、删除网络列表。

type CNI interface {
    AddNetworkList(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
    DelNetworkList(net *NetworkConfigList, rt *RuntimeConf) error
 
    AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
    DelNetwork(net *NetworkConfig, rt *RuntimeConf) error

CSI(Container Storage Interface):容器存储接口,提供存储资源
K8S将存储体系抽象出了外部存储组件接口,也就是CSI,通过grpc接口对外提供服务。第三方存储厂商可以发布和部署公开的存储插件,而无需接触K8S核心代码。

13、qos分级,系统怎么打分
QoS(Quality of Service),大部分译为 “服务质量等级”,又译作 “服务质量保证”,k8s创建一个 Pod 时,它就会给这个 Pod 分配一个 QoS 等级,可以是以下等级之一:

Guaranteed:Pod 里的每个容器都必须有内存/CPU 限制和请求,而且值必须相等。如果一个容器只指明limit而未设定request,则request的值等于limit值。

Burstable:Pod 里至少有一个容器有内存或者 CPU 请求且不满足 Guarantee 等级的要求,即内存/CPU 的值设置的不同。

BestEffort:容器必须没有任何内存或者 CPU 的限制或请求。

该配置不是通过一个配置项来配置的,而是通过配置 CPU/MEM的 limits 与 requests 值的大小来确认服务质量等级。

三种 QoS 优先级:Guaranteed --> Burstable --> BestEffort

Kubernetes 资源回收策略:当集群监控到 node 节点内存或者CPU资源耗尽时,为了保护node正常工作,就会启动资源回收策略,通过驱逐节点上Pod来减少资源占用。

三种 QoS 策略被驱逐优先级,从高到低(从左往右)

BestEffort --> Burstable --> Guaranteed

14、调度策略
API Server接受客户端提交Pod对象创建请求后的操作过程中,有一个重要的步骤就是由调度器程序kube-scheduler从当前集群中选择一个可用的最佳节点来接收并运行它,通常是默认的调度器kube-scheduler负责执行此类任务。对于每个待创建的Pod对象来说,调度过程通常分为两个阶段—》过滤—》打分,过滤阶段用来过滤掉不符合调度规则的Node,打分阶段建立在过滤阶段之上,为每个符合调度的Node进行打分,分值越高则被调度到该Node的机率越大。

Pod调度策略除了系统默认的kube-scheduler调度器外还有以下几种实现方式:

nodeName(直接指定Node主机名)
nodeSelector (节点选择器,为Node打上标签,然后Pod中通过nodeSelector选择打上标签的Node)
污点taint与容忍度tolerations
NodeAffinity 节点亲和性
PodAffinity Pod亲和性
PodAntAffinity Pod反亲和性
这应该是最全的Pod调度策略 - 知乎

15、为什么设计pod,pod有什么好处
        试想这样一个场景,我们通过docker启动一个容器为tomcat,在启动一个容器为mysql,这样一组具有关联性的容器对外通过ip+port的方式对外提供服务。假设mysql容器的原因,容器死亡 。那么我们无法很快的在感知到服务是否正常。同时,假设tomacat想要访问mysql,在容器化时代,我么必须将mysql的ip通过环境变量注入的方式注入tomcat容器,并将tomcat容器的端口映射到主机端口,以便外界能够访问。

        通过pod这样包含多个容器的设计模式,在pod中启动两个容器myql以及tomcat,那么我么可以用pod的live or death来很快判定该pod包含的2个关联进程的正常与死亡。此时pod内部对于运维开发人员来讲,是一个黑盒子,我们无需直接关注pod内部发生了什么,而只需要关注pod是否正常即可。同时pod设计之初,pause容器的引入,可以很方便的解决多个业务容器之间的ip通信以及文件共享问题,解决了多node下容器通信的问题。

16、CRD
        在 Kubernetes 中一切都可视为资源,Kubernetes 1.7 之后增加了对 CRD 自定义资源二次开发能力来扩展 Kubernetes API,通过 CRD 我们可以向 Kubernetes API 中增加新资源类型,而不需要修改 Kubernetes 源码来创建自定义的 API server,该功能大大提高了 Kubernetes 的扩展能力。
        当你创建一个新的CustomResourceDefinition (CRD)时,Kubernetes API服务器将为你指定的每个版本创建一个新的RESTful资源路径,我们可以根据该api路径来创建一些我们自己定义的类型资源。CRD可以是命名空间的,也可以是集群范围的,由CRD的作用域(scpoe)字段中所指定的,与现有的内置对象一样,删除名称空间将删除该名称空间中的所有自定义对象。customresourcedefinition本身没有名称空间,所有名称空间都可以使用。

通过crd资源创建自定义资源,即自定义一个Restful API:

$ vi resourcedefinition.yaml:

apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  # 名称必须与下面的spec字段匹配,格式为: <plural>.<group>
  name: crontabs.stable.example.com
spec:
  # 用于REST API的组名称: /apis/<group>/<version>
  group: stable.example.com
  # 此CustomResourceDefinition支持的版本列表
  versions:
    - name: v1
      # 每个版本都可以通过服务标志启用/禁用。
      served: true
      # 必须将一个且只有一个版本标记为存储版本。
      storage: true
  # 指定crd资源作用范围在命名空间或集群
  scope: Namespaced
  names:
    # URL中使用的复数名称: /apis/<group>/<version>/<plural>
    plural: crontabs
    # 在CLI(shell界面输入的参数)上用作别名并用于显示的单数名称
    singular: crontab
    # kind字段使用驼峰命名规则. 资源清单使用如此
    kind: CronTab
    # 短名称允许短字符串匹配CLI上的资源,意识就是能通过kubectl 在查看资源的时候使用该资源的简名称来获取。
    shortNames:
    - ct
创建自定义contab资源
$ kubectl create -f resourcedefinition.yaml
然后在以下位置创建一个新的带有名称空间的RESTful API端点:
/apis/stable.example.com/v1/namespaces/*/crontabs/...然后我们可以使用该url来创建和管理自定义对象资源。
查看自定义contab资源的信息
$ kubectl get contab/ct
1.2、创建自定义资源的对象:

根据crd对象资源创建出来的RESTful API,来创建crontab类型资源对象
$ vi my-crontab.yaml:

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "* * * * */5"
  image: my-awesome-cron-image
在创建CustomResourceDefinition对象之后,我们可以创建定制资源的对象。自定义对象可以包含自定义字段。这些字段可以包含任意JSON。上面的例子中cronSpec和image自定义字段设置在CronTab类型的自定义对象中。CronTab类型来自您在上面创建的CustomResourceDefinition对象的规范。

创建自定义资源contab资源的对象
$ kubectl create -f my-crontab.yaml
Kuberneters(K8s)CRD资源详解 - 简书

17、operator编程实践
        operator 是一种 kubernetes 的扩展形式,利用自定义资源对象(Custom Resource)来管理应用和组件,允许用户以 Kubernetes 的声明式 API 风格来管理应用及服务。operator 定义了一组在 Kubernetes 集群中打包和部署复杂业务应用的方法,operator主要是为解决特定应用或服务关于如何运行、部署及出现问题时如何处理提供的一种特定的自定义方式。

十分钟弄懂 k8s Operator 应用的制作流程 - 知乎

18、ingress(router)
        k8s 对外暴露服务(service)主要有两种方式:NotePort, LoadBalance, 此外externalIPs也可以使各类service对外提供服务,但是当集群服务很多的时候,NodePort方式最大的缺点是会占用很多集群机器的端口;LB方式最大的缺点则是每个service一个LB又有点浪费和麻烦,并且需要k8s之外的支持; 而ingress则只需要一个NodePort或者一个LB就可以满足所有service对外服务的需求。工作机制大致可以用下图表示:

Ingress包含了两大主件Ingress Controller和Ingress。

Ingress解决的是新的服务加入后,域名和服务的对应问题,基本上是一个ingress的对象,通过yaml进行创建和更新进行加载。

Ingress Controller是将Ingress这种变化生成一段Nginx的配置,然后将这个配置通过Kubernetes API写到Nginx的Pod中,然后reload.(注意:写入 nginx.conf 的不是service的地址,而是service backend 的 pod 的地址,避免在 service 在增加一层负载均衡转发)

 k8s 对外服务之ingress_yrx420909的博客-CSDN博客_ingress k8s

k8s 的ingress在OpenShift称为Route,基于HAProxy的Ingress Controller来实现外部入栈请求的流量路由,运行在infra节点。

19、iptables和ipvs的区别
        从k8s的1.8版本开始,kube-proxy引入了IPVS模式,IPVS模式与iptables同样基于Netfilter,但是ipvs采用的hash表,iptables采用一条条的规则列表。iptables又是为了防火墙设计的,集群数量越多iptables规则就越多,而iptables规则是从上到下匹配,所以效率就越是低下。因此当service数量达到一定规模时,ipvs的hash查表的速度优势就会显现出来,从而提高service的服务性能

        每个节点的kube-proxy负责监听API server中service和endpoint的变化情况。将变化信息写入本地userspace、iptables、ipvs来实现service负载均衡,使用NAT将vip流量转至endpoint中。由于userspace模式因为可靠性和性能(频繁切换内核/用户空间)早已经淘汰,所有的客户端请求svc,先经过iptables,然后再经过kube-proxy到pod,所以性能很差。

两者差别如下:

ipvs 为大型集群提供了更好的可扩展性和性能

ipvs 支持比 iptables 更复杂的负载均衡算法(最小负载、最少连接、加权等等)

ipvs 支持服务器健康检查和连接重试等功能

ipvs采用的hash表,iptables采用一条条的规则列表

20、权限管理
k8s有两种账号: UserAccount(人使用的账号), ServiceAccount(Pod使用的账号)

UserAccount:访问API Server通常是人去访问,或写的脚本去访问,这类访问使用的账号。

ServiceAccount:Pod自身去连接API Server时,使用的账号。

在K8s中我们操作任何资源都需要经历三个检查步骤:认证、授权 和 准入控制。

当然这些仅针对普通用户,k8s中默认clusteradmin是拥有最高权限的。

认证:即用户要登陆k8s上操作资源,你必须提供合法的用户名和密码。认证方式有

        token(共享秘钥) 

        SSL(双向SSL认证)

授权:用户认证通过后,要查看该用户能操作什么资源,若其要操作的资源在其允许操作的资源范围内则通过。授权方式有以下几种,默认为RBAC。
        ABAC(基于属性的访问控制)

        RBAC(基于角色的访问控制)

        NODE(基于节点的访问控制)

        WEB HOOK(自定义HTTP回调方法的访问控制)

准入控制:这块主要是对认证授权通过后,后期对要操作的级联对象操作的检查

ServiceAccount
ServiceAccount是为了方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的。

1.serviceaccount则是仅局限它所在的namespace;   

2.每个namespace都会自动创建一个default 的ServiceAccount,default默认只有下载镜像的权限。

3.Token controller检测ServiceAccount的创建,并为它们创建secret

4.开启ServiceAccount Admission Controller后

        1.每个Pod在创建后都会自动设置spec.serviceAccount为default

        2.验证Pod引用的service account已经存在,否则拒绝创建     

        3.如果Pod没有指定ImagePullSecrets,则把service account的ImagePullSecrets加到Pod中

        4.每个container启动后都会挂载该service account的token和ca.crt到/var/run/secrets/kubernetes.io/serviceaccount/

如果想为POD使用专门的sa,可以通过spec.serviceAccountName可以指定专门的sa,通过RBAC给对应的sa授权。

RBAC(基于角色的访问控制)
授权机制默认通过RBAC(基于角色的访问控制)进行授权,它只有允许授权,没有拒绝授权,因为默认是拒绝所有,我们仅需要定义允许该用户做什么即可。

RBAC引入了4个新的资源对象:Role、ClusterRole、RoleBinding、ClusterRoleBinding

Role(角色)
Role可理解为一组权限的组合,即我将一组权限打包后,取一个名字。这里的权限都是许可形式,不存在拒绝的规则。Role针对的是一个namespace。创建时需指定对应的namespace。

可操作权限(get、create、list、delete、update、edit、watch、exec等)

可操作对象(Pods、PV、ConfigMaps、Deployments、Nodes、Secrets、Namespaces等)

ClusterRole(集群角色)
和Role一样,都是一组权限的组合,但是针对的是整个集群,创建无需指定对应的namespace。

RoleBinding(角色绑定)和ClusterRoleBinding(集群角色绑定)
就是将user 和 role关联绑定,相当于公司的中职位授予,如:A能力很强,公司授予他,技术部总监,另外还兼职公司副CTO等。

RoleBinding也可以引用ClusterRole,但是绑定后的用户还是只能针对对应的namespace。

ClusterRoleBinding只能引用ClusterRole

用上面两个集群来说明Role,RoleBinding 和 clusterRole,clusterRoleBinding
集群1:
        每个名称空间(Namespace)中,为了定义一个此名称空间的管理员,不得不每个名称空间都创建相同的Admin Role,然后使用roleBinding将AdminRole关联到用户上,来让指定用户成为此名称空间中的管理员。这样做非常繁琐,若名称空间很多,就要在这些名称空间中都要做相同操作,很麻烦。
集群2:
        在整个k8s集群级别创建一个admin role,然后使用roleBinding绑定clusterRole来引用它,将用户关联roleBinding,这样该用户就成功的拥有了对当前名称空间的管理员权限。这样就很省事了。只需要创建一个集群级别的admin role即可。

若还想创建一个用户拥有管理所有名称空间中的所有资源,使用ClusterRoleBinding,将ClusterRole和管理用户绑定,授予此用户具有集群管理员的权限。
————————————————
版权声明:本文为CSDN博主「huangfukui」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/huangfukui/article/details/122147867

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值