传统应用面临的问题

随着应用的规模变得越来越庞大,逻辑也越来越复杂,迭代更新也越来越频繁 ,逐渐发现了一些问题:

  • 性价比低,资源利用率低

有时候用户只是希望运行一些简单的程序而已,比如跑一个小进程,为了不相互影响,就要建立虚拟机。这显然会浪费不少资源,毕竟 IaaS 层产品都是按照资源进行收费的。同时操作也比较复杂,花费时间也会比较长;

  • 迁移成本高

如果想要迁移整个自己的服务程序,就要迁移整个虚拟机。显然,迁移过程也会很复杂;

  • 环境不一致

在进行业务部署发布的过程中,服务之间的各种依赖,比如操作系统、开发语言及其版本、依赖的库/包等,都给业务开发和升级带来很大的制约。
如果没有 Docker 的横空出世,这些问题解决起来似乎有些困难。

Docker


这个新的容器管理引擎大大降低了使用容器技术的门槛,轻量、可移植、跨平台、镜像一致性保障等优异的特性,一下子解放了生产力。开发者可以根据自己的喜好选择合适的编程语言和框架,然后通过微服务的方式组合起来。交付同学可以利用容器保证交付版本和交付环境的一致性,也便于各个模块的单独升级。测试人员也可以只针对单个功能模块进行测试,加快测试验证的速度。

在某一段时期内,大家一提到 Docker,就和容器等价起来,认为 Docker 就是容器,容器就是Docker。其实容器是一个相当古老的概念,并不是 Docker发明的,但 Docker 却为其注入了新的灵魂——Docker 镜像

Docker 镜像解决了环境打包的问题,它直接打包了应用运行所需要的整个“操作系统”,而且不会出现任何兼容性问题,它赋予了本地环境和云端环境无差别的能力,这样避免了用户通过“试错”来匹配不同环境之间差异的痛苦过程, 这便是 Docker 的精髓。

它通过简单的 Dockerfile 来描述整个环境,使开发者可以随时随地构建无差别的镜像,方便了镜像的分发和传播。相较于以往通过光盘、U盘、ISO文件等方式进行环境的拷贝复制,Docker镜像无疑把开发者体验提高到了前所未有的高度。这也是 Docker 风靡全球的一个重要原因。

容器调度平台


如果我们大规模地使用容器,就不得不考虑容器调度、部署、跨多节点访问、自动伸缩等问题。 | 能力 | 解释 | | —- | —- | | 调度 | 自动生成容器实例 | | 亲和/反亲和 | 生成的容器可以相邻或者相隔,帮助提高可用性和性能 | | 健康检查 | 自动检测容器的健康状态 | | 容错 | 自动在健康的节点上重新生成容器实例 | | 可扩展 | 自动根据需要增加或者删除容器实例 | | 网络 | 允许容器之间互相通信 | | 服务发现 | 允许容器之间互相发现 | | 滚动升级 | 容器升级可以避免对业务操作影响,同时可以出错回滚 |

首先容器调度平台可以自动生成容器实例,然后是生成的容器可以相邻或者相隔,帮助提高可用性和性能,还有健康检查、容错、可扩展、网络等功能,它几乎完美地解决了需求与资源的匹配编排问题。

2014 年 6 月 7 日的第一个 commit 拉开了 Kubernetes 的序幕。它基于 Google 内部超过 15 年历史的大规模集群管理系统 Borg ,集结其精华,可以对容器进行编排管理、自动部署、弹性伸缩等操作,它于 2015 年 7 月 21 日正式对外发布第一版本,走进了大众视线。

经过 6 年的时间,Kubernetes 成为云厂商的“宠儿”,而且国内的诸多大厂已经在生产环境中大规模使用 Kubernetes,用于运行自己的核心业务系统,无数中小企业也都在进行业务容器化探索以及云原生化改造。

在Kubernetes中,你可以直接通过 YAML 或者 JSON 进行声明,然后通过 PATCH 的方式就可以完成对 API 对象的多次修改,而无须关心原始 YAML 或 JSON 文件的内容。可以说声明式 API 也是 Kubernetes 项目能够成为事实标准的一个核心所在。

kubernetes架构


📚K8S简介 - 图1

控制面三大组件

Kubernetes 的控制面包含着 kube-apiserver、kube-scheduler、kube-controller-manager 这三大组件

kube-apiserver,它是整个 Kubernetes 集群的“灵魂”,是信息的汇聚中枢,提供了所有内部和外部的 API 请求操作的唯一入口。同时也负责整个集群的认证、授权、访问控制、服务发现等能力。
用户可以通过命令行工具 kubectl 和 APIServer 进行交互,从而实现对集群中进行各种资源的增删改查等操作。APIServer 跟 BorgMaster 非常类似,会将所有的改动持久到 Etcd 中,同时也保存着一份内存拷贝。
这也是为什么我们希望 Master 节点可以性能好、资源规格大,尤其是当集群规模很大的时候,APIServer 的吞吐量以及占用的 CPU 和内存都要很大。APIServer 还提供很多可扩展的能力,方便增强自己的功能。

Kube-Controller-Manager,它负责维护整个 Kubernetes 集群的状态,比如多副本创建、滚动更新等。Kube-controller-manager 并不是一个单一组件,内部包含了一组资源控制器,在启动的时候,会通过 goroutine
拉起多个资源控制器。这些控制器的逻辑仅依赖于当前状态,因为在分布式系统中没办法保证全局状态的同步。
同时在实现的时候避免使用过于复杂的状态机,因此每个控制器仅仅对自己对应的资源对象做操作。而且控制器做了很多容错处理,比如增加 retry 机制等。

Kube-scheduler,它的工作简单来说就是监听未调度的 Pod,按照预定的调度策略绑定到满足条件的节点上。这个工作虽说看起来是三大件中最简单的,但是做的事情可一点不少。

计算节点相关组件

  • 容器运行时主要负责容器的镜像管理以及容器创建及运行。大家都知道的 Docker 就是很常用的容器,此外还有 KataFrakti等。只要符合 CRI(Container Runtime Interface,容器运行时接口)规范的运行时,都可以在 Kubernetes 中使用。
  • Kubelet 负责维护 Pod 的生命周期,比如创建和删除 Pod 对应的容器。同时也负责存储和网络的管理。一般会配合 CSI、CNI 插件一起工作。
  • Kube-Proxy 主要负责 Kubernetes 内部的服务通信,在主机上维护网络规则并提供转发及负载均衡能力。

常用附件

  1. CoreDNS 负责为整个集群提供 DNS 服务;
  2. Ingress Controller 为服务提供外网接入能力;
  3. Dashboard 提供 GUI 可视化界面;
  4. Fluentd + Elasticsearch 为集群提供日志采集、存储与查询等能力。

Master 和 Node 的交互方式

在这一点上,Kubernetes 和 Borg 完全相反。Kubernetes 中所有的状态都是采用上报的方式实现的。APIServer 不会主动跟 Kubelet 建立请求链接,所有的容器状态汇报都是由 Kubelet 主动向 APIServer 发起的。

当集群资源不足的时候,可以按需增加Node 节点。一旦启动 Kubelet 进程以后,它会主动向 APIServer 注册自己,这是 Kubernetes 推荐的 Node 管理方式。当然你也可以在Kubelet 启动参数中去掉自动注册的功能,不过一般都是默认开启这个模式的。

一旦新增的 Node 被 APIServer 纳管进来后,Kubelet 进程就会定时向 APIServer 汇报“心跳”,即汇报自身的状态,包括自身健康状态、负载数据统计等。当一段时间内心跳包没有更新,那么此时 kube-controller-manager 就会将其标记为NodeLost(失联)。这也是 Kubernetes 跟 Borg 有区别的一个地方。Kubernetes 中各个组件都是以 APIServer 为中心,通过松耦合的方式进行。借助声明式 API,各部件通过 watch 的机制就可以根据各个对象的变化,很快地做出相应的处理操作。

容错性和可扩展性

假定有发生任何错误的可能,通过 backoff retry、多副本、滚动升级等机制,增强集群的容错性,提高 Kubernetes 系统的稳定性。同时对各个组件增加可扩展能力,保证 Kubernetes 对新功能的接入能力,让人们可以对 Kubernetes 进行个性化定制。

各个组件的证书


etcd 集群内部各 member 之间需要一对 CA (Certificate Authority)用于签发证书,然后签发出一对 TLS 证书用于内部各 member 之间的数据互访和同步。
同时 etcd 集群需要对外暴露服务,方便 kube-apiserver 可以读写数据,这个时候就需要一对 CA 和 一对 TLS 证书。一般来说,为了方便,我们这里可以使用同一份 CA 证书来签发证书。

kube-apiserver 跟 etcd 集群之间的访问,我们也需要用 etcd 的 CA 证书,单独为 kube-apiserver 签发一对 TLS 证书。

Kubernetes 集群内部其他各组件,包括 kube-controller-manager、kube-scheduler、kubelet、kube-proxy 等,与 kube-apiserver 都需要安全访问,因此我们还需要一对 CA 证书,用于签发各个组件的 TLS 证书。同时
kube-apiserver 有时需要主动向 kubelet 发起连接,那么这里还需要为 kube-apiserver 签发一对 TLS 证书。