1 背景

随手记,测试环境资源不足,一台服务器有多个服务,存在以下问题:

  1. 服务输出过多日志,写满磁盘,导致整个环境不可用
  2. 服务使用直接内存,占用内存导致 load、swap 飙升
  3. 服务密集使用CPU,时间分片短,CPU压力大

2 资源隔离

虚拟机也可以限制 cpu、memory、disk 的使用,但要在 host os 的基础上运行一个 guest os,资源消耗较大,所以选取了更轻量的 docker 容器。

3 容器编排

虚拟机的运维可以使用 Ansible,容器的运维则需要容器编排平台,有3个基本要求:

  1. 调度。选择出最合适的宿主机,并启动容器
  2. 故障转移。通过存活探针对容器健康检查,并适时重启、再调度
  3. 水平伸缩。容器算力不够时自动扩容

此外,编排平台还可以支持服务发现、负载均衡等功能。
前期容器化的服务不多,我们使用 swarm 做容器编排。但服务多起来后,出现调度失败,负载均衡跟不上再调度等情况。
swarm 集群单个 leader,这就决定它无法横向扩展,如果开启负载均衡,那么 leader 的单点问题会更突出。
我们需要能在生产运行的容器编排平台,这里综合比对 Kubernetes 和 mesos。

3.1 集群规模

kubernetes 是面向容器的编排工具,帮助淘宝在 2017 年管理近 8000个节点。
mesos 是面向资源的调度平台,帮助 twitter 管理上万个节点。
随手记线上机器规模在 500 台左右,两者都可以考虑。

3.2 维护成本

mesos 只关心资源,应用层通过 framework 实现。
我们几乎所有容器都运行长期伺服型应用,除了安装 marathon,还要安装 marthon-lb 实现负载均衡,安装 mesos-dns 实现服务发现。
痛点是技术栈混杂,其中 marthon 用 c++ 实现,marthon-lb 用 scala 使用,mesos-dns 用 python 实现,难以维护。
kubernetes 从调度器 Scheduler,到插件 CSI、CNI,甚至底层数据库 etcd 都是 go 实现,对随手记这种规模的公司更加友好。

3.3 健康检查

mesos 初衷是建立一个大数据场景下的资源共享池,没有考虑对容器的支持,后天弥补的健康检查有性能缺陷。
健康检查由 marthon 实现,有两个痛点:

  1. 检测进程、应用进程不在同一主机,带来额外的网络负担,并且不稳定的网络也会导致错误的检查结果
  2. marthon 的首要任务是调度,同时做健康检查可能引起过高的IO负载
    kubernetes 在每一个节点有一个 kube-proxy 进程,负责对同主机的应用进程做健康检查,并上报到 kube-api,设计精良。

3.3 网络

mesos 提供主机模式、桥接模式。主机模式下的端口由容器使用,可能会导致端口冲突。桥接模式下,容器端口使用端口映射桥接到动态分配的主机端口。
kubernetes 开放 CNI 网络插件,使用 veth pair 实现内部网络,也支持通过外部网络暴露服务。
网络方面,二者功能相当,均可考虑。

3.4 存储

masos + marthon 提供本地存储、外部存储。
kubernetes 开放 CSI 存储插件,同时抽出 PV、PVC,方便开发、运维工作分离。
随手记有部分业务读写文件系统,如果没有外部存储,再调度后去到别的节点,就看不到上次生成的文件。
由于 marthon 的外部存储是 beta 特性,因此考虑 kubernetes。

3.5 调度逻辑

亲密关系调度 要把两个容器调度在同一个宿主机。超亲密关系调度 要让两个容器共享同一个 namespace(网络、存储)。
假设容器A申请1G内存,容器B申请0.5G内存,现在要统一调度它们:

  1. mesos 悲观调度,也就是资源囤积,当所有设置了 Affinity 约束的任务都达到时,才开始统一调度。调度效率低,并存在死锁问题
  2. borg 乐观调度,先调度,不满足了再回滚。调度效率高
  3. kubernetes 原子调度,将两个容器需要的资源捆绑在一起申请。调度效率、资源利用率平衡

3.6 社区活跃度

关注度 mesos 4.6k,kubernetes 71.3k
参与度 mesos 17,kubernetes 865
issue mesos 0,kubernetes 2k
综上,kubernetes 在技术、生态层面比 mesos 都领先,所以选择 kubernetes。

参考文献