0. k8s容器概括
docker的组成
- cgroup做资源隔离
- namespace做物理隔离
- rootfs做系统隔离
exec的执行过程
- 找到欲进入的容器的pid
- 根据pid找到该容器对应的namespace
- 通过setns进入到该命名空间
- 执行某个命令
- docker 创建容器时,可通过—net指定加入到某个容器网络,或宿主机网络;与上面setns同理
- CMD 与 ENTRYPOINT的区别
- cmd是可通过run后面的命令覆盖的
- entrypoint是不可通过run后面的命令覆盖的,但是可以通过run后面的输入添加参数
docker 挂载
- 在启动容器时,如果未指定宿主机,则自动挂载到宿主机的某目录上
- 在容器进程创建后,chroot前,将某目录挂载到该容器对应的宿主机某目录下;由于挂载前容器进程已创建,故挂载事件只在这个容器里可见,宿主机上无法看到挂载点,同理,如果容器的该目录中有文件,在宿主机上并不会展示
- 由于宿主机上看不到该挂载点,所以当执行docker commit时,并不会将挂载目录的内容提交到image中
k8s本质
- 容器分为两部分
- 容器的静态视图,即rootfs,也就是image内容
- 容器的动态视图,即cgroup+namespace
- 做为云提供商只要能将docker 镜像以容器的方式运行起来,即能加入到docker的生态圈中
- k8s的组成
- master之kube-apiserver
- master之kube-scheduler
- master之kube-controller-manager
- node之kubelet
- node之kube-proxy
- kubelet控制容器过程中使用的规范
- CRI:Container Runtime Interface
- OCI:Open Container Initiative
- CNI:Container Networking Interface
- CSI:Container Storage Interface
- Device Plugin
- K8S中的概念
- Service
- Deployment
- Pod
- DaemonSet
- StatefulSet
- Secret
- ConfigMap
- Ingress
Pod的实质
- Pod是一组共享Namespace的容器
- Pod中存在一个基本的Infra容器,其它容器通过join该容器的方式实现共享Namespace
- Pod 的生命周期只跟 Infra 容器一致,而与容器 A 和 B 无关。
- 同一个 Pod 里面的所有用户容器来说,它们的进出流量,也可以认为都是通过 Infra 容器完成的
- Init Container会先启动,启动完成并且退出后才会启动用户容器
深入理解pod
- pod通过NodeName识别调度到哪个节点
- 通过HostAliases设置hosts
- ImagePullPolicy:Always IfNotPresent Never
- postStart与preStop
- pod的状态 Pending Running Succeeded Failed Unknown
- Running指容器已经全部创建成功,并且至少有一个运行中(有可能还不可接收请求,正在启动中);而Running的子状态Ready指的是容器是否已正常运行,并且可接收外部请求
- livenessProbe readinessProbe
- podpreset 为pod设置公共字段
Headless Service 及 StatefulSet
- Headless Service:无clusterip的 Service
- StatefulSet:有状态的pod集合,即pod的名称及对应的启动node节点一致
并且可以保证pod的启动顺序;另外保证Pod 拥有独立的 Volume,并且重启后仍然挂载该Volume
API对象
- 组成:Group(API 组)、Version(API 版本)和 Resource(API 资源类型)三个部分组成
- Kubernetes 里的核心 API 对象,比如:Pod、Node 等,是不需要 Group 的(即:它们 Group 是“”)
- 核心的api直接在 /api 这个层级进行下一步的匹配过程
- 对于 CronJob 等非核心 API 对象来说,Kubernetes 就必须在 /apis 这个层级里查找
PV与PVC
- PVC是对PV的声明
- PVC与PV绑定的条件,spec下的配置一致,storageClassName相同
- PVC与PV绑定后,会在PVC的spec.volumeName上填入所绑定的PV
- PV的挂载
- Attach:为虚拟机挂载远程磁盘的操作,该操作由Volume Controller 负责维护
- Mount:将磁盘设备格式化并挂载到 Volume 宿主机目录;该操作必须在node上执行,故该操作由kubelet中的一个goroutine完成
- StorageClass:声明一种存储类型
- PVC声明存储的大小,当PVC上存在StorageClassName时,并且存在命名为该Name的StorageClass时,就可以根据PVC及StorageClass创建出对应的PV,从而实现动态绑定的效果
- 如果不存在PVC上StorageClassName对应的StorageClass时,会进行静态绑定
- 当PVC的StorageClassName为“”时,则该PVC只能和StorageClassName同样为“”的PV绑定
- Local Persistent Volume:本地持久化挂载
- 创建本地挂载时,指定该挂载点的节点
- Local Persistent Volume尚不支持动态绑定PV
- Pod绑定该PV对应的PVC
- 创建StorageClass描述PV延时绑定,延时到pod调度时,根据调度的结果及PV中对应的节点,取节点交集启动该Pod;防止出现提前绑定PV和PVC后,Pod不能调度到该节点的情况
单节点容器网络
- veth pair:一个成对的端口,所有从这对端口一 端进入的数据包都将从另一端出来,反之也是一样
- docker0: docker容器网桥,所有的容器虚拟网卡,均接入到该网桥上,即所有容器网卡接收的数据包,都由docker0处理
- ARP: 通过三层的 IP 地址找到对应的二层 MAC 地址的协议。
- route命令
- 查看机器路由配置
- 匹配某目标地址段网络由哪个网关处理
- 如果未匹配到路由规则,则由默认的路由处理
- 容器间A->B的网络通信过程
- 在A容器中通过路由规则匹配到处理的网卡
- 该网卡是一对veth pair网卡,当流量进入该网卡时,即进入到了host上与之对应的网卡上
- host与之对应的虚拟网卡插在了docker 网桥 docker0上
- docker0网桥通过目标mac查找到对应的端口,即B容器在host上对应的veth pair网卡
- 数据包由veth pair进入到容器内
- 上述省略了ARP的前置过程,具体ARP的过程与上述过程类似
多节点容器网络
- Overlay Network:通过软件构建一个覆盖在已有宿主机网络之上的、可以把所有容器连通在一起的虚拟网络
- Overlay Network 本身,可以由每台宿主机上的一个“特殊网桥”共同组成
- 当 Node 1 上的 Container 1 要访问 Node 2 上的 Container 3 的时候,Node 1 上的“特殊网桥”在收到数据包之后,能够通过某种方式,把数据包发送到正确的宿主机,比如 Node 2 上。
- 而 Node 2 上的“特殊网桥”在收到数据包后,也能够通过某种方式,把数据包转发给正确的容器,比如 Container 3
flannel之UDP的实现原理
- flannel通过etcd保存不同容器子网对应的节点ip
- 在启动docker时,可通过指定pid的方式,实现不同节点的容器网络ip段不同
- Flannel 会在宿主机上创建出一系列的路由规则
- Flannel是一个 TUN 设备(Tunnel 设备)
- 在 Linux 中,TUN 设备是一种工作在三层(Network Layer)的虚拟网络设备
- TUN 设备的功能非常简单,即:在操作系统内核和用户应用程序之间传递 IP 包
- 节点1上的A容器访问节点2上的B容器的过程,假设A容器的ip是100.96.1.2,B容器的ip是100.96.2.3
- 由于目的地址 100.96.2.3 并不在 Node 1 的 docker0 网桥的网段里,所以这个 IP 包会被交给默认路由规则,通过容器的网关进入 docker0 网桥
- 由于目的地址100.96.2.3,匹配不到node1节点路由表中 docker0 网桥对应的 100.96.1.0/24 网段,只能匹配到第二条、也就是 100.96.0.0/16 对应的这条路由规则,从而进入到一个叫作 flannel0 的设备中
- 当操作系统将一个 IP 包发送给 flannel0 设备之后,flannel0 就会把这个 IP 包,交给创建这个设备的应用程序,也就是 Flannel 进程。这是一个从内核态(Linux 操作系统)向用户态(Flannel 进程)的流动方向
- 反之,如果 Flannel 进程向 flannel0 设备发送了一个 IP 包,那么这个 IP 包就会出现在宿主机网络栈中,然后根据宿主机的路由表进行下一步处理。这是一个从用户态向内核态的流动方向
- flanneld 看到了这个 IP 包的目的地址,是 100.96.2.3,先从etcd中根据该地址查询到节点的ip,然后把它发送给了 Node 2 宿主机
- 每台宿主机上的 flanneld,都监听着一个 8285 端口,所以 flanneld 只要把 UDP 包发往 Node 2 的 8285 端口即可
- flanneld 会直接把这个 IP 包发送给它所管理的 TUN 设备,即 flannel0 设备
- 然后在节点2的路由表中寻找这个 IP 包的下一步流向
- Linux 内核就会按照这条路由规则,把这个 IP 包转发给 docker0 网桥
- docker0 网桥会扮演二层交换机的角色,将数据包发送给正确的端口,进而通过 Veth Pair 设备进入到 container-2 的 Network Namespace 里
- 由于上述过程中,存在多次用户态与内核态之间的数据拷贝,所以性能很差
flannel之VXLAN的实现原理
- VLAN:
- 通过VLAN在二层交换机上隔离不同的端口,以实现网络隔离的效果
- 隔离的优点,防止广播数据帧在网络中范围传播,从而节省带宽及机器对这部分功能处理的cpu消耗
- 隔离的缺点
- 两个VLAN的网络无法直接通信
- VLAN最多划分4096个,现已无法满足大规模云计算IDC的需求
- 无法解决同一交换机中多租户的网络地址重叠的问题
- 虚拟化技术的出现增加了交换机的负担,为了保证集群中所有虚机可以正常通信,交换机必须保存每台虚机的MAC地址,这样就导致了交换机中的MAC表异常庞大,从而影响交换机的转发性能
- 虚拟机迁移范围受网络架构限制
- 静态VLAN,通过指定交换机的端口划分VLAN
- 动态VLAN之基于MAC地址的VLAN,通过查询并记录端口所连计算机上网卡的MAC地址来决定端口的所属
- 动态VLAN之基于子网的VLAN,通过所连计算机的IP地址,来决定端口所属VLAN的
- 动态VLAN之基于用户的VLAN,根据交换机各端口所连的计算机上当前登录的用户,来决定该端口属于哪个VLAN,这里的用户识别信息,一般是计算机操作系统登录的用户,比如可以是Windows域中使用的用户名
- Overlay:https://support.huawei.com/enterprise/zh/doc/EDOC1100023543?section=j015
- Overlay网络是将已有的物理网络(Underlay网络)作为基础,在其上建立叠加的逻辑网络,实现网络资源的虚拟化
- Overlay网络是建立在已有物理网络上的虚拟网络,具有独立的控制和转发平面,对于连接到Overlay的终端设备(例如服务器)来说,物理网络是透明的,从而可以实现承载网络和业务网络的分离。
- 解决的问题
- 针对虚拟机规模受网络规格限制:虚拟机发出的数据包封装在IP数据包中,对网络只表现为封装后的网络参数。因此,极大降低了大二层网络对MAC地址规格的需求。
- 针对网络隔离能力限制:Overlay技术扩展了隔离标识的位数(24比特),极大扩展了隔离数量
- 针对虚拟机迁移范围受网络架构限制:Overlay将以太报文封装在IP报文之上,通过路由在网络中传输。通过路由网络,虚拟机迁移不受网络架构限制。而且路由网络具备良好的扩展能力、故障自愈能力、负载均衡能力
- Overlay技术有多种,例如VXLAN、NVGRE、STT等,其中VXLAN是目前获得最广泛支持的Overlay技术。
- VTEP:用于建立VxLAN隧道的端点设备成为VTEP,封装和解封装在VTEP节点上进行
- VNI:
- VXLAN头部包含有一个VXLAN标识(即VNI,VXLAN Network Identifier)
- 只有在同一个VXLAN上的虚拟机之间才能相互通信
- VNI在数据包之中占24比特,故可支持1600万个VXLAN的同时存在,远多于VLAN的4094个,因此可适应大规模租户的部署
- VXLAN:VXLAN技术是网络Overlay技术的一种实现,对于Overlay技术,笔者的理解是:在基于物理网络拓扑的基础上通过一定的技术来构建虚拟的、不同于物理网络拓扑的逻辑网络,而物理网络的拓扑结构对于Overlay终端而言是透明的,终端不会感知到物理网络的存在,而仅仅能感知到逻辑网络结构。对于终端的视角,网络的情况和直接通过物理设备实现逻辑拓扑的效果是相同的。
- ARP及数据传输流程:VM1——VTEP1——物理交换机——VTEP2——VM2
- VM1给VM2发送了一个TCP报文
- VTEP1收到报文后检查VM1和VM2是否属于一个VNI,(如果不属于将转发给VXLAN网关)检查后属于一个VNI,需要转发给VTEP2
- VTEP1封装VXLAN报文以单播的形式发送给VTEP2
- VTEP2收到报文后解封装,查找流表。VM2是自己下联终端
- VTEP2单播的形式发送给VM2,至此一个报文发送完毕
- ARP及数据传输流程:VM1——VTEP1——物理交换机——VTEP2——VM2
- docker clan网络请求过程
- 当 Node 2 启动并加入 Flannel 网络之后,在 Node 1(以及所有其他节点)上,生成一条Node 2节点ip对应flannel1.1的路由规则;同时会自动生成node 2 VTEP 设备的arp记录
- 当容器A发出请求后,这个网络数据包,先到达docker0
- docker0发现不是该节点的docker网络,会根据路由规则匹配到flannel1.1,即node1的VTEP 设备,暂称之为源VTEP
- “源 VTEP 设备”收到“原始 IP 包”后,就要想办法把“原始 IP 包”加上一个目的 MAC 地址,封装成一个二层数据帧,然后发送给“目的 VTEP 设备”;而mac地址,在加入flannel网络时,即已在节点上生成了对应的arp记录
- 然后会在源VTEP中进行一系列的封包处理后将封装后的数据包发送至目标VTEP
- 目标VTEP收到数据包后,会先进行解封处理,取出原始的ip地址
- 解封后,根据目的虚机或容器ip,匹配路由规则,发到docker0网桥
flannel之Host-gw的实现原理
- 在路由规则中,指定如果目标ip是某ip,则下一跳为某个节点,该节点即为该容器所在节点
- 通过Host-gw方式的性能损耗大概在10%
- 而其它vxlan的损耗大概在25%
k8s之Service
- Service 的clusterIp是一个VIP
- 当创建一个Service后,kube-proxy会通过informer监听到该事件,然后会在节点上创建一系列的iptables,使得对Service ClusterIP的访问,随机请求到后续的三个节点上
- Kube-proxy之IPVS模式
- iptables模式会在节点上创建大量的iptables规则,这会严重制约pod数量
- 当创建了 Service 之后,kube-proxy 首先会在宿主机上创建一个虚拟网卡(叫作:kube-ipvs0),并为它分配 Service VIP 作为 IP 地址
- 而接下来,kube-proxy 就会通过 Linux 的 IPVS 模块,为这个 IP 地址设置三个 IPVS 虚拟主机(即三个pod),并设置这三个虚拟主机之间使用轮询模式 (rr) 来作为负载均衡策略
- 在大规模集群里,非常建议 kube-proxy 设置–proxy-mode=ipvs 来开启这个功能。它为 Kubernetes 集群规模带来的提升,还是非常巨大的
—————————————————————————
0-17