前世今生
Google开源的一个容器编排引擎
kubernetes,简称K8s,是用8代替8个字符“ubernete”而成的缩写。是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规划,更新,维护的一种机制。
传统的应用部署方式是通过插件或脚本来安装应用。这样做的缺点是应用的运行、配置、管理、所有生存周期将与当前操作系统绑定,这样做并不利于应用的升级更新/回滚等操作,当然也可以通过创建虚拟机的方式来实现某些功能,但是虚拟机非常重,并不利于可移植性。
新的方式是通过部署容器方式实现,每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。相对于虚拟机,容器能快速部署,由于容器与底层设施、机器文件系统解耦的,所以它能在不同云、不同版本操作系统间进行迁移。
容器占用资源少、部署快,每个应用可以被打包成一个容器镜像,每个应用与容器间成一对一关系也使容器有更大优势,使用容器可以在build或release 的阶段,为应用创建容器镜像,因为每个应用不需要与其余的应用堆栈组合,也不依赖于生产环境基础结构,这使得从研发到测试、生产能提供一致环境。类似地,容器比虚拟机轻量、更“透明”,这更便于监控和管理。
前生 Borg系统 google开发,go语言编写
特点
- 轻量级:消耗资源小
- 开源
- 弹性伸缩
- 负载均衡:IPVS
适合人群
- 软件工程师
- 测试工程师
- 运维工程师
- 软件架构师
- 项目经理
- 。。。。
组件说明
Borg组件说明
K8S结构说明
网络结构
组件结构
etcd
官方将它定位成一个可信赖的分布式键值存储服务,它能够为整个分布式集群存储一些关键数据,协助分布式集群的正常运转。
推荐在k8s集群中使用Etcd v3,v2已在k8s v1.11中弃用
etcd v3引入本地database持久化存储
键值对数据库,储存K8S集群所有重要信息(持久化),一个高可用的K/V键值对存储和服务发现系统
flannel
实现夸主机的容器网络的通信
scheduler
调度器
负责介绍任务,选择合适的节点进行分配任务,调度容器,分配到Node
replication controller
CrontrollerManager:维持维护副本期望数目
apiserver
所有服务访问的统一入口
kube-apiserver
提供kubernetes集群的API调用
node
kubelet
维持Pod生命周期,与docker等容器虚拟化技术进行交互,管理
直接跟容器引擎交互实现容器生命周期管理,在Node节点上按照配置文件中定义的容器规格启动容器
kube proxy
负责写入规则至 IPTABLES、IPVS 实现服务映射访问的,提供网络代理服务
firewall 默认
默认操作防火墙去实现Pod的映射。负载均衡
Pod
contianer
coredns
可以为集群中的SVC创建一个域名IP的对应关系解析
dashboard
给K8S集群提供一个B/S结构访问体系
ingress controller
官方只能实现4层代理,INGRESS可以实现七层代理
fedetation
提供一个可以跨集群中心多K8S统一管理功能
prometheus
提供K8S集群的监控能力
ELK
提供K8S集群日志统一分析介入平台
Pod概念
- 自主式Pod
- 控制器管理的Pod
自主式Pod
关闭后,不可以再次启用
容器管理Pod
RS、RC
- RC:ReplicationController
- 用来确保容器应用副本始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod来替代,而异常多出来的容器也会自动回收。
- 在新版本K8S建议使用ReplicaSet来取代ReplicationController
- RS:ReplicaSet
- 本质和ReplicationController没有本质不同,只是名字不一样,并且ReplicaSet支持集合式的selector
- 虽然replicaSet可以独立使用,但一般还是建议使用Deployment来自动管理ReplicaSet,这样就无需担心跟其他机制的不兼容问题(比如ReplicaSet 不支持 rolling-update 但deployment支持)
deployment
Deployment 为Pod 和 ReplicaSet 之上,提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController 来方便的管理应用。
你只需要在 Deployment 中描述您想要的目标状态是什么,Deployment controller 就会帮您将 Pod 和ReplicaSet 的实际状态改变到您的目标状态。您可以定义一个全新的 Deployment 来
创建 ReplicaSet 或者删除已有的 Deployment 并创建一个新的来替换。也就是说Deployment是可以管理多个ReplicaSet的,
HPA( Horizontal Pod Autoscaling )
仅适用于Deployment和ReplicaSet
在V1版本中仅支持根据Pod的CPU利用率扩缩容,在vlalpha版本中,支持根据内存和用户自定义的metric扩缩容
StatefullSet
为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计)其应用场景包括:
- 稳定的持久化存贮,即Pod重新调度后还是能访问到相同的持久化数据,
- 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的service)来实现
- 有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的舒徐依次进行(即从0到n-1,在下一个Pod运行之前所有之前的Pod必须是Running和Ready状态)
- 有序收缩,有序删除(即从N-1到0)
DaemonSet
确保全部(或者一些)Node上运行一个Pod的副本,当有Node加入集群时,也会为他们新增一个Pod,当有Node从集群移除时,这些Pod也会被回收,删除DaemonSet也会删除它创建的所有Pod
典型用法
- 运行集群存储daemon,例如每个Node上运行glusterd、ceph
- 在每个Node上运行日志收集daemon,例如fluentd、logstash
- 在每个Node上运行监控daemon,例如Prometheus Node Exporter
Job,Cronjob
负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束
Cron Job管理基于时间的job即:
- 在给定时间点只运行一次
- 周期性地在给定时间点运行
服务发现
出现原因
Pod的生命是有限的,如果Pod重启IP很有可能会发生变化。
如果我们的服务都是将Pod的IP地址写死,Pod的挂掉或者重启,后端其他服务也将会不可用,当然我们可以通过手动修改如nginx的upstream配置来改变后端的服务IP。
现在我们可以通过,Consul,ZooKeeper还有我们熟悉的etcd等工具,有了这些工具过后我们就可以只需要把我们的服务注册到这些服务发现中心去就可以,然后让这些工具动态的去更新Nginx的配置就可以了,我们完全不用去手工的操作了。
service
Kubernetes集群就为我们提供了这样的一个对象 - Service,Service是一种抽象的对象,它定义了一组Pod的逻辑集合和一个用于访问它们的策略,其实这个概念和微服务非常类似。一个Serivce下面包含的Pod集合一般是由Label Selector来决定的。
我们这样就可以不用去管后端的Pod如何变化,只需要指定Service的地址就可以了,因为我们在中间添加了一层服务发现的中间件,Pod销毁或者重启后,把这个Pod的地址注册到这个服务发现中心去。Service的这种抽象就可以帮我们达到这种解耦的目的。
kube-proxy
在Kubernetes集群中,每个Node会运行一个kube-proxy进程, 负责为Service实现一种 VIP(虚拟 IP,就是clusterIP)的代理形式。
Service其实是由kube-proxy组件和Iptables来实现的。
现在的Kubernetes中默认是使用的iptables这种模式来代理
这种模式,kube-proxy会监视Kubernetes master对 Service 对象和 Endpoints (端点)对象的添加和移除。 对每个 Service,它会添加上 iptables 规则,从而捕获到达该 Service 的 clusterIP(虚拟 IP)和端口的请求,进而将请求重定向到 Service 的一组 backend(后端) 中的某一个个上面。 对于每个 Endpoints 对象,它也会安装 iptables 规则,这个规则会选择一个 backend Pod。
默认的策略是,随机选择一个 backend。 我们也可以实现基于客户端 IP 的会话亲和性,可以将 service.spec.sessionAffinity 的值设置为 "ClientIP" (默认值为 "None")。
另外需要了解的是如果最开始选择的 Pod 没有响应,iptables 代理能够自动地重试另一个 Pod,所以它需要依赖 readiness probes(准备就绪探测器)。
Pod协同
网络通讯模式
网络通讯模式说明
K8S网络模型假定了所有Pod都在一个可以直接连通的扁平的网络空间中,这在GCE(Google Compute Engine)里面是现成的网络模型,K8S假定这个网络已经存在。而在私有云里搭建K8S集群,就不能假定这个网络已经存在了,我们需要自己实现这个假设,将不同节点上的docker容器之间的相互访问先打通,然后运行K8S
- 同一个Pod内的多个容器之间:IO
- 各Pod之间的通讯:Overlay Network
- Pod与service之间的通讯:各节点的Iptables规则
网络解决方案
Flannel
Flannel是CoreOS团队针对K8S设计的一个网络规划服务,简单来说,它的功能是让集群种不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址,而且它还能在这些IP地址之间建立一个覆盖网络(Overlay Network),通过这个覆盖网络,将数据包原封不动地传递到目标容器内
ETCD之Flannel提供说明
- 存储管理Flannel可分配的IP地址段资源
- 监控ETCD中每个POD的实际地址,并在内存中建立维护Pod节点路由表
组件通讯模式说明
同一个Pod内部通讯
同一个Pod共享同一个网络命名空间,共享同一个Linux协议栈
Pod1至Pod2
- Pod1与Pod2不在同一台主机
- Pod的地址是与docker0在同一个网段的,但docker0网段和宿主机网卡是两个完全不同的IP网段,并且不同的Node之间的通信只能通过宿主机的物理网卡进行,将Pod的IP和所在Node的Ip关联起来,通过这个关联让Pod可以互相访问
- Pod1与Pod2在同一台主机
- 由Docker0网桥直接转发请求至Pod2,不需要经过Flannel
Pod至service的网络
目前基于性能考虑,全部为iptables维护和转发
Pod到外网
Pod向外网发送请求,查找路由表,转发数据包到宿主机的网卡、宿主机网卡完成路由选择后,iptables执行Masquerade,把源IP更改为宿主机网卡的IP,然后向外网服务器发送请求
外网访问Pod
service