阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Kubernetes应用部署模型解析(原理篇)

114次阅读
没有评论

共计 6907 个字符,预计需要花费 18 分钟才能阅读完成。

摘要:本系列文章着眼于实际部署,带您快速掌握 Kubernetes。本文主要介绍部署之前需要了解的原理和概念,包括 Kubernetes 的组件结构,各个组件角色的功能,以及 Kubernetes 的应用模型等。

【编者按】Kubernetes 可用来管理 Linux 容器集群,加速开发和简化运维(即 DevOps)。但目前网络上关于 Kubernetes 的文章介绍性远多于实际使用。本系列文章着眼于实际部署,带您快速掌握 Kubernetes。本文为上篇,主要介绍部署之前需要了解的原理和概念,包括 Kubernetes 的组件结构,各个组件角色的功能,以及 Kubernetes 的应用模型等。


十多年来 Google 一直在生产环境中使用容器运行业务,负责管理其容器集群的系统就是 Kubernetes 的前身 Borg。其实现在很多工作在 Kubernetes 项目上的 Google 开发者先前就在 Borg 这个项目上工作。多数 Kubernetes 的应用部署模型的思想都起源于 Borg, 了解这些模型是掌握 Kubernetes 的关键。Kubernetes 的 API 版本目前是 v1,本文以代码 0.18.2 版为基础来介绍它的应用部署模型,最后我们用一个简单的用例来说明部署过程。 在部署结束后,阐述了它是如何用 Iptables 规则来实现各种类型 Service 的。

 

Kubernetes 架构

 

Kubernetes集群包括 Kubernetes 代理 (agents)Kubernetes服务 (master node) 两种角色,代理角色的组件包括 Kube-proxy Kubelet,它们同时部署在一个节点上,这个节点也就是代理节点。服务角色的组件包括 kube-apiserverkube-schedulerkube-controller-manager,它们 可以任意布属,它们可以部署在同一个节点上,也可以部署在不同的节点上(目前版本好像不行)。Kubernetes集群依赖的第三方组件目前有 etcddocker两个。前者提供状态存储,二者用来管理容器。集群还可以使用分布式存储给容器提供存储空间。下图显示了目前系统的组成部分:

Kubernetes 应用部署模型解析(原理篇)

 

Kubernetes 代理节点

Kubelet 和 Kube-proxy 运行在代理节点上。他们监听服务节点的信息来启动容器和实现 Kubernetes 网络和其它业务模型,比如 Service、Pod 等。当然每个代理节点都运行 Docker。Docker 负责下载容器镜像和运行容器。

 

 

Kubelet

 

Kubelet组件管理 Pods 和它们的容器,镜像和卷等信息。

 

Kube-Proxy

Kube-proxy是一个简单的网络代理和负载均衡器。它具体实现 Service 模型,每个 Service 都会在所有的 Kube-proxy 节点上体现。根据 Serviceselector所覆盖的 Pods, Kube-proxy 会对这些 Pods 做负载均衡来服务于 Service 的访问者。

 

 

Kubernetes 服务节点

Kubernetes服务组件形成了 Kubernetes 的控制平面,目前他们运行在单一节点上,但是将来会分开来部署,以支持高可用性。

 

 

etcd

所有的持久性状态都保存在 etcd 中。Etcd 同时支持 watch,这样组件很容易得到系统状态的变化,从而快速响应和协调工作。

 

 

Kubernetes API Server

这个组件提供对 API 的支持,响应 REST 操作,验证 API 模型和更新 etcd 中的相应对象。

 

 

Scheduler

通过访问 Kubernetes 中 /binding API, Scheduler 负责 Pods 在各个节点上的分配。Scheduler 是插件式的,Kubernetes 将来可以支持用户自定义的 scheduler。

 

 

Kubernetes Controller Manager Server

Controller Manager Server 负责所有其它的功能,比如 endpoints 控制器负责 Endpoints 对象的创建,更新。node 控制器负责节点的发现,管理和监控。将来可能会把这些控制器拆分并且提供插件式的实现。

 

 

Kubernetes 模型

Kubernetes 的伟大之处就在于它的应用部署模型,主要包括 Pod、Replication controller、Label 和 Service。

 

 

Pod

Kubernetes 的最小部署单元是 Pod 而不是容器。作为 First class API 公民,Pods 能被创建,调度和管理。简单地来说,像一个豌豆荚中的豌豆一样,一个 Pod 中的应用容器同享同一个上下文:

 

 

  1. PID 名字空间。但是在 docker 中不支持
  2. 网络名字空间,在同一 Pod 中的多个容器访问同一个 IP 和端口空间。
  3. IPC 名字空间,同一个 Pod 中的应用能够使用 SystemV IPC 和 POSIX 消息队列进行通信。
  4. UTS 名字空间,同一个 Pod 中的应用共享一个主机名。
  5. Pod 中的各个容器应用还可以访问 Pod 级别定义的共享卷。

 

从生命周期来说,Pod 应该是短暂的而不是长久的应用。Pods 被调度到节点,保持在这个节点上直到被销毁。当节点死亡时,分配到这个节点的 Pods 将会被删掉。将来可能会实现 Pod 的迁移特性。在实际使用时,我们一般不直接创建 Pods, 我们通过 replication controller 来负责 Pods 的创建,复制,监控和销毁。一个 Pod 可以包括多个容器,他们直接往往相互协作完成一个应用功能。

 

Replication controller

复制控制器确保 Pod 的一定数量的份数 (replica) 在运行。如果超过这个数量,控制器会杀死一些,如果少了,控制器会启动一些。控制器也会在节点失效、维护的时候来保证这个数量。所以强烈建议即使我们的份数是 1,也要使用复制控制器,而不是直接创建 Pod。

 

在生命周期上讲,复制控制器自己不会终止,但是跨度不会比 Service 强。Service 能够横跨多个复制控制器管理的 Pods。而且在一个 Service 的生命周期内,复制控制器能被删除和创建。Service 和客户端程序是不知道复制控制器的存在的。

复制控制器创建的 Pods 应该是可以互相替换的和语义上相同的,这个对无状态服务特别合适。

Pod 是临时性的对象,被创建和销毁,而且不会恢复。复制器动态地创建和销毁 Pod。虽然 Pod 会分配到 IP 地址,但是这个 IP 地址都不是持久的。这样就产生了一个疑问:外部如何消费 Pod 提供的服务呢?

 

Service

Service 定义了一个 Pod 的逻辑集合和访问这个集合的策略。集合是通过定义 Service 时提供的 Label 选择器完成的。举个例子,我们假定有 3 个 Pod 的备份来完成一个图像处理的后端。这些后端备份逻辑上是相同的,前端不关心哪个后端在给它提供服务。虽然组成这个后端的实际 Pod 可能变化,前端客户端不会意识到这个变化,也不会跟踪后端。Service 就是用来实现这种分离的抽象。

 

对于 Service,我们还可以定义 Endpoint,Endpoint 把 Service 和 Pod 动态地连接起来。

 

Service Cluster IP 和 kuber proxy

每个代理节点都运行了一个 kube-proxy 进程。这个进程从服务进程那边拿到 Service 和 Endpoint 对象的变化。对每一个 Service, 它在本地打开一个端口。到这个端口的任意连接都会代理到后端 Pod 集合中的一个 Pod IP 和端口。在创建了服务后,服务 Endpoint 模型会体现后端 Pod 的 IP 和端口列表,kube-proxy 就是从这个 endpoint 维护的列表中选择服务后端的。另外 Service 对象的 sessionAffinity 属性也会帮助 kube-proxy 来选择哪个具体的后端。缺省情况下,后端 Pod 的选择是随机的。可以设置 service.spec.sessionAffinity “ClientIP”来指定同一个 ClientIP 的流量 代理到同一个后端。在实现上,kube-proxy 会用 IPtables 规则把访问 Service 的 Cluster IP 和端口的流量重定向到这个本地端口。下面的部分会讲什么是 service 的 Cluster IP。

 

注意:在 0.18 以前的版本中 Cluster IP 叫 PortalNet IP。

 

内部使用者的服务发现

Kubernetes在一个集群内创建的对象或者在代理集群节点上发出访问的客户端我们称之为内部使用者。要把服务暴露给内部使用者,Kubernetes 支持两种方式:环境变量和 DNS。

 

 

环境变量

当 kubelet 在某个节点上启动一个 Pod 时,它会给这个 Pod 的容器为当前运行的 Service 设置一系列环境变量,这样 Pod 就可以访问这些 Service 了。一般地情况是 {SVCNAME}_SERVICE_HOSTh{SVCNAME}_SERVICE_PORT变量 , 其中{SVCNAME}Service名字变成大写,中划线变成下划线。比如Service “Redis-master”,它的端口是 TCP  6379,分配到的 Cluster IP 地址是 10.0.0.11,kubelet 可能会产生下面的变量给新创建的 Pod 容器:

 

REDIS_MASTER_SERVICE_HOST= 10.0.0.11
REDIS_MASTER_SERVICE_PORT=6379
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
REDIS_MASTER_PORT_6379_TCP_PORT=6379
REDIS_MASTER_PORT_6379_TCP_ADDR= 10.0.0.11

注意,只有在某个 Service 后创建的 Pod 才会有这个 Service 的环境变量。

 

DNS

一个可选的 Kubernetes 附件(强烈建议用户使用)是 DNS 服务。它跟踪集群中 Service 对象,为每个 Service 对象创建 DNS 记录。这样所有的 Pod 就可以通过 DNS 访问服务了。

 

比如说我们在 Kubernetes 名字空间 ”my-ns” 中有个叫 my-service 的服务,DNS 服务会创建一条 ”my-service.my-ns” 的 DNS 记录。同在这个命名空间的 Pod 就可以通过 ”my-service” 来得到这个 Service 分配到的 Cluster IP,在其它命名空间的 Pod 则可以用全限定名 ”my-service.my-ns” 来获得这个 Service 的地址。

 

Pod IP and Service Cluster IP

Pod IP 地址是实际存在于某个网卡 (可以是虚拟设备) 上的,但 Service Cluster IP 就不一样了,没有网络设备为这个地址负责。它是由 kube-proxy 使用 Iptables 规则重新定向到其本地端口,再均衡到后端 Pod 的。我们前面说的 Service 环境变量和 DNS 都使用 Service 的 Cluster IP 和端口。

 

就拿上面我们提到的图像处理程序为例。当我们的 Service 被创建时,Kubernetes 给它分配一个地址 10.0.0.1。这个地址从我们启动 API 的 service-cluster-ip-range 参数 (旧版本为 portal_net 参数) 指定的地址池中分配,比如service-cluster-ip-range=10.0.0.0/16。假设这个 Service 的端口是 1234。集群内的所有 kube-proxy 都会注意到这个 Service。当 proxy 发现一个新的 service 后,它会在本地节点打开一个任意端口,建相应的 iptables 规则,重定向服务的 IP 和 port 到这个新建的端口,开始接受到达这个服务的连接。

当一个客户端访问这个 service 时,这些 iptable 规则就开始起作用,客户端的流量被重定向到 kube-proxy 为这个 service 打开的端口上,kube-proxy 随机选择一个后端 pod 来服务客户。这个流程如下图所示:

Kubernetes 应用部署模型解析(原理篇)

根据 Kubernetes 的网络模型,使用 Service Cluster IPPort访问 Service 的客户端可以坐落在任意代理节点上。外部要访问 Service,我们就需要给Service 外部访问IP

 

外部访问 Service

Service 对象在 Cluster IP range 池中分配到的 IP 只能在内部访问,如果服务作为一个应用程序内部的层次,还是很合适的。如果这个 Service 作为前端服务,准备为集群外的客户提供业务,我们就需要给这个服务提供公共 IP 了。

 

外部访问者是访问集群代理节点的访问者。为这些访问者提供服务,我们可以在定义 Service 时指定其 spec.publicIPs,一般情况下 publicIP 是代理节点的物理 IP 地址。和先前的 Cluster IP range 上分配到的虚拟的 IP 一样,kube-proxy 同样会为这些 publicIP 提供 Iptables 重定向规则,把流量转发到后端的 Pod 上。有了 publicIP,我们就可以使用 load balancer 等常用的互联网技术来组织外部对服务的访问了。

spec.publicIPs 在新的版本中标记为过时了,代替它的是 spec.type=NodePort,这个类型的 service,系统会给它在集群的各个代理节点上分配一个节点级别的端口,能访问到代理节点的客户端都能访问这个端口,从而访问到服务。

 

Label 和 Label selector

Label标签在 Kubernetes 模型中占着非常重要的作用。Label 表现为 key/value 对,附加到 Kubernetes 管理的对象上,典型的就是 Pods。它们定义了这些对象的识别属性,用来组织和选择这些对象。Label 可以在对象创建时附加在对象上,也可以对象存在时通过 API 管理对象的 Label。

 

在定义了对象的 Label 后,其它模型可以用 Label 选择器(selector)来定义其作用的对象。

Label选择器有两种,分别是 Equality-basedSet-based

比如如下 Equality-based 选择器样例:

 

environment = production
tier != frontend
environment = production,tier != frontend

 

对于上面的选择器,第一条匹配 L abel具有 environment key 且等于 production 的对象,第二条匹配具有 tier key,但是值不等于frontend 的对象。由于 kubernetes 使用 AND 逻辑,第三条匹配 production 但不是 frontend 的对象。

Set-based选择器样例:

 

environment in (production, qa)
tier notin (frontend, backend)
partition

 

第一条选择具有 environment key,而且值是production 或者 qalabel附加的对象。第二条选择具有 tier key,但是其值不是frontendbackend。第三条选则具有 partition key 的对象,不对 value 进行校验。

replication controller复制控制器和 Service 都用 labellabel selctor来动态地配备作用对象。复制控制器在定义的时候就指定了其要创建 PodLabel和自己要匹配这个 PodselectorAPI服务器应该校验这个定义。我们可以动态地修改 replication controller 创建的 PodLabel用于调式,数据恢复等。一旦某个 Pod 由于 Label 改变 replication controller移出来后,replication controller会马上启动一个新的 Pod 来确保复制池子中的份数。对于 ServiceLabel selector 可以用来选择一个 Service 的后端Pods

OpenStack, Kubernetes, Mesos 谁主沉浮  http://www.linuxidc.com/Linux/2015-09/122696.htm

Kubernetes 集群搭建过程中遇到的问题及解决  http://www.linuxidc.com/Linux/2015-12/125735.htm

Kubernetes 的详细介绍:请点这里
Kubernetes 的下载地址:请点这里

下篇:Kubernetes 应用部署模型解析(部署篇)

作者简介:龚永生,九州云架构师。多年 Linux 系统开发,J2EE 产品和云计算相关技术研发经验。目前活跃在 OpenStack 社区的各个项目上,主要技术方向是虚拟网络项目 Neutron,是 Neutron 项目早期的主要贡献者之一。

本文永久更新链接地址:http://www.linuxidc.com/Linux/2015-12/125761.htm

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-21发表,共计6907字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中