12.Docker与Kubernetes——生产级容器集群平台
Kubernetes是Google团队发起并维护的开源容器集群管理系统,底层基于Docker、rkt等容器技术,提供强大的应用管理和资源调度能力。Kubernetes已经成为目前容器云领域影响力最大的开源平台,使用Kubernetes,用户可以轻松搭建和管理一个可扩展的生产级别容器云。
1.简介
作为一套分布式应用容器集群系统,Kubernetes拥有鲜明的技术优势:
- 优秀的API设计,以及简洁高效的架构设计,主要组件个数很少,彼此之间通过接口调用;
- 基于微服务模式的多层资源抽象模型,兼顾灵活性与可操作性,提出的Pod模型被许多平台借鉴;
-可拓展性好,模块化容易替换,伸缩能力极佳;单集群即可支持5000个节点,同时运行150000个Pods; - 自动化程度高,真正实现“所得即所需”,用户通过模板声明服务后,整个生命周期都是自动化管理,包括伸缩、负载均衡、资源分配、故障恢复、更新等;
- 部署支持多种环境,包括虚拟机、裸机部署,还很好支持常见云平台,包括AWS、GCE等;
- 支持丰富的运维和配置工具,方便用户对集群进行性能测试、问题检查和状态监控;❑ 自带控制台、客户端命令等工具,允许用户通过多种方式与kubernetes集群进行交互。
基于Kubernetes,可以很容易的实现一套容器云。Kubernetes支持通过模板来定义服务的配置,用户将配置模板提交之后,Kubernetes会自动管理(包括部署、发布、伸缩、更新等)应用容器来让服务维持指定状态,实现了十分高的可靠性,用户无须关心任何细节。
2.核心概念
Kubernetes为了更好地管理应用的生命周期,将不同资源对象进行了进一步的操作抽象。学习使用Kubernetes实际上就是要掌握这些不同的抽象对象。
Kubernetes中每种对象都拥有一个对应的声明式API。对象包括三大属性:元数据(metadata)、规范(spec)和状态(status)。通过这三个属性,用户可以定义让某个对象处于给定的状态(如多少Pod运行在哪些节点上)以及表现策略(如如何升级、容错),而无须关心具体的实现细节。
当使用Kubernetes管理这些对象时,每个对象可以使用一个外部的json或yaml模板文件来定义,通过参数传递给命令或API。每个模板文件中定义apiVersion(如v1)、kind(如Deployment、Service)、metadata(包括名称、标签信息等)、spec(具体的定义)等信息。例如:
另外,为了方便操作这些基础对象,Kubernetes还引入了控制器(Controller)的高级抽象概念。这些控制器面向特定场景提供了自动管理Pod功能,用户使用控制器而无须关心具体的Pod相关细节。
3.资源抽象对象
Kubernetes对集群中的资源进行了不同级别的抽象,每个资源都是一个REST对象,通过API进行操作,通过json或yaml格式的模板文件进行定义。在使用Kubernetes过程中,要注意积累这些模板文件。在Kubernetes代码包的example目录下自带了十分翔实的示例模板文件,我们可以读读。
3.1容器组
在Kubernetes中,并不直接操作容器,最小的管理单位是容器组(Pod)。容器组由一个或多个容器组成,Kubernetes围绕容器组进行创建、调度、停止等生命周期管理。
同一个容器组中,各个容器共享命名空间(包括网络、IPC、文件系统等容器支持的命名空间)、cgroups限制和存储卷。这意味着同一个容器组中,各个应用可以很方便地相互进行访问,比如通过localhost地址进行网络访问,通过信号量和共享内存进行进程间通信等,类似经典场景中运行在同一个操作系统中的一组进程。可以简单地将一个Pod当作是一个抽象的“虚拟机”,里面运行若干个不同的进程(每个进程实际上就是一个容器)。
实现上,是先创建一个gcr.io/google_containers/pause容器,创建相关命名空间,然后创建Pod中的其他应用容器,并共享pause容器的命名空间。
组成容器组的若干容器往往是存在共同的应用目的,彼此关联十分紧密,例如一个Web应用与对应的日志采集应用、状态监控应用。如果单纯把这些相关的应用放一个容器里面,又会造成过度耦合,管理、升级都不方便。
- 待定(Pending):已经被系统接受,但容器镜像还未就绪;
- 运行(Running):分配到节点,所有容器都被创建,至少一个容器在运行中;
- 成功(Succeeded):所有容器都正常退出,不需要重启,任务完成;
- 失败(Failed):所有容器都退出,至少一个容器是非正常退出;
- 未知(Unknown):未知状态,例如所在节点无法汇报状态。
3.2服务
Kubernetes主要面向的对象是持续运行,并且无状态(stateless)。
服务(Service)的提出,主要是要解决Pod地址可变的问题。由于Pod随时可能发生故障,并可能在其他节点上被重启,它的地址是不能保持固定的。因此,用一个服务来代表提供某一类功能(可以通过标签来筛选)的一些Pod,并分配不随Pod位置变化而改变的虚拟访问地址(Cluster IP)。这也符合微服务的理念。
典型情况是,比如网站的后端服务,可能有多个Pod都运行了后端处理程序,它们可以组成一个服务。前端只需通过服务的唯一虚拟地址来访问即可,而无须关心具体是访问到了哪个Pod。可见,服务跟负载均衡器实现的功能很相似。
根据访问方式的不同,服务可以分为如下几种类型:
- ClusterIP:提供一个集群内部的地址,该地址只能在集群内解析和访问。ClusterIP是默认的服务类型;
- NodePort:在每个集群节点上映射服务到一个静态的本地端口(默认范围为30000~32767)。从集群外部可以直接访问,并自动路由到内部自动创建的ClusterIP;
- LoadBalancer:使用外部的路由服务,自动路由访问到自动创建的NodePort和ClusterIP;
- ExternalName:将服务映射到externalName域指定的地址,需要1.7以上版本kube-dns的支持。
组成一个服务的Pod可能是属于不同复制控制器的,但服务自身是不知道复制控制器的存在的。同样,服务也是一个REST对象,用户可以通过模板来定义一个服务资源:
这个模板会筛选所有带有标签的app: webApp的Pod,作为web-service,对外呈现的访问端口为80,映射到Pod的80端口上。
服务在创建后,会被自动分配一个集群地址,这个地址并不绑定到任何接口,将作为访问服务的抽象地址。访问该地址,会被映射到Pod的实际地址。实现上是通过Kube-Proxy进程。每个节点上都会运行一个Kube-Proxy进程,负责将到某个Service的访问给代理或者均衡到具体的Pod上去。同时,会为每一个服务都创建环境变量,指向集群地址;或者在DNS中注册该服务的集群地址。
也许会有用户考虑使用DNS方式来替代服务的集群IP机制,这是完全可以的,Kuber-netes也提供了基于skydns的插件支持。但是要处理好DNS查找的缓存过期时间问题。当某个Pod发生变化时,要让客户端本地的DNS缓存过期。
另外,服务支持进行不同类型的健康检查(通过容器spec中的livenessProbe或Read-inessProbe字段定义),目前包括三种类型:
- 通过HTTP获取资源是否成功;
- 在容器中执行指定命令,返回值是否为0;
- 打开给定socket端口是否成功。
探测的结果可能为成功、失败或未知。其中LivenessProbe反映的是容器自身状态,如果配置了重启策略,则失败状态会触发自动重启;而ReadinessProbe字段用来则反映容器内的服务是否可用。
3.3存储卷
存储卷(Volume)即容器挂载的数据卷,跟Pod有一致的生命周期,Pod生存过程(包括重启)中,数据卷跟着存在;Pod退出,则数据卷跟着退出。
几个比较常见的数据卷类型包括:emptyDir、hostPath、gcePersistentDisk、awsElastic-BlockStore、nfs、gitRepo、secret。
- emptyDir:当Pod创建的时候,在节点上创建一个空的挂载目录,挂载到容器内。当Pod从节点离开(例如删除掉)的时候,自动删除挂载目录内数据。节点上的挂载位置可以为物理硬盘或内存。这一类的挂载适用于非持久化的存储,例如与Pod任务相关的临时数据等。除此之外,其他存储格式大都是持久化的;
- hostPath:将节点上某已经存在的目录挂载到Pod中,Pod退出后,节点上的数据将保留;
- gcePersistentDisk:使用GCE的Persistent Disk服务,Pod退出后,会保留数据;
- awsElasticBlockStore:使用AWS的EBS Volume服务,数据也会持久化保留;
- nfs:使用NFS协议的网络存储,也是持久化数据存储;
- gitRepo:挂载一个空目录到Pod,然后clone指定的git仓库代码到里面,适用于直接从仓库中给定版本的代码来部署应用;
- secret:用来传递敏感信息(如密码等),基于内存的tmpfs,挂载临时秘密文件。
其他类型的数据卷还包括iscsi、flocker、glusterfs、rbd、downwardAPI、FlexVolume、AzureFileVolume等。
持久化的存储以插件的形式提供为PersistentVolume资源,用户通过请求某个类型的PersistentVolumeClaim资源,来从匹配的持久化存储卷上获取绑定的存储。
资源定义仍然通过yml或json格式的模板文件,例如定义一个持久化存储卷: