四、理解 Pod 和容器设计模式

2022-09-21 10:13:43 浏览数 (1)

为什么需要 Pod

容器的本质

  • 一个视图被隔离、资源受限的进程
  • 容器里 PID = 1 的进程就是应用本身
  • 管理虚拟机 = 管理基础设施;管理容器 = 管理应用本身

Kubernetes

  • 云时代的“操作系统”
  • 容器就是这个操作系统的软件安装包

进程组

有的应用由多个进程组成,这些进程共享应用的资源,相互协作以达到应用的功能。

容器管理多进程的应用

容器是单线程模型,只能管理一个进程,容器的生命周期和这个进程关联。这会导致其他进程因为主进程的停止而成为无人管理状态,相关资源无法回收。

Pod

Pod 实际上正是 kubernetes 项目抽象出来的一个可以类比为进程组的概念。多进程的应用对应一个 Pod,每个进程对应一个容器。

应用之间往往有着密切的协作关系,使得它们必须部署在同一台机器上并且共享某些信息。

为什么 Pod 必须是原子调度单位?

为什么要把 Pod 的概念抽象出来,而不是通过调度来解决?

  • 举例:两个容器紧密协作
    • App:业务容器,产生日志
    • LogCollector:上传日志文件到 ElasticSearch
  • 内存要求
    • App:1g
    • LogCollector:0.5g
  • 可用节点
    • Node_A:1.25g
    • Node_B:2g

如果调度前没有考虑整个 Pod 所需配置,就有可能将 App 放置到 Node_A,导致 LogCollector 无法调度。

其他解决方案
Mesos
  • 当所有设置了 Affinity 约束的任务都达到时,才开始统一调度,这是一个非常典型的成组调度的解法。
  • 调度效率会损失,可能产生死锁。
Google:Omega
  • 乐观调度,不管这些冲突的异常情况,先调度,同时设置一个非常精妙的回滚机制,这样经过冲突后,通过回滚来解决问题。
  • 实现复杂,悲观锁的设置一定比乐观锁要简单。

再次理解 Pod

亲密关系 - 调度解决
  • 两个应用需要运行在同一台宿主机上。
超亲密关系 - Pod 解决
  • 会发生直接的文件交换
  • 使用localhost或者Socket文件进行本地通信(效率高)
  • 发生非常频繁的RPC调用
  • 共享某些Linux Namespace(比如一个容器要加入另一个容器的Network Namespace)

Pod 的实现机制

Pod 要解决的问题

如何让一个 Pod 里的多个容器之间最高效的共享某些资源和数据。

共享网络

在每个 Pod 里,额外起一个 Infra container 小容器来共享整个 Pod 的 Network Namespace。

Infra container 是一个非常小的镜像,大概 100~200KB 左右,是一个汇编语言写的、永远处于“暂停”状态的容器。由于有了这样一个 Infra container 之后,其他所有容器都会通过 Join Namespace 的方式加入到 Infra container 的 Network Namespace 中。

整个 Pod 里面,必然是 Infra container 第一个启动。并且整个 Pod 的生命周期是等同于 Infra container 的生命周期的,与容器 A 和 B 是无关的。这也是为什么在 Kubernetes 里面,它是允许去单独更新 Pod 里的某一个镜像的,即:做这个操作,整个 Pod 不会重建,也不会重启,这是非常重要的一个设计。

共享存储

把 volume 变成了 Pod level。所有同属于一个 Pod 的容器,共享所有的 volume。

详解容器设计模式

示例

WAR 包 Tomcat 的容器化

方法一
  • 将WAR包和Tomcat打包到一个镜像
  • 无论是WAR包和Tomcat更新都需要重新制作镜像
方法二
  • 镜像只打包Tomcat,使用 Volume 把WAR包挂载到Tomcat里
  • 容器所在的宿主机不固定,取决于 Scheduler,可以使用分布式存储系统,但太复杂了

InitContainer

  • 比spec.containers定义的用户容器先启动,并且 InitContainer 严格按照定义的顺序执行,而用户定义的 container 是并发启动
  • 可以在InitContainer中,将WAR包写到volume里,供后续启动的Tomcat容器使用

容器设计模式:Sidecar

在 Pod 里面,可以定义一些专门的容器,来执行主业务容器所需要的一些辅助工作。

Sidecar:应用与日志收集
  • 前置操作,例如执行初始化脚本
  • 日志收集,本身是一个进程,一个小容器,那么就可以把它打包进 Pod 里面去做这个收集工作;
  • 监控 Pod 里的应用
  • 还有一个非常重要的东西就是 Debug 应用,在应用 Pod 里面再次定义一个额外的小的 Container,它可以去 exec 应用 pod 的 namespace;
Sidecar:代理容器
  • 访问外部服务集群,但该集群未提供负载均衡,所以访问地址有多个。
  • 该负载均衡功能抽取为代理容器。
  • 在 Pod 内部,同一 Network Namespace,可以使用 localhost 直接通信,没有性能损耗
Sidecar:适配器容器
  • 将接口转换封装到容器里
  • 适配器模式
好处
  • 辅助操作和主要业务解耦
  • 监控 Sidecar ,日志 Sidecar,代理容器 Sidecar 可以被复用

0 人点赞