编辑推荐: |
本文来自于百度,介绍了Kubernetes
架构,应用程序部署模型,服务发现与负载均衡,Service 如何在内部工作,Persistent
Volumes 的使用等。 |
|
Kubernetes 已成为在私有云、公有云和混合云环境中大规模部署容器化应用的事实标准。AWS、Google
Cloud、Azure、IBM Cloud 和 Oracle Cloud 等几个最大的公有云平台都可以为
Kubernetes 提供托管服务。
几年前,Red Hat 用 Kubernetes 完全替代了自己的 OpenShift 实施方案,并与
Kubernetes 社区合作推出了下一代容器平台。Mesosphere 在 Kubernetes
流行起来后迅速将 Kubernetes 的关键特性,如容器分组,重叠网络,4 层路由,Secrets
等集成到它们的容器平台 DC / OS 中。DC / OS 还将 Kubernetes 与 Marathon
整合为一个容器编排系统。Pivotal 最近推出了基于 Kubernetes 的 Pivotal Container
Service(PKS),用于在 Pivotal Cloud Foundry 上部署第三方服务……时至今日,仍然有许多组织和技术提供商正在跟随
Kubernetes 发展的脚步对产品进行相应调整。
2014 年,Kubernetes 走入人们的视野 。它整合了谷歌内部容器集群管理系统 Borg
和 Omega 优势,汲取了谷歌大规模应用容器技术十几年经验 。在我看来, Kubernetes 让人们对于诸如微服务,serverless
功能,Service Mesh 和 Event-driven 应用程序等新兴软件架构模式的适应变得容易,并为构建整个云原生生态铺平了道路。最重要的是,其
cloud agnostic 设计让容器化应用程序无需对应用程序代码进行任何更改,就可以在任何平台上运行。当前
Kubernetes 主要用在大型企业部署场景下,但从长远来看,中小型企业也可以应用 Kubernetes
节省大量的基础设施和维护成本。
接下来,我将在文中介绍 Kubernetes 的高级架构,应用程序部署模型,服务发现和负载均衡,内部/外部路由分离、persistent
volume 的使用,部署节点守护程序,部署有状态分布式系统,作业后台运行,部署数据库,配置管理,凭证管理,滚动更新,自动缩放和包管理。
Kubernetes 架构
这个集群管理器的基本设计策略之一就是,无需更改应用程序代码,就能部署在虚拟机上运行的现有应用程序。另外,任何运行在虚拟机上的应用程序都可以通过容器化组件在
Kubernetes 上实现部署。这是通过容器分组、容器编排、覆盖网络、基于第 4 层虚拟 IP、服务发现、支持守护程序运行、部署有状态应用程序组件、以及扩展容器编排系统这些核心功能实现的。
另外,Kubernetes 可以提供一组可动态扩展的主机,可以应用容器运行 workload,并使用一组称为
master 的管理主机来提供管理整个容器基础架构的 API。这些 workload 包括长期运行服务
,批处理作业和容器主机的守护程序。为了提供容器到容器的路由,所有容器主机都用覆盖网络连接在一起。部署在
Kubernetes 上的应用程序在集群网络中是动态可见的,并可通过传统负载均衡器向外部网络暴露。集群管理器的状态存储在一个高度分布的
key/value 存储(etcd)中,该存储在 master 上运行。
Kubernetes 调度程序可以确保每个应用程序组件都已进行健康检查,可提供高可用。当副本的数量设置大于
1 时,多个主机中的实例都会被调度。如果其中一个主机不可用,那么运行在该主机上的所有容器,都可能被任一主机调度。
Kubernetes 的迷人功能之一就是提供两级自动缩放。首先,可以使用一个名为 Horizontal
Pod Autoscaler 的资源来自动调整容器,它可以监视资源消耗并对所需容器数量进行相应地调整。其次,它可以通过添加和删除主机的方式,根据资源需求扩展容器集群。此外,通过引入集群联合功能,Horizontal
Pod Autoscaler 甚至可以使用单个 API 端点跨多个数据中心管理 Kubernetes
集群。
这只是 Kubernetes “开箱即用”众多功能的冰山一角。接下来,我将介绍 Kubernetes
的核心功能,并详解应该如何设计并部署你的软件应用程序。
应用程序部署模型
上图是 Kubernetes 上高级应用程序部署模型。它使用 ReplicaSet 来编排容器。我们可以将
ReplicaSet 视为基于 YAML 或基于 JSON 的元数据文件,该文件可以定义容器镜像、端口、副本数量、激活状况检查、活动状况检查、环境变量、数据挂载和创建并管理容器需要的安全规则。
容器在 Kubernetes 上以组的形式创建,被称为 Pod,它是 Kubernetes 的一个元数据定义或资源。每个
Pod 都可以通过 Linux namespace,cgroup 和其他内核功能在容器之间共享文件系统、网络接口以及操作系统用户。而
ReplicaSets 可以由一个叫做 Deployment 的高级资源进行管理,Deployment
提供用于滚动更新和处理其回滚的功能。
通过执行下面这样一条简单的 CLI 命令,就可以在 Kubernetes 上部署容器化的应用程序了。
一旦执行上述 CLI 命令,给定容器镜像将创建一个部署定义,一个副本集和一个 pod; 另外使用应用程序名称将添加一个
selector label。由此创建的每个 pod 将有两个容器,一个用于给定的应用程序组件,另一个叫做
Pause 用于连接网络接口。
服务发现与负载均衡
Kubernetes 的主要功能之一,是使用 SkyDNS 和 4 层虚拟 IP 路由系统,提供服务发现和内部路由模型。这些功能为要求使用
service 的应用程序提供了内部路由。通过副本集创建的一组 Pod 可以使用集群网络内的 service
进行负载均衡。service 用选择器标签(selector labels)连接到 Pod。每个 service
会分到一个唯一的 IP 地址,和一个由其名称派生的主机名,并以循环的方式在 Pod 中路由请求。该
service 甚至还能为需要会话关联的应用程序提供基于 IP 的路由机制。一个 service 可以定义一个端口集合,为给定
service 定义的属性将以相同的方式应用于所有端口。因此,在一个场景中,只需要一个给定端口的会话关联,在该端口中所有其他端口都需要使用基于轮询的路由,这可能要用到多个
service。
Service 如何在内部工作?
Kubernetes service 使用一个名为 kube-proxy 的组件来实现。每个节点中都有一个
kube-proxy 实例。Kube-proxy 有三种代理模式:Userspace,iptables
和 IPVS。当前的默认模式是 iptables。
在第一种代理模式下,userspace,kube-proxy 本身充当代理服务器,由 iptables
规则接受的请求委托给后端 Pod。在这种模式下,kube-proxy 将在 userspace 中运行,并增加一个跳转到信息流。在
iptables 中,kube-proxy 创建一组 iptables 规则,用于将来自客户端的传入请求直接转发到网络层上的后端
Pod 端口,而无需在中间添加额外的跳转。这个代理模式比第一种模式快得多,因为它无需在中间添加额外代理服务器,直接在
kernel space 中运行。
Kubernetes v1.8 版本增加了第三种代理模式,与第二种代理模式非常相似,它不用 iptables
规则而是使用基于 IPVS 的虚拟服务器来路由请求。IPVS 是一种传输层负载均衡功能,可在基于 Netfilter
的 Linux kernel 中运行,并提供一组负载均衡算法。通过 iptables 使用 IPVS
是因为使用 iptables 可以同步代理规则的性能开销。当创建数千个服务时,与 IPVS 的几毫秒相比,更新
iptables 规则需要相当长的时间。此外,IPVS 使用 hash table 来查找通过 iptables
进行顺序扫描的代理规则。
内/外路由分离
Kubernetes service 可以通过两种主要方式暴露于外部网络。第一种方法是通过暴露节点上的动态端口来使用节点端口,将流量转发到服务端口。第二种方法是通过使用
ingress controller 配置负载均衡器, ingress controller 可以通过连接到相同的覆盖网络将请求委托给
service。 Ingress controller 是一个后台进程,它可以运行在监听 Kubernetes
API 的容器中,根据给定的一组 ingress 动态地配置并重新加载给定的负载均衡器。Ingress
基于使用服务的 hostname 和 context paths 来定义路由规则。
一旦使用 kubectl run 命令将应用程序部署到 Kubernetes 上,它就可以通过负载均衡器暴露给外部网络,如下所示:
上述命令将创建一个负载均衡器类型的 service,并将创建该 Pod 时生成的相同选择器标签(selector
label )将其映射到 Pod。因此,根据 Kubernetes 集群的配置方式,基础架构上的负载均衡器服务将通过
service 或直接为给定的 Pod 路由请求而创建。
Persistent Volumes 的使用
需要在文件系统上保留数据的应用程序可以使用 volume 将存储设备挂载到临时容器中,这与虚拟机使用
volumes 的方式类似。Kubernetes 通过引入称为 persistent volume
claims(PVC)的中间资源,将物理存储设备与容器进行松散耦合。PVC 定义了磁盘大小,磁盘类型(ReadWriteOnce,ReadOnlyMany,ReadWriteMany)并且可以将存储设备动态地连接到某个
Pod 定义的 volume 上 。绑定过程既可以使用 PV 静态处理,也可以动态地使用 persistent
storage provider 。在这两种方法中,volume 将一对一地连接到一个 PV,这取决于配置,因为即使该
Pod 被终止,数据也将被保留。根据所使用的磁盘类型,多个 Pod 将能够连接到相同的磁盘并进行读取或写入。
支持 ReadWriteOnce 的磁盘只能连接到一个 Pod,并且不能同时在多个 Pod 中共享。但是,支持
ReadOnlyMany 的磁盘可以在只读模式下同时在多个 Pod 中共享。顾名思义,具有ReadWriteMany
支持的磁盘可以连接到多个 Pod,以读写模式共享数据。Kubernetes 提供了一系列 volume
plugins,用于支持 AWS EBS,GCE 持久性磁盘,Azure File,Azure Disk
以及其他众所周知的存储系统(如 NFS,Glusterfs,Cinder 等)等公有云平台上提供的存储服务。
在节点部署守护程序
Kubernetes 提供了一个名为 DaemonSets 的资源,用于在每个 Kubernetes
节点中将守护进程的副本作为后台进程运行。DaemonSet 的一些用例如下所示:
集群存储守护程序,如 glusterd,ceph 要部署在每个节点上以提供持久性存储;
节点监视守护进程,如 Prometheus 节点可导出程序,将在每个节点上运行,以监视容器主机;
日志收集守护程序,如 fluentd 或 logstash ,在每个节点上运行以收集容器和 Kubernetes
组件日志;
Ingress controller pod 将在一组节点上运行,以提供外部路由。
部署有状态分布式系统
容器化应用程序最困难的任务之一,就是设计有状态分布式组件的部署体系结构。由于无状态组件可能没有预定义的启动顺序、集群要求、点对点
TCP 连接、唯一的网络标识符、正常的启动和终止要求等,因此可以很容易地进行容器化。诸如数据库,大数据分析系统,分布式
key/value 存储和 message brokers 可能有复杂的分布式体系结构,都可能用到上述功能。Kubernetes
引入了 StatefulSets 资源来支持这种复杂的需求。
StatefulSets 类似于 ReplicaSets,但是它可以处理 Pod 的启动顺序,为保留每个
Pod 的状态设置唯一标识,同时具有以下功能:
Stable,唯一的网络标识符
Stable,持久化的存储
Ordered,优雅的部署和缩放
Ordered,优雅的删除和终止
Ordered,自动滚动更新
Stable 指的是将网络标识符和持久存储跨 Pod 重新调度。如上图所示,使用 headless
services 提供唯一的网络标识符。Kubernetes 提供了以分布式方式部署 Cassandra
和 Zookeeper 的 StatefulSets 示例。
运行后台作业
除了 ReplicaSets 和 StatefulSets 之外,Kubernetes 还提供了两个额外的控制器,用于在后台运行称为
Jobs 和 CronJobs 的 workload 。 Job 和 CronJobs 之间的区别在于,Job
执行一次并终止,而 CronJobs 与标准 Linux cron job 类似,根据给定时间间隔周期性执行。
部署数据库
由于大家对集群化、点对点连接、主从复制、分区、管理备份等都有要求,因此在容器平台上部署数据库以供生产使用比部署应用程序要困难的多。如前所述,StatefulSets
专门应付这种复杂要求,而在 Kubernetes 上运行 PostgreSQL 和 MongoDB
集群有几个相应选项。
YouTube 的数据库集群系统 Vitess 现在是一个 CNCF 项目,对于在 Kubernetes
上大规模运行 MySQL 来说,它是一个很好的选择。值得注意的是,这些选项还处于非常早期的阶段,如果现有的生产级数据库系统可用于给定的基础架构,例如
AWS 上的 RDS,GCP 上的 Cloud SQL 或内部部署数据库集群考虑到安装复杂性和维护开销,选择其中一种选择可能会更好。
配置管理
容器通常使用环境变量来对其运行时配置进行参数化。但是,典型的企业应用程序使用大量的配置文件来提供给定部署所需的静态配置。Kubernetes
提供了一种称为 ConfigMaps 的简单资源来管理此类配置文件的方法,无需将它们捆绑到容器镜像中。只需要使用以下
CLI 命令可以使用目录,文件或 literal values 创建 ConfigMaps:
一旦创建 ConfigMap 后,可以使用 volume mount 将其挂载到一个容器。借助这种松散耦合的体系结构,只需更新相关的
ConfigMap 并执行滚动更新程序就可以无缝地更新已运行系统的配置,我将在下一节中对其进行解释。注意
ConfigMaps 目前不支持嵌套文件夹; 因此,如果应用程序的嵌套目录结构中有可用的配置文件,则需要为每个目录级别创建一个
ConfigMap。
凭证管理
与 ConfigMaps 类似,Kubernetes 提供了另一个好功能,称为 Secrets,用于管理敏感信息,如密码,OAuth
令牌和 ssh 密钥。否则,在已经运行的系统上更新该信息可能需要重建容器镜像。
使用以下方法可以创建一个 Secret 来管理基本身份验证凭据:
一旦创建了 secret,就可以使用环境变量或 volume mounts 通过 Pod 进行读取。当然,其他类型的敏感信息也可以使用相同的方法注入到
Pod 中。
滚动更新
上面的动画说明了如何通过使用蓝/绿部署方法为已经运行的应用程序进行滚动更新,而不会导致系统停机。这是
Kubernetes 的另一个非常棒的功能,应用程序可以无缝地推出安全更新和向后兼容的更改。如果更改不向后兼容,则可能需要使用单独的部署定义执行手动蓝/绿部署。
此方法允许使用简单的 CLI 命令执行卷展栏更新容器镜像:
一旦执行了 rollout,可以按照以下方式检查 rollout 过程的状态:
使用相同的 CLI 命令 kubectl set image deployment ,可以将更新回滚到以前的状态。
自动缩放
Kubernetes 允许使用 ReplicaSets 或 Deployments 手动缩放 Pod。如上图所示,可以通过向部署添加另一个名为
Horizontal Pod Autoscaler(HPA)的资源来扩展此功能,以根据实际资源使用情况动态缩放
Pod。HPA 将通过资源度量 API 监视每个 Pod 的资源使用情况,并通知部署相应地更改副本集的副本计数。Kubernetes
使用高级延迟和低级延迟来避免由于某些情况下频繁资源使用波动而可能发生的波动。目前,HPA 仅支持基于
CPU 使用率的扩展。如果需要,还可以通过根据应用程序的性质自定义指标 API 插入自定义指标。
包管理
Kubernetes 社区启动了一个单独的项目来实施 Kubernetes 的管理器(Package
Manager),名为 Helm。Kubernetes 资源(如 deployment,service,configmap,ingress
等)可以使用 chart 进行模板化和打包,在安装时使用输入参数对它们进行配置。更重要的是,它允许在使用依赖关系实现安装包时重用现有图表。
Helm 库可以托管在公有和私有云环境中,用于管理应用程序图表。Helm 提供了一个 CLI,用于将来自给定
Helm repo 的应用程序安装到选定的 Kubernetes 环境中。大家可以在 Github
repo 和 central Helm server——Kubeapps Hub 找到这个众所周知的软件应用程序
Helm 图表。
Kubernetes 结合 Google 大规模运行容器应用程序十年经验。目前,它已经被最大的公有云供应商和技术提供商所采用。在撰写本文时,它正在被更多的软件供应商和企业所接受。Kubernetes
在 2015 年开源并衍生出 Cloud Native Computing Foundation (CNCF),最近成为基金会旗下首个毕业的项目。CNCF
也开始整合容器生态系统以及其他与容器相关的项目,如 CNI,Containerd,Envoy ,Fluentd,gRPC,Jagger,Linkerd,Prometheus,rkt
和 Vitess。Kubernetes 之所以受到各大组织的欢迎和认可,其关键原因首先是它的完美设计,其次就是其开源的特性、与业界领袖的合作的热情以及始终对创意和贡献保持开放的态度。 |