一、Pod 控制器类型
Pod概念
当一个 Pod 创建后,Pause 容器就会随着 Pod 启动,只要是有 Pod,Pause 容器就要被启动。
在同一个 Pod 里面的容器不能出现端口冲突,否则这个 Pod 可能会出现无法启动、无限重启。
一个 Pod 里面的容器数量是大于等于1。
Pod 里面的容器都是共享 Pause 的网络栈,在同一个 Pod 里即共享网络又共享存储卷。
RC和RS概念
Replication Controller 用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的 Pod 来代替;而如果异常多出来的容器也会自动回收。
在 K8s 新版本中,官方不再使用RC(Replication Controler),建议使用 RS(ReplicaSet)代替,因为RS支持集合式的 selector。
ReplicaSet 跟 Replication Controller 没有本质区别,只是名字不一样,并且 ReplicaSet 支持集合式的 selector。
支持集合式的 selector 作用:
在创建 Pod 的时候会为它打上标签(tag),也会为 Pod 里面的容器打上标签,当需要删除容器或者进行其他操作的时候,可以通过标签来进行相关操作。
Deployment原理:
RS 不支持滚动更新,但是 Deployment 支持滚动更新,RS 和 Deployment 建议一起使用的原因是 Deployment 不负责 Pod 创建,Deployment 需要创建 RS 来达到创建 Pod 的能力。
Deployment 结合 RS 使用,滚动更新:
Deployment 创建出来之后,它会去创建一个 RS,Deployment 再去负责创建对应 Pod;
当某一天需要版本更新,Deployment 会去新建一个RS-2版本,在RS-2下启动v2版本的第一个容器,则退出v1版本的第一个容器,以此类推...到达滚动更新状态。
回滚:
回滚的机制是因为 Deployment 在滚动更新之后,RS-1并没有删除,而是被停用状态,当执行回滚的时候,Deployment 就好启动旧版本的RS-1,到达一个回滚效果。
StatefulSet概念
StatefulSet 是为了解决有状态服务的问题,有状态服务分为 MySQL、MongoDB 等,无状态服务分为 Nginx、Apache 等。
应用场景包括:
- 稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现;
- 稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service 来实现;
- 有序部署,有序扩展;
- 有序收缩,有序删除。
DaemonSet概念
DaemonSet 确保全部(或者一些)Node上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个 Pod。当有 Node 从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。
使用 DaemonSet 的一些典型用法:
- 运行集群存储 daemon,例如在每个 Node 上运行 glusterd、ceph。
- 在每个 Node 上运行日志收集 daemon,例如fluentd、logstash。
- 在每个 Node 上运行监控 daemon,例如Prometheus Node Exporter。
Job
Job 负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束。
Job 如果判断这个脚本不是正常退出,则重新执行一遍,直到正常退出为止,并且还可以设置正常退出次数,比如正常退出次数两次,才允许这个脚本执行成功。
CronJob
CronJob 是一个计划任务,跟 Linux 的 Crontab 类似,编写的格式跟 Linux 的 Crontab 一样。
可以通过一些参数来自定义任务,比如:
failedJobHistoryLimit: # 为失败的任务执行保留的历史记录数,默认为1
successfulJobHistoryLimit:# 为成功的任务执行保留的历史记录数,默认为3
startingDeadlineSeconds: # 因各种原因缺失执行作业的时间点所导致的启动作业错误的超时时长,会被计入错误历史记录
suspend: # 是否挂起后续的任务执行,默认为false,对运行中的作业不会产生影响
二、服务发现
service概念
如果 Pod 之间没有相干性,是无法通过一个 Service 代理或者收集的。
Service收集的机制:
第一、比如是通一个 RC、RS、Deployment 创建的 Pod;
第二、或者拥有同一组标签,Service 通过标签来收集 Pod。
三、网络通信方式
同一个 Pod 内部通信
同一个 Pod 共享同一个网络命名空间,共享同一个Linux协议栈,使用回环网卡(lo)通信。
两个不同 Pod 之间访问
Pod1 与 Pod2 不在同一台主机的情况:
Pod 的地址是与 docker0 在同一个网段的,但是 docker0 网段与宿主机网卡是两个完全不同的IP网段,并且不同 Node 之间的通信只能通过宿主机的物理网卡进行。
将 Pod 的 IP 和所在 Node 的IP关联起来,通过这个关联让 Pod 可以互相访问。
假设 Web APP2 需要访问 Backend:
源地址写自己的(10.1.15.2/24),目标地址写(10.1.20.3/24);
由于目标地址不是跟 Web app2 同一网段,所以发送数据包到网关(Docker0);
Docker0网关发送到 Flannel0,Flannel0 有一个路由表存储在 Etcd 中,根据路由表来进行转发;
Flannel0 将数据包转发到 Flanneld,因为 Flannel0 是 Flanneld 中的一个网桥;
到 Flanneld 之后,它会对该数据报文进行二次封装,请看上图右边数据封装结构;
此时数据包到了66.12这台机器上:
Flanneld 收到数据包后,解封数据包之后转发到 Flannel0 网桥中;
Flannel0 转发到 Docker0,Docker0 根据目标IP地址转发到 Backend 容器中;
因为 Docker0 只能看到第二层源IP地址和目标IP地址,第一层源IP地址和目标IP地址已经被砍掉了。
Pod1 与 Pod2 在同一台主机情况:
由 docker0 网桥直接转发请求到 Pod2,不需要经过 Flannel。
组件通讯示意图
节点网络:真实网络,就是节点主机的物理网卡;
Pod 网络:虚拟网络,所有的 Pod 之间通信都是通过该网络;
Service 网络:虚拟网络,通过 Service 网络访问后端Pod。
以上有不恰当或者讲得不对的地方,希望各位留言指正,谢谢!
站在巨人的肩膀上!