Kubernetes学习笔记
POD容器
POD是什么?
- Pod是最小部署单元,一个Pod有一个或多个容器组成,Pod中容器共享存储和网络,在同一台Docker主机上运行。
POD的基本结构
pause的作用
- 我们看下在node节点上都会起很多pause容器,和pod是一一对应的。
- 每个 POD 里运行着一个特殊的被称之为 Pause 的容器,其他容器则为业务容器,这些业务容器共享Pause容器的网络栈和 Volume 挂载卷,因此他们之间通信和数据交换更为高效,在设计时我们可以充分利用这一特性将一组密切相关的服务进程放入同一个 POD 中。同一个POD 里的容器之间仅需通过 localhost 就能互相通信。
- kubernetes 中的 pause 容器主要为每个业务容器提供以下功能:
- PID 命名空间:Pod中的不同应用程序可以看到其他应用程序的进程ID
- 网络命名空间:Pod中的多个容器能够访问同一个IP和端口范围
- IPC命名空间:Pod中的多个容器能够使用SystemV IPC或POSIX消息队列进行通信
- UTS命名空间:Pod中的多个容器共享一个主机名
- Volumes(共享存储卷):Pod中的各个容器可以访问在Pod级别定义的Volumes
POD网络原理
POD网络结构
- 基本概念:POD 是 K8S 最小的操作单元;POD 也是一个容器,独立的沙箱环境,有自己的 IP 地址和自己的hostname;POD 是容器的容器,内部用来封装 Docker 容器。
- POD本身就是运行在操作系统中的一个进程,相当于是一台独立机器(虚拟化概念),POD 内部可以封装一个容器,也可以封装多个容器;在物理机节点上, POD 和 POD 之间是相互独立的。
- 当创建一个pod的资源对象的时候,先创建一个pause容器,此容器会帮助pod创建共享网卡、共享存储卷; 共享网卡、共享存储卷都是 POD 内部容器共享的资源。
- 共享网卡(网络栈):会分配一个独立、唯一的 IP 地址;此 IP 地址被 POD 内部容器共享,另外 POD 的 IP 地址也是此 IP 地址(POD 内部容器共享同一块网卡,因此他们都是使用的同一个 IP 地址)。
- 注意:POD 内部容器共享同一个网卡,IP 地址是相同的,端口不能冲突。
访问POD容器
POD内部容器访问
- 由于 POD 内部的容器共享同一个网卡,因此 POD 内容容器的访问,就相当于访问本地服务一样,使用 localhost 访问即可。
POD 外网访问
- POD、Service 都是运行在操作系统内部一个进程,独立一个沙箱环境,有自己的IP地址,有自己的端口;就是一个虚拟的机器,因此外网不能直接访问物理节点内部的沙箱环境,必须通过物理的网卡的转发。
POD 外部访问
- 由于POD网络采用特殊设计模式:POD 和 POD内部容器共享同一个ip地址的,因此访问 POD 内部容器的时候的,直接通过 IP:容器端口 即可访问到此容器服务。
同一个机器,跨 POD 访问
- 在同一个节点内部 POD 之间相互访问,需要借助于网桥完成 IP 寻址(IP 路由),然后由网桥把请求转发给相应的 POD 服务。
不同机器,POD 访问
- 不同节点 POD 要实现通信,必须借助于 Route table(路由表),实现在不同节点中ip寻址。
网卡 IP 冲突
- 对于 Docker 容器来说,是一个单机版的,当 Docker 在一个 Node 节点创建一个容器的时候,生成 Docker 网桥(网段),此节点中所有的容器都在此网桥下,都是同一个网段。
- 问题:此时此刻,导致POD IP 地址发生冲突,如何解决?
- 在同一个k8s集群中,POD IP 要具有唯一性。答案是使用 开源网络组件 flannel。
- Flanel网络插件确保POD IP地址在整个 Kubernetes集群中具有唯一性的IP地址; 只需要确保网桥的网段不一致就行了,在网桥下的 POD IP 自然不会发生冲突。
基于应用网络
DNS + ClusterIP
- 在服务部署中,网关是对外提供服务的,订单服务属于局域网内部的服务,不需要直接对外提供服务,只需要通过网关来访问订单服务即可,在微服务架构模式下,服务之间访问通过服务名称解析出服务的 IP 地址的方式模式,因此在 Kuberntes 部署模式下,借助了 DNS 服务 IP 解析模式,实现服务发现。
集群内网访问外部服务
- 第一种模式:直接访问外部的数据库即可,把数据库所在的 IP+端口直接访问到服务内部。
- 缺点:把数据库连接地址直接封装到服务镜像中,耦合度太高,一旦数据库地址发生变化,那么将要进行重新打包,重新部署。
- 第二种模式:Service 对外做一个转发,访问外部服务的时候,通过service、endpoints转发,即可实现外部服务访问; endpoints 就是一个 ip地址数组(Endpoints : [mysqlIP])。
外网访问内网服务
- 外部服务要访问内部服务,必须在物理机开辟一个端口,先访问物理机,然后通过物理机端口和service端口映射,把请求转发给service服务,实现从外到内的一个访问的一个流程。
问题答疑
【Q-01】内网访问外网的dns是怎么来设置的?
- 【参考答案】创建service,kubernetes自动把service名称,ip的映射存储在dns,因此dns服务是kubernetes来自动实现维护。
【Q-02】一定要用service吗?用配置中心管理mysql连接地址呢? - 【参考答案】使用配置中心也是ok,把数据注入到 POD 内部。
Service服务发现
Service VIP(虚拟IP)
POD服务集群负载均衡的问题
- 针对 POD IP 动态变化的问题,nginx/openresty 无法感知到的问题,如何解决这一问题呢?
- 答案:服务发现(及时发现 POD IP 发生变化,及时更新转发规则),Kubernetes 提供了 4 层负载均衡的转发的模式,就是 Service 资源对象。
什么是Service?
- Service 资源对象其实就是 Kubernetes 抽象出一个虚拟的对象(运行在 Node 节点一个进程服务),有自己有的IP地址(虚拟IP)和自己的服务端口。
- Service就相当于是一个网关,对应的一组业务的请求都必须经过 Service 资源对象(被Service拦截),然后对请求进行某种规则的转发。
- 思考: Kubernetes 设计 Service 原因是什么?
- Service 要实现服务发现(自动进行),屏蔽掉底层 POD 异常,宕机发生的IP地址,hostname 变化而造成的一系列的影响,使得用户就不需要关心底层POD到底发生了何种变化。
Service 的几个问题
问题1
- Service 如何知道为那几个pod服务(几十万个pod服务)提供服务的呢?
- 回答:Service 资源对象通过标签选择器确定哪些 POD 为当前的 Service 对象的服务对象;
问题2
- Service 服务组态如何划分的?(同一个 Service 资源对象可以同时给订单服务、支付服务提供服务吗)?
- 回答:在服务部署的时候,一个 Service 对应一个业务组,一个 Service 只能对应一个业务组。
问题3
- Service VIP 是否会发生变化?(IP地址发生变化,对服务是否有影响)
- 回答:Service VIP 一般不会发生变化,除非 Service 资源对象进行重建,即使 Service IP 地址发生了变化,对服务没有任何影响。
- 第一:服务名称没有变化【Service 服务名称没有变化,DNS可以根据服务名称解析到对应的 IP】。
- 第二:标签选择器没有发生变化,新的Service对象可以根据标签选择器找到你对应服务。
问题4
- Service VIP 是否存在单点故障?
- 回答:不存在,Service VIP 资源对象存储在 etcd 中,高可用由etcd来保障的;即使是 Node 节点宕机,Service进程宕了,还可以从 etcd 中对服务进行恢复。
问题5
- Service 是否可以通过外网直接访问呢?
- 回答:Service 是一个虚拟的对象,运行在操作系统内部进程,外网服务无法直接访问 Service,如果需要访问 Service,必须先访问物理节点,然后由物理节点转发请求。
问题6
- Service 对象是否可以无限制的创建?(10000个 Service)?
- 回答:根据极限压力测试(华为容器云提供方案)
- Service(iptables) > 500 个,性能急剧下降 5000 (11min),20000 (5 hours)
- Service (ipvs) 没有限制 5000 (50us) ,20000(70us)
如何实现负载均衡
- Service 实现负载均衡的原理是利用 net filter(防火墙)iptables 实现请求的转发(轮询、随机)
- Service iptables是如何实现请求分发的?
- Service 本身并不具备请求分发能力,Kubernetes 实现 POD 服务负载均衡是借助 iptables 能力的实现的。
如何实现服务发现
- 问题描述: POD IP、hostname 发生了变化,iptables中 Service IP,POD IP映射关系也要发生响应的变化,此变化由谁来维护的?
- POD IP 发生变化,Endpoints Controller 控制器通过 watch(Kubernetes API接口)监控 POD 服务变化,及时更新Servcie 与 POD 映射关系,从而实现服务发现。
路由规则改写
- Kube-proxy 核心组件监控 etcd中Service、pod映射关系,发现pod ip发生变化后,更新iptables的路由规则,从而实现访问服务的时候,可以及时发现新的 POD 服务。
Service VIP如何产生
- 选择题:
- 由kubernetes自动创建的
- 部署服务的时候手动创建的 (√)
- 服务上线部署的时候:
- Deployment 部署对象
- Service 对象
Service负载均衡的方案
Service VIP 负载均衡的实现方案:
- userspace
- iptables — k8s默认负载均衡方案
- ipvs
UserSpace
- UserSpace 负载均衡的方案就是利用 kube-proxy 组件实现负载均衡(默认随机),也就是说请求转发由 kube-proxy 来实现。
Iptables
- Iptables模式为Services的默认代理模式。在iptables 代理模式中,kube-proxy不在作为反向代理的在VIPs 和backend Pods之间进行负载均衡的分发。这个工作放给工作在四层的iptables来实现。iptables 和netfilter紧密集成,密切合作,都在kernel space 就实现了包的转发。
- 在这个模式下,kube-proxy 主要有这么几步来实现实现报文转发:
- 通过watching kubernetes集群 cluster API, 获取新建、删除Services或者Endpoint Pod指令。
- kube-proxy 在node上设置iptables规则,当有请求转发到Services的 ClusterIP上后,会立即被捕获,并重定向此Services对应的一个backend的Pod。
- kube-proxy会在node上为每一个Services对应的Pod设置iptables 规则,选择Pod默认算法是随机策略。
- 在iptables模式中,kube-proxy把流量转发和负载均衡的策略完全委托给iptables/netfiter 来做,这些转发操作都是在kernel space 来实现,比userspace 快很多。
- 在Linux中使用iptables完成tcp的负载均衡有两种模式:随机、轮询
随机策略
- 下面以一个example说明iptables两种LB方式的具体实现:系统中提供3个servers,下面我们通过配置iptables使流量均衡访问这3台server。
- 随机:(Random balancing)
# 随机:(Random balancing)
iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -m statistic --mode random --probability 0.33 -j DNAT --to-destination 10.0.0.2:1234
iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -m statistic --mode random --probability 0.5 -j DNAT --to-destination 10.0.0.3:1234
iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -j DNAT --to-destination 10.0.0.4:1234
- rules说明:
- 第一条规则中,指定–probability 0.33 ,则说明该规则有33%的概率会命中;
- 第二条规则也有33%的概率命中,因为规则中指定 --probability 0.5。 则命中的概率为:50% * (1 - 33%)=0.33;
- 第三条规则中,没有指定 --probability 参数,因此意味着当匹配走到第三条规则时,则一定命中,此时走到第三条规则的概率为:1 - 0.33 -0.33 ≈ 0.33。
- 由上可见,三条规则命中的几率一样的。此外,如果我们想修改三条规则的命中率,可以通过 --probability 参数调整。
- 假设有 n 个 server,则可以设定 n 条 rule 将流量均分到 n 个 server 上,其中 --probability 参数的值可通过以下公式计算得到:
# i 代表规则的序号(第一条规则的序号为1),n 代表规则/server的总数,p 代表第 i 条规则中 --probability 的参数值
p=1/(n−i+1)
- 注意:因为 iptables 中,规则是按顺序匹配的,由上至下依次匹配,因此设计 iptables 规则时,要严格对规则进行排序。因此上述三条规则的顺序也不可以调换,不然就无法实现 LB 均分了。
轮询策略
- 轮询算法中有两个参数:
- n:指每 n 个包
- p:指第 p 个包
- 在规则中 n 和 p 代表着: 从第 p 个包开始,每 n 个包执行该规则。这样可能有点绕口,直接看栗子吧:还是上面的例子, 有 3 个 server,3 个 server 轮询处理流量包,则规则配置如下:
# every:每n个包匹配一次规则;packet:从第p个包开始
iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -m statistic --mode nth --every 3 --packet 0 -j DNAT --to-destination 10.0.0.2:1234
iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -m statistic --mode nth --every 2 --packet 0 -j DNAT --to-destination 10.0.0.3:1234
iptables -A PREROUTING -t nat -p tcp -d 192.168.1.1 --dport 27017 -j DNAT --to-destination 10.0.0.4:1234
IPVS
什么是IPVS
- IPVS(IP虚拟服务器)实现传输层负载平衡,通常称为第 4 层 LAN 交换,是 Linux 内核的一部分。
- IPVS在主机上运行,在真实服务器集群前充当负载均衡器。 IPVS可以将对基于TCP和UDP的服务的请求定向到真实服务器,并使真实服务器的服务在单个IP地址上显示为虚拟服务。
IPVS vs. IPTABLES
IPVS模式在Kubernetes v1.8中引入,并在v1.9中进入了beta。 IPTABLES模式在v1.1中添加,并成为自v1.2以来的默认操作模式。 IPVS和IPTABLES都基于netfilter。 IPVS模式和IPTABLES模式之间的差异如下:
- IPVS为大型集群提供了更好的可扩展性和性能。
- IPVS支持比iptables更复杂的负载平衡算法(最小负载,最少连接,位置,加权等)。
- IPVS支持服务器健康检查和连接重试等。
- 我们都知道,在Linux 中iptables设计是用于防火墙服务的,对于比较少规则的来说,没有太多的性能影响。但是对于,一个K8S集群来说,会有上千个Services服务,当然也会转发到Pods,每个都是一条iptables规则,对集群来说,每个node上会有大量的iptables规则,简直是噩梦。
- 同样IPVS可以解决可能也会遇见这样大规模的网络转发需求,但是IPVS用hash tabels来存储网络转发规则,比iptables 在这上面更有优势,而且它主要工作在kernel space,减少了上下文切换带来的开销。
IPVS负载步骤
kube-proxy 和 IPVS 在配置网络转发中,有这么几步:
- 通过 watching kubernetes 集群 cluster API, 获取新建、删除 Services 或者 Endpoint Pod 指令,有新的Service建立,kube-proxy 回调网络接口,构建IPVS规则。
- 同时,kube-proxy 会定期同步 Services 和 backend Pods 的转发规则,确保失效的转发能被更新修复。
- 有请求转发到后端的集群时,IPVS的负载均衡直接转发到 backend Pod。
IPVS负载算法
- IPVS支持的负载均衡算法有这么几种:
- rr: 轮询
- lc: 最小连接数
- dh: 目的地址hash
- sh: 源地址hash
- sed: 最短期望延迟
- nq: 无须队列等待
- 在node上通过 “–ipvs-scheduler”参数,指定kube-proxy的启动算法。
Service、Deployment部署文件
Deployment对象
Service对象
- 查看帮助文档,查询资源清单:
# 查看此资源对象资源清单
kubectl explain 资源对象