漫谈Kubernetes本质(4)-支持更多关系

279 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情

这时,“link”这针对一种案例设计的解决方案过于简单。一旦要追求项目的普适性,那就一定要从顶层开始做好设计。

k8s主要设计思想,从宏观角度,以统一方式定义任务之间的各种关系,并为将来支持更多种类的关系留有余地。如k8s对容器间的“访问”进行了分类,先总结出一类常见“紧密交互”的关系,即:

  • 应用间需频繁交互和访问
  • 会直接通过本地文件进行信息交换

常规环境下的应用往往会被直接部在同一台机器,通过Localhost通信,通过本地磁盘目录交换文件。而在k8s,这些容器会被划分为一个“Pod”。

Pod

Pod里的容器共享同一个Network Namespace、同一组数据卷,达到高效率交换信息。

Pod是k8s中最基础的一个对象,源于Borg论文中的Alloc设计

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

而对另外一种更常见需求,如

Web应用与DB间的访问关系

k8s则提供“Service”服务。像这样的两个应用,故意不部署在同一机器,即使Web应用所在机器宕机,DB也不受影响。 可对一个容器,其IP地址等信息不固定的,Web应用怎么找到DB容器的Pod?所以,k8s给Pod绑定一个Service服务。Service服务声明的IP地址等信息“终生不变”。Service主要就是作为Pod的代理入口(Portal),从而代替Pod对外暴露一个固定的网络地址。 这对Web应用的Pod,需关心的就是DB Pod的Service信息。Service后端真正代理的Pod的IP地址、端口等信息的自动更新、维护,则是k8s职责。

围绕着容器和Pod不断向真实的技术场景扩展,可知k8s核心功能“全景图”

  • 从容器出发,先遇到容器间“紧密协作”关系难题,于是扩展到Pod
  • 有了Pod,希望能一次启动多个应用的实例,就需Deployment这个Pod的多实例管理器
  • 有了这一组相同Pod后,又需通过一个固定的IP地址和端口以负载均衡方式访问它,于是就有Service

若现在

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

最典型案例,Web应用对DB访问时需Credential(数据库的用户名和密码)信息,k8s如何处理呢?

k8s提供Secret对象,一个保存在Etcd里的KV对。把Credential信息以Secret方式存在Etcd,k8s就会在你指定Pod(如Web应用Pod)启动时,自动把Secret里的数据以Volume方式挂载到容器。这样,Web应用就能访问DB。

除了应用与应用之间的关系外,应用运行的形态是影响“如何容器化这个应用”的第二个重要因素。为此,k8s定义了基于Pod改进后的对象。如:

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

正是Kubernetes定义容器间关系和形态的主要方法。Kubernetes并没有像其他项目那样,为每个管理功能创建一个指令,然后在项目中实现其中的逻辑。这种做法,的确可以解决当前的问题,但是在更多的问题来临之后,力不从心。Kubernetes推崇:

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

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

这就是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容器副本就被启动了。

7 总结

容器可分为:

  • 容器运行时
  • 容器镜像

调度

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

编排

而k8s擅长按用户意愿和整个系统规则,完全自动化地处理好容器之间的各种关系。所以Kubernetes的本质是为用户提供一个具有普遍意义的容器编排工具。Kubernetes为用户提供的不仅限于一个工具。它真正的价值,还是在于提供了一套基于容器构建分布式系统的基础依赖。

参考

  • 深入剖析Kubernetes