一、三个容器管理器平台
- Apache MESOS 开源的分布式资源管理框架,被推特选为基础平台,2019年推特换位k8s,MESOS最新版可以在MESOS上管理k8s
- DOCKER SWARM docker总部发行的,实现docker的集群方案,和docker捆版一起,比较轻量,功能少,但是大规划话实现非常好,对docker实现好
- Kubernetes Goolge研发, 由borg采用go语言开发,资源消耗少,弹性伸缩,开源,负载均衡
二、kubernetes组件
1️⃣ 服务的分类
- 有状态服务:数据库管理系统(DBMS)
- 无状态服务:lvs APACHE
2️⃣ borg架构
3️⃣ k8s架构
- replication controller :简称rc 控制器,维护副本数目,副本数量如果达不到数量值控制器就会去申请副本,以便于达到数量值,也就是删除对应的pod和删除对应的pod
- kubectl : 命令行管理工具
- web UI : web界面
- Scheduler:调度器,负载介绍任务,选择合适的节点进行分配任务
- api server : 所有服务访问统一入口
- kubetet:负责维护容器的生命周期,同时也复制Volume和网络的管理
- kube proxy:负责为Service提供集群内部的服务发现和负载均衡
⭐️ 看上图,就可以看见以上所有服务都要以 api server
交互,所以看起来会很繁忙,但是每个服务都会在服务本身产生一定的缓存,并不是每件事都要到 api server
里面去请求
组件一: Etcd
⭐️ etcd
的官方将它定位成一个可信赖的分布式键值存储服务,它能够为整个分布式集群存储一些关键数据,协助分布式集群的正常运转,天生支持集群不需要中间件,可以保存一些配置文件
⭐️ etcd
是 CoreOS
团队于 2013 年 6月发起的开源项目,它的目标是构建一个高可用的分布式键值 (key-value)
数据库。etcd
内部采用 raft
协议作为一致性算法,etcd 基于 Go
语言实现。
⭐️ etcd 的特点
- 简单:安装配置简单,而且提供了HTTP API进行交互,使用也很简单
- 安全:支持SSL证书验证
- 快速:根据官方提供的benchmark数据,单实例支持每秒2k+读操作
- 可靠:采用raft算法,实现分布式系统数据的可用性和一致性
⭐️ 为了保证数据的强一致性,etcd
集群中所有的数据流向都是一个方向,从 Leader
(主节点)流向 Follower
,也就是所有 Follower
的数据必须与 Leader
保持一致,如果不一致会被覆盖。
⭐️ 用户对于 etcd
集群所有节点进行读写
- 读取:由于集群所有节点数据是强一致性的,读取可以从集群中随便哪个节点进行读取数据
- 写入:etcd 集群有 leader,如果写入往 leader 写入,可以直接写入,然后然后Leader节点会把写入分发给所有 Follower,如果往 follower 写入,然后Leader节点会把写入分发给所有 Follower
⭐️ etcd目前有两个版本一个是v3 一个是v2,v2版是将数据写入到内存中,v3是把数据写入到本地数据卷的库中,但是推荐使用v3,v2以及被弃用
⚠️ 需要注意的是在kubernetes1.11版本前的是不支持v3版本的
⭐️ETCD
的内部架构图
1️⃣使用的模式是C/S的构建服务
k8也是用http协议支持C/S
C/S
:Clinet
-Server
,服务器负责数据库的管理,客户机负责完成与用户的交互。ETCD
就是采用这种模式,kubernetes
也是。Raft
:存储读写信息WAL
:预写日志
其他插件
CoreDNS
:可以为集群中的SVC创建一个域名IP的对应关系解析。、
Dashboard
:k8s集群提供B/S结构
ps: B/S 浏览器/服务器模式
Ingress controller
: 官方只能实现四层代理,ingress实现7层代理
Federation
:可以提供一个可以夸集群中心多K8s统一管理的功能
Prometheus
:普罗米修斯,提供K8s集群的监控能力
ELK
:提供k8s的集群日志统一分析接入平台
三、Pod
- 自主式Pod:不是被控制器管理的Pod,死了以后不会被控制器“复活”,也不会创建一个和他期望值一样的Pod
- 控制器管理的Pod: 被控制器管理的Pod,和自助式Pod是反着来的
⭐️ 在同一个容器里面他们的网络,存储都是共享的,因此不能发生端口冲突。
1️⃣ReplicationController & ReplicaSet & Deployment
ReplicationController
用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收。在新版本的Kubernetes
中建议使用ReplicaSet
来取代ReplicationControlle
ReplicaSet
跟ReplicationController
没有本质的不同,只是名字不一样,并且ReplicaSet
支持集合式的selector
,通过labels
来操作- 虽然
ReplicaSet
可以独立使用,但-般还是建议使用Deployment
来自动管理ReplicaSet
,这样就无需担心跟其他机制的不兼容问题(比如ReplicaSet
不支持rolling- update
但Deployment
支持)
⭐️selector
:搜索,标签搜索,rc
不支持集合式搜索,rs
支持,就是创建 Pod
的时候会给 Pod
打上标签,可以直接搜索标签,或者一组标签
⭐️rolling-update
:滚动更新,也就是你需要把一个或者一组 Pod
更新成最新版本,它就会给你先生成一个新版的 Pod
,在给你删除你旧版的 Pod
⭐️ 回滚:和更新类似,只不过式反着来的
2️⃣ Deployment (ReplicaSet )
⭐️ Deployment
为 Pod
和 ReplicaSet
提供了一个声明式定义(declarative
) 方法,用来替代以前的 ReplicationController
来方便的管理应用。典型的应用场景包括:
- 定义
Deployment
来创建Pod和ReplicaSet - 滚动升级和回滚应用
- 扩容和缩容
- 暂停和继续Deployment
命令式编程: 它侧重于如何实现程序,就像我们刚接触编程的时候那样,我们需要把程序的实现过程按照逻辑结果一步步写下来
声明式编程: 它侧重于定义想要什么,然后告诉计算机/引擎,让他帮你去实现
3️⃣ HPA (HorizontalPodAutoScale)
⭐️ Horizontal Pod Autoscaling
仅适用于 Deployment
和 ReplicaSet
,在V1版本中仅支持根据 Pod
的 CPU
利用率扩所容,在 v1alpha
版本中,支持根据内存和用户自定义的 metric
扩缩容.
4️⃣ StatefulSet
⭐️ StatefulSet
是为了解决有状态服务的问题(对应 Deployments
和 ReplicaSets
是为无状态服务而设计),其应用场景包括:
- 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于
PVC
来实现 - 稳定的网络标志,即Pod重新调度后其
PodName
和HostName
不变,基于Headless Service
(即没有Cluster IP
的Service
)来实现 - 有序部署,有序扩展,即
Pod
是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下-一个Pod运行之前所有之前的Pod
必须都是Running
和Ready
状态) ,基于init containers
来实现 - 有序收缩,有序删除(即从N-1到0)
5️⃣ Service
⭐️ Kubernetes
中一个应用服务会有一个或多个实例(Pod
),每个实例(Pod
)的IP地址由网络插件动态随机分配(Pod
重启后IP地址会改变)。为屏蔽这些后端实例的动态变化和对多实例的负载均衡,引入了Service这个资源对象
ClusterIP
: 默认方式。根据是否生成ClusterIP
又可分为普通Service
和Headless
Service
两类:- 普通
Service
:通过为Kubernetes的Service分配一个集群内部可访问的固定虚拟IP(Cluster IP
),实现集群内的访问。为最常见的方式。 Headless Service
:该服务不会分配Cluster IP
,也不通过kube-proxy
做反向代理和负载均衡。而是通过DNS提供稳定的网络ID
来访问,DNS
会将headless service
的后端直接解析为podIP列表。主要供StatefulSet使用。NodePort
:除了使用Cluster IP之
外,还通过将service
的port
映射到集群内每个节点的相同一个端口,实现通过nodeIP
:nodePort
从集群外访问服务。LoadBalancer
:和nodePort
类似,不过除了使用一个Cluster IP
和nodePort
之外,还会向所使用的公有云申请一个负载均衡器(负载均衡器后端映射到各节点的nodePort),实现从集群外通过LB访问服务。ExternalName
:是Service
的特例。此模式主要面向运行在集群外部的服务,通过它可以将外部服务映射进k8s
集群,且具备k8s
内服务的一些特征(如具备namespace
等属性),来为集群内部提供服务。此模式要求kube-dns
的版本为1.7
或以上。这种模式和前三种模式(除headless service
)最大的不同是重定向依赖的是dns层次,而不是通过kube-proxy
。
6️⃣ DaemonSet
⭐️ DaemonSet
确保全部(或者一些) Node
上运行 一个 Pod
的副本。当有 Node
加入集群时,也会为他们新增一个 Pod
。当有Node从集群移除时,这些 Pod
也会被回收。删除 DaemonSet
将会删除它创建的所有 Pod
- 使用
DaemonSet
的一些典型用法: - 运行集群存储
daemon
, 例如在每个Node
. 上运行glusterd
、ceph
。 - 在每个
Node
.上运行 日志收集daemon
, 例如fluentd
、logstash
。 - 在每个
Node
. 上运行监控daemon
, 例如Prometheus
Node
Exporter
为什么会有一些呢?因为我们可以在创建Pod的时候打上一个污点,这些被打上污点的就不会在被创建副本了
7️⃣ Job, Cron job
⭐️ Job
负责批处理任务,即仅执行一次的任务,它保证批处理任务的-一个或多个 Pod
成功结束
打个比方,就比如你运行一个脚本,job
就会判断你是不是正常退出,如果不是正常退出,他就会在去执行那个脚本,直到正常退出为止
⭐️ Cron Job 管理基于时间的Job, 在特定达到时间循环创建job 即:
- 在给定时间点只运行一次
- 周期性地在给定时间点运行
四、服务发现
1️⃣client
向 service
发送请求,这个请求会带有标签,service
就通过标签来寻找对应 Pod
2️⃣ 客户端向访问一组 pod
,但是 pod
和 pod
之间都不相干的时不可以通过 service
统一代理的,但是如果时同一个rc创建的或者有同一个标签就就可以访问代理
五、网络通讯方式
⭐️ Kubernetes
的网络模型假定了所有 Pod
都在一一个可以直接连通的扁平的网络空间中,这在GCE (Google Compute Engine
)里面是现成的网络模型,Kubernetes
假定这个网络已经存在。而在私有云里搭建Kubernetes 集群,就不能假定这个网络已经存在了。我们需要自己实现这个网络假设,将不同节点上的 Docker
容器之间的互相访问先打通,然后运行 Kubernetes
1️⃣同一个 Pod
内的多个容器之间通过lo回环通讯
2️⃣各个 Pod
之间通过 Overlay Network
来通讯
- 同节点通过
cni
网桥转发数据包 - 不同节点的
pod
需要通过网络插件来支持通讯
3️⃣ Pod
与 Servicer
之间的通讯就要通过各节点的Iptables
1️⃣Flannel
⭐️ Flannel
是 Core0S
团队针对 Kubernetes
设计的一一个网络规划服务,简单来说,它的功能是让集群中的不同节点主机创建的 Docker
容器都具有全集群唯一- 的虚拟 IP
地址。而且它还能在这些 IP
地址之间建立-一个覆盖网络(Overlay
Network
),通过这个覆盖网络,将数据包原封不动地传递到目标容器内
⭐️Flannel
首先创建了一个名为 flannel0
的网桥,而且这个网桥的一端连接 docker0
的网桥,另一端连接一个名为 flanneld
的服务进程。
⭐️ Flanneld
进程并不简单,它首先上连 etcd
,利用 etcd
来管理可分配的 IP
地址段资源,同时监控 etcd
中每个 Pod
的实际地址,并在内存中建立了一个 Pod
节点路由表;然后下连 docker0
和物理网络,使用内存中的 Pod
节点路由表,将 docker0
发给它的数据包包装起来,利用物理网络的连接将数据包投递到目标 flanneld
上,从而完成 pod
到 pod
之间的直接的地址通信。
⭐️ Flannel之间的底层通信协议的可选余地有很多,比如 UDP
、VXlan
、AWS VPC
等等。只要能通到对端的 Flannel
就可以了。源 Flannel
封包,目标 Flannel
解包,最终 docker0
看到的就是原始的数据,非常透明,根本感觉不到中间 Flannel
的存在。
2️⃣ETCD和Flannel
⭐️ 存储管理 Flannel
可分配的IP地址段资源,监控 ETCD
中每个 Pod
的实际地址,并在内存中建立委会 Pod
节点路由表
⭐️ 同一 Pod
内的网络通信。在同一个 Pod
内的容器共享同一个网络命名空间,共享同一个 Linux
协议栈。所以对于网络的各类操作,就和它们在同一台机器上一样,它们可以用 localhost
地址直接访问彼此的端口。其实这和传统的一组普通程序运行的环境是完全一样的,传统的程序不需要针对网络做特别的修改就可以移植了。这样做的结果是简单、安全和高效,也能减少将已经存在的程序从物理机或者虚拟机移植到容器下运行的难度。
⭐️Pod1
到 Pod2
的网络,分两种情况。Pod1
与 Pod2
不在同一台主机与 Pod1
与 Pod2
在同一台主机。
- 不在同一主机:
Pod
的地址是与docker0
在同一个网段的,但docker0
网段与宿主机网卡是两个完全不同的IP
网段,并且不同Node
之间的通信只能通过宿主机的物理网卡进行。将Pod
的IP
和所在Node
的IP
关联起来,通过这个关联让Pod
可以互相访问。 - 在同一主机:
Pod1
和Pod2
在同一台主机的话,由Docker0
网桥直接转发请求到Pod2
,不需要经过Flannel
。
⭐️ Pod
到 Service
的网络。创建一个 Service
时,相应会创建一个指向这个 Service
的域名,域名规则为{服务名}.{namespace
}.svc
.{集群名称}。之前 Service
IP的转发由 iptables
和 kube-proxy
负责,目前基于性能考虑,全部为 iptables
维护和转发。iptables
则由 kubelet
维护。Service
仅支持UDP和 TCP
协议,所以像 ping
的 ICMP
协议是用不了的,所以无法 ping
通 Service
IP
。
⭐️ Pod
到外网。Pod
向外网发送请求,查找路由表, 转发数据包到宿主机的网卡,宿主网卡完成路由选择后,iptables
执行 Masquerade
,把源IP更改为宿主网卡的 IP
,然后向外网服务器发送请求。
⭐️ 集群外部访问 Pod
或 Service