Kubernetes 容器编排实战(一) - 漫谈 Kubernetes 的本质(下)

Kubernetes 容器编排实战(一) - 漫谈 Kubernetes 的本质(下)

Borg分配(分配的缩写)是一台机器上可以运行一个或多个任务的资源的保留集。无论是否使用资源,资源都会保持分配状态。 Alloc可用于为将来的任务留出资源,在停止任务和重新启动任务之间保留资源,以及将来自不同作业的任务收集到同一台计算机上–例如,一个Web服务器实例和一个关联的logaver任务,用于复制服务器的URL日志从本地磁盘记录到分布式文件系统。分配资源与机器资源的处理方式相似。在一个内部运行的多个任务共享其资源。如果必须将分配重定位到另一台计算机,则其任务将随之重新安排。

分配集就像一项工作:它是一组在多台机器上保留资源的分配。创建分配集后,可以提交一个或多个作业以在其中运行。为简便起见,我们通常使用“任务”来指代分配或*任务(在分配外的一个),使用“作业”来指代作业或分配集。


而对于另外一种更为常见的需求,比如

Web应用与数据库之间的访问关系

Kubernetes则提供了一种叫作“Service”的服务。像这样的两个应用,往往故意不部署在同一机器,即使Web应用所在的机器宕机了,数据库也不受影响。

可对于一个容器来说,它的IP地址等信息是不固定的,Web应用又怎么找到数据库容器的Pod呢?


所以,Kubernetes的做法是给Pod绑定一个Service服务

Service服务声明的IP地址等信息是“终生不变”的。Service主要就是作为Pod的代理入口(Portal),从而代替Pod对外暴露一个固定的网络地址。

这样,对于Web应用的Pod来说,它需要关心的就是数据库Pod的Service信息。不难想象,Service后端真正代理的Pod的IP地址、端口等信息的自动更新、维护,则是Kubernetes的职责。


围绕着容器和Pod不断向真实的技术场景扩展,我们就能够摸索出一幅如下所示

Kubernetes核心功能“全景图”

Kubernetes 容器编排实战(一) - 漫谈 Kubernetes 的本质(下)

从容器这个最基础的概念出发,首先遇到了容器间“紧密协作”关系的难题,于是就扩展到了Pod


有了Pod之后,我们希望能一次启动多个应用的实例,这样就需要Deployment这个Pod的多实例管理器


而有了这样一组相同的Pod后,我们又需要通过一个固定的IP地址和端口以负载均衡的方式访问它,于是就有了Service


如果现在

两个不同Pod之间不仅有“访问关系”,还要求在发起时加上授权信息

最典型的例子就是Web应用对数据库访问时需要Credential(数据库的用户名和密码)信息。

那么,在Kubernetes中这样的关系又如何处理呢?


Kubernetes项目提供了一种叫作Secret的对象,是一个保存在Etcd里的键值对。

这样,你把Credential信息以Secret的方式存在Etcd里,Kubernetes就会在你指定的Pod(比如,Web应用Pod)启动时,自动把Secret里的数据以Volume的方式挂载到容器里。这样,这个Web应用就可以访问数据库了。


除了应用与应用之间的关系外,应用运行的形态是影响“如何容器化这个应用”的第二个重要因素。

为此,Kubernetes定义了基于Pod改进后的对象。比如


  • Job
    描述一次性运行的Pod(比如,大数据任务)
  • DaemonSet
    描述每个宿主机上必须且只能运行一个副本的守护进程服务
  • CronJob
    描述定时任务


如此种种,正是Kubernetes定义容器间关系和形态的主要方法。

Kubernetes并没有像其他项目那样,为每一个管理功能创建一个指令,然后在项目中实现其中的逻辑

这种做法,的确可以解决当前的问题,但是在更多的问题来临之后,往往会力不从心


相比之下,在Kubernetes中,我们推崇

  • 首先,通过一个“编排对象”,比如Pod/Job/CronJob等描述你试图管理的应用
  • 然后,再为它定义一些“服务对象”,比如Service/Secret/Horizontal Pod Autoscaler(自动水平扩展器)等。这些对象,会负责具体的平台级功能。


这种使用方法,就是所谓的“声明式API”。这种API对应的“编排对象”和“服务对象”,都是Kubernetes中的API对象(API Object)。

这就是Kubernetes最核心的设计理念,也是接下来我会重点剖析的关键技术点。


Kubernetes如何启动一个容器化任务

现在已经制作好了一个Nginx容器镜像,希望让平台帮我启动这个镜像。并且,我要求平台帮我运行两个完全相同的Nginx副本,以负载均衡的方式共同对外提供服务。


如果DIY,可能需要启动两台虚拟机,分别安装两个Nginx,然后使用keepalived为这两个虚拟机做一个虚拟IP。


而如果使用Kubernetes呢?要做的则是编写如下这样一个YAML文件(比如名叫nginx-deployment.yaml):


apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

在上面这个YAML文件中,定义了一个Deployment对象,它的主体部分(spec.template部分)是一个使用Nginx镜像的Pod,而这个Pod的副本数是2(replicas=2)。

然后执行:

$ kubectl create -f nginx-deployment.yaml

这样,两个完全相同的Nginx容器副本就被启动了。

不过,这么看来,做同样一件事情,Kubernetes用户要做的工作也不少啊

别急,在后续会陆续介绍Kubernetes这种“声明式API”的好处,以及基于它实现的强大的编排能力。

总结

首先,一起回顾了容器的核心知识,说明了容器其实可以分为两个部分

  • 容器运行时
  • 容器镜像


然后,重点介绍了Kubernetes的架构,详细讲解了它如何使用“声明式API”来描述容器化业务和容器间关系的设计思想。

调度

过去很多的集群管理项目(比如Yarn、Mesos,以及Swarm)所擅长的,都是把一个容器,按照某种规则,放置在某个最佳节点上运行起来。这种功能,称为“调度”。


编排

而Kubernetes所擅长的,是按照用户的意愿和整个系统的规则,完全自动化地处理好容器之间的各种关系。

这种功能,就是我们经常听到的一个概念:编排。


所以说,Kubernetes的本质,是为用户提供一个具有普遍意义的容器编排工具。

Kubernetes为用户提供的不仅限于一个工具。它真正的价值,还是在于提供了一套基于容器构建分布式系统的基础依赖


参考

深入剖析Kubernetes

上一篇:Lync Server外部访问系列PART6:启用外部访问


下一篇:Linux学习(十一):不可忽略的Linux支持的文件系统