近几年来,随着以 Docker 为代表的容器技术的出现,终结了之前 DevOps 中交付和部署环节因环境、配置及程序本身的不同而造成的动辄几种甚至几十种部署配置的困境,将它们统一在容器镜像上。但 Docker 更适用于管理单个容器,一旦开始使用越来越多的容器封装和运行应用程序,必将会导致其管理和编排变得越来越困难。最终,用户不得不对容器实施分组,以便跨所有容器提供网络、安全、监控等服务。于是,以 Kubernetes 为代表的容器编排系统应运而生。本文就是对 Kubernetes 做一个简单的总结,主要从 Kubernetes 架构、组件和核心概念来简单讲述,是一篇关于 Kubernetes 的入门文章。

什么是 Kubernetes

Kubernetes(因为首尾字母中间有 8 个字符,所以被简写成 K8s),它是一个是用于自动部署、扩展和管理容器化应用程序的工业级容器编排平台,尽管公开面世不过短短数年,但 Kubernetes 已经成为容器编排领域事实上的标准。

Kubernetes(来自希腊语,意为 “舵手” 或 “飞行员”)是由 Joe Beda、Brendan Burns 和 Craig McLuckie 创立,而后 Google 的其他几位工程师,包括 Brian Grant 和 Tim Hockin 等加盟共同研发,并由 Google 在 2014 年首次对外宣布。Kubernetes 的开发和设计都深受 Google 内部系统 Borg 的影响,事实上,它的许多顶级贡献者之前也是 Borg 系统的开发者。

2015年4月,Borg 论文《Large-scale cluster management at Google with Borg》 首次公开,有兴趣的同学可以看一下。

Kubernetes 的发展历程如下图所示(图片来自 Kubernetes Introduction),

Kubernetes History

Kubernetes 的特性

Kubernetes 本质上是底层资源与容器间的一个抽象层,如果和单机架构类比,有点类似于分布式时代的 Linux,它旨在提供一个可预测性、可扩展性与高可用性的方法来完全管理容器化应用程序和服务的生命周期的平。简单总结起来,它具有以下几个重要特性:

  1. 自动装箱(调度):建构于容器之上,基于资源依赖及其他约束自动完成容器部署且不影响其可用性,并通过调度机制混合关键型应用和非关键型应用的工作负载于同一节点以提升资源利用率
  2. 自我修复(自愈):支持容器故障后自动重启、节点故障后重新调度容器,以及其他可用节点、健康状态检查失败后关闭容器并重新创建等自我修复机制;
  3. 水平扩展(可扩展):支持通过简单命令或 UI 手动水平扩展,以及基于 CPU 等资源负载率的自动水平扩展机制;
  4. 服务发现和负载均衡:Kubernetes 通过其附加组件之一的 KubeDNS(或 CoreDNS)为系统内置了服务发现功能,它会为每个 Service 配置 DNS 名称,并允许集群内的客户端直接使用此名称发出访问请求,而 Service 则通过 iptablesipvs 内建了负载均衡机制;
  5. 自动发布和回滚:Kubernetes 支持 灰度 更新应用程序或其配置信息,它会监控更新过程中应用程序的健康状态,以确保它不会在同一时刻杀掉所有实例,而此过程中一旦有故障发生,就会立即自动执行回滚操作;
  6. 密钥和配置管理:Kubernetes 的 ConfigMap 实现了配置数据与 Docker 镜像解耦,当需要时,仅对配置做出变更而无须重新构建 Docker 镜像,这为应用开发部署带来了很大的灵活性。此外,对于应用所依赖的一些敏感数据,如用户名和密码、令牌、密钥等信息,Kubernetes 专门提供了 Secret 对象为其解耦,既便利了应用的快速开发和交付,又提供了一定程度上安全保障;
  7. 存储编排:Kubernetes 支持 Pod 对象按需自动挂载不同类型的存储系统,这包括节点本地存储、公有云服务商的云存储(如 AWS 和 GCP 等),以及网络存储系统(例如,NFS、iSCSI、GlusterFS、Ceph、Cinder 和 Flocker 等);
  8. 批量处理执行:除了服务型应用,Kubernetes 还支持批处理作业及 CI(持续集成),如果需要,一样可以实现容器故障后恢复。

Kubernetes 架构

这里我们先来看下 Kubernetes 的架构图,如下图所示(图片来自 Kubernetes Introduction):

Kubernetes 架构图

可以看出,Kubernetes 架构是一个比较典型的二层架构和 server-client 架构:

  1. Master: 作为中央的管控节点,会去与 Node 进行一个连接。所有 UI 的、clients、这些 user 侧的组件,只会和 Master 进行连接,把希望的状态或者想执行的命令下发给 Master,Master 会把这些命令或者状态下发给相应的节点,进行最终的执行;
  2. Node: Node 的职责是运行容器应用,Node 由 Master 管理,Node 负责监控并汇报容器的状态,同时根据 Master 的请求管理容器的生命周期。

下面分别来看下 Master 和 Node 组件内部的一些核心服务。

Kubernetes 组件 – Master

Master 节点主要由 API Server、Controller Manager 和 Scheduler 三个组件,以及一个用于集群状态存储的 etcd 存储服务组成:

  1. API Server: 提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制;
  2. Controller Manager: 负责维护集群的状态,比如:故障检测、自动扩展、滚动更新等;
  3. Scheduler: 负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上(K8s 还支持用户自定义调度器);
  4. etcd: 集群的所有状态信息都需要持久存储于存储系统 etcd 中,不过,etcd 是由 CoreOS 基于 Raft 协议开发的分布式键值存储,可用于服务发现、共享配置以及一致性保障(如数据库主节点选择、分布式锁等)。

Kubernetes 组件 – Node

Node 负责提供运行容器的各种依赖环境,并接受 Master 的管理。每个 Node 主要由以下几个组件构成:

  1. kubelet: 它是运行于工作节点之上的守护进程,负责容器的生命周期,也负责 Volume 和 网络的管理,它从 API Server 接收关于 Pod 对象的配置信息并确保它们处于期望的状态,kubelet 会在 API Server 上注册当前工作节点,定期向 Master 汇报节点资源使用情况,并通过 cAdvisor 监控容器和节点的资源占用状况;
  2. Container Runtime: 负责镜像下载、管理以及 Pod 和容器的真正运行;
  3. kube-proxy: 负责为 Service 提供 Cluster 内部的服务发现和负载均衡。

Kubernetes 核心附件

Kubernetes 集群还依赖于一组称为 ”附件”(add-ons)的组件以提供完整的功能,它们通常是由第三方提供的特定应用程序,且托管运行于 Kubernetes 集群之上,如下图所示(图片来自 《Kubernetes 进阶实战》):

Kubernetes 组件图

下面列出的几个附件各自为集群从不同角度引用了所需的核心功能:

  1. KubeDNS: 在集群中调度运行提供 DNS 服务的 Pod,同一集群中的其他 Pod 可使用此 DNS 服务解决主机名;
  2. Kubernetes Dashboard: 集群的全部功能都要基于 Web 的 UI 来管理集群中的应用设置是集群自身;
  3. Heapster: 容器和节点的性能监控与分析系统,它收集并解析多种指标数据,如资源利用率、生命周期事件等;
  4. Ingress Controller: Service 是一种工作与传统层的负载均衡器,而 Ingress 是在应用层实现的 HTTP(s) 负载均衡机制,Ingress 只是一组路由规则的集合,这些规则需要通过 Ingress Controller 发挥作用。

Kubernetes 的核心概念

前面已经了解了 Kubernetes 的架构及组件信息,这里我们来总结一下 Kubernetes 生态下一些核心概念,只有了解并理解这些概念,才能更好地使用 Kubernetes。

Pod

Kubernetes 并不直接运行容器,而是使用一个抽象的资源对象来封装一个或者多个容器,这个抽象即为 Pod,它也是 Kubernetes 的最小调度单元(可以参考 Kubernetes 指南之 POD)。用户可以通过 Kubernetes 的 Pod API 生产一个 Pod,让 Kubernetes 对这个 Pod 进行调度,也就是把它放在某一个 Kubernetes 管理的节点上运行起来。一个 Pod 简单来说是对一组容器的抽象,它里面会包含一个或多个容器。

Kubernetes 之 POD

特点:

  1. Pod 资源对象是一种集合了一到多个应用容器、存储资源、专用 IP 及支撑容器运行的其他选项的逻辑组件;
  2. 所有 Pod 内部的容器可以访问共享的 Volume 和共享数据;

Volume

我们知道容器的数据都是非持久化的,在容器消亡以后数据也跟着丢失,所以 Docker 提供了 Volume 机制以便将数据持久化存储。Volume 本身就是卷的概念,它是用来管理 Kubernetes 存储的,是用来声明在 Pod 中的容器可以访问的文件目录的,一个卷可以被挂载在 Pod 中一个或者多个容器的指定路径下面。

而 Volume 本身是一个抽象的概念,一个 Volume 可以去支持多种的后端的存储。比如说 Kubernetes 的 Volume 就支持了很多存储插件,它可以支持本地的存储,可以支持分布式的存储,比如说像 ceph,GlusterFS ;它也可以支持云存储,比如说阿里云上的云盘、AWS 上的云盘、Google 上的云盘等等(在资源描述文件的配置方式参考 Kubernetes 指南之 Volume)。

ReplicaSet

ReplicaSet(也简称为 RS,K8s 之前的版本这个功能叫做 Replication Controller)用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的 Pod 来替代;而异常多出来的容器也会自动回收(这些都是由 Master 端的 Controller Manager 来做的)。ReplicaSet 的典型应用场景包括确保健康 Pod 的数量、弹性伸缩、滚动升级以及应用多版本发布跟踪等。

资源配置文件的使用示例,参考 Kubernetes 指南之 ReplicaSet 示例

Deployment

Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义 (declarative) 方法,用来替代以前的 ReplicationController 或 ReplicaSet 来更方便的管理应用。

Deployment 是在 Pod 这个抽象上更为上层的一个抽象,它可以定义一组 Pod 的副本数目、以及这个 Pod 的版本,一般大家用 Deployment 这个抽象来做应用的真正的管理,而 Pod 是组成 Deployment 最小的单元。

比如说我可以定义一个 Deployment,这个 Deployment 里面需要两个 Pod,当一个 Pod 失败的时候,控制器就会监测到,它重新把 Deployment 中的 Pod 数目从一个恢复到两个,通过再去新生成一个 Pod。通过控制器,我们也会帮助完成发布的策略。比如说进行滚动升级,进行重新生成的升级,或者进行版本的回滚。

Deployment 的资源配置声明及相关的操作命令参考:Kubernetes 指南之 Deployment

一个简单的、3 副本的 nginx 应用的资源配置文件可以定义为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80

Service

Service 是对一组提供相同功能的 Pods 的抽象,并为它们提供一个统一的入口,借助 Service,应用可以方便的实现服务发现与负载均衡,并实现应用的零宕机升级,Service 通过标签来选取服务后端,一般配合 ReplicaSet(简称 RS)或者 Deployment 来保证后端容器的正常运行。这些匹配标签的 Pod IP 和端口列表组成 endpoints,由 kube-proxy 负责将服务 IP 负载均衡到这些 endpoints 上,如下图所示(图片来自 Overview of a Service):

Kubernetes Service

关于 Service,个人的理解是,它只是一种抽象,通过 label(资源标签)绑定到对应的 RC 和 Deployment 上,它是不会创建 Pod 的,Pod 还是由 RS 或 Deployment 创建的。下面是一个示例,这个 Service 将服务的 80 端口转发到 default namespace 中带有标签 run=nginx 的 Pod 的 80 端口上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: Service
metadata:
labels:
run: nginx
name: nginx
namespace: default
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
run: nginx
sessionAffinity: None
type: ClusterIP

Namespace

Namespace 是对一组资源和对象的抽象集合(Kubernetes 指南之 Namespace),比如可以用来将系统内部的对象划分为不同的项目组或用户组。常见的 Pod, service, Replication Controller 和 Deployment 等都是属于某一个 namespace 的(默认是 default),而 node, persistent volume,namespace 等资源则不属于任何 namespace。

Namespace 常用来隔离不同的用户,比如 Kubernetes 自带的服务一般运行在 kube-system namespace 中。

常用的命令:

1
2
3
4
5
6
7
8
9
10
# 查询 K8s 的 namespace 信息
kubectl get namespaces

# 命令行直接创建 namespace
kubectl create namespace new-namespace
# 通过资源描述文件来创建 namespace
kubectl create -f ./my-namespace.yaml

# 删除 namespace
kubectl delete namespaces new-namespace

其他

其他还是有一些比较重要的资源对象,只不过这些没有上面这些常用,大家可以参考 Kubernetes 指南之资源对象

小结

这篇文章主要是对 Kubernetes 的架构、组件及核心的概念做了一下梳理,并没有涉及特别深入的内容,正如文章标题所述,算是一篇入门的文章介绍,以后如果有机会、有时间个人计划是好好研究一下 Kubernetes,更新一些稍微深入的内容。


参考: