如何规模化企业的数字化服务--Kubernetes的最佳实践

2020-03-20| Kubernetes, Docker, CI/CD, 云计算, 微服务

企业的线上产品的发展主要分为3个阶段。第一阶段主要是快速打造产品,然后推向市场并验证想法;第二阶段主要是打磨产品同时发展用户基数,使得用户基数达到千万级别;第三阶段则是维护产品,迭代新功能,保证产品能够为企业带来持续的收入。每一个阶段都会有对应的技术手段来支撑,本文的内容主要解决企业在第二阶段所面临的挑战。这些挑战主要有:企业如何在原来的基础上重构数字化产品?企业如何构建支撑千万级用户的数字化产品?对于后者,企业需要综合多种技术手段来实现,其中Kubernetes(K8S)在容器编排方面为拥有千万级别用户群体的服务提供了支持。接下来,让我们看看K8S是如何规模化数字化产品的。

  1. Kubernetes所解决的问题
  2. 什么是Kubernetes(K8S)
  3. 为什么选择K8S
  4. K8S的组成部分
  5. K8S的资源类型
  6. 在AWS上搭建K8S服务的选项

Kubernetes所解决的问题

当一款数字化产品的用户基数非常庞大的时候(比如每天的访问量达到几千万人次时),企业需要升级其技术解决方案,以便能够支撑庞大的用户群体。拥有庞大用户群体的数字化服务有很多,比如Google的搜索引擎,淘宝,微博等等。而这类数字化服务有一个共同的特征:其后台运行着成成千上万台服务器,由它们向用户提供服务。通过人工来管理这群服务器显然不是一个可行的办法,因此Google的工程师为了高效管理这种量级的服务器,发明了这个工具:Kubernetes(K8S)。通过这个工具,工程师只需要键入几条命令就可以同时操作多台机器,从而实现轻松管理成千上万台服务器。

这些数字化产品大多都是微服务化的,而微服务的几大特点就是:服务与服务之间是相互独立的;它们之间是通过行为来交互的;为了高可用性,每一个服务都会被复制到不同的服务器上,当某台服务器坏了或者死机了,那么运行在其它服务器上的服务依然能够提供服务;不同服务互相协作,最终支撑了数字化产品。K8S特别适合微服务场景,比如工程师只需要执行一个命令就能让K8S部署某类服务,并自动替换失败的服务。除此之外,工程师还可以通过一个命令使得K8S自动部署或更新服务,这些服务能够根据负载的多少而自动增加或减少。为了方便K8S部署,其部署单元被抽象出来,而这种单元就是我们常常见到的容器,其中Docker是一款非常流行的容器工具,因此K8S和Docker工具结合很好地支持微服务结构的数字化产品。

使用K8S能够方便地为数字化产品的负载能力提供横向扩展,那么K8S是如何做到的?接下来我们要了解什么是K8S?它提供了哪些功能?

什么是Kubernetes(K8S)

Kubernetes (K8S)是一套管理容器资源的开源系统,它提供了以下功能:

  • 分配资源

它会根据资源的使用情况(这些资源包括数据中心,服务器,CPU,内存,端口等),在一族服务器上,以最优的方式,创建和运行容器。

  • 部署

它支持多种在线逐步更新策略,这些策略有rolling deployment, blue-green deployment以及 canary deployment。如果在更新过程中产生错误,它会自动恢复到上一次可用的状态,从而确保服务7*24小时可用。

  • 自带修复功能

它会一直监控资源的运行状态,自动将可用的资源替换不可使用的资源。

  • 弹性伸缩

它支持横向和纵向伸缩。负载增多或减少时,它可以自动增加或减少适度的资源来响应负载。它也可以升级或降级资源的处理能力来支持纵向扩展,比如提高CPU的处理能力或者增加内存。

  • 负载均衡

它能使外部访问内部资源(常见的资源有container),并将外部请求均匀地分配给不同的资源。

  • 发现服务

它有内置的DNS服务,并提供Service资源,使得容器能够找到彼此来进行通信。

  • 配置和授权

它允许你设置不同的环境变量来区分不同的环境,这些环境有stage、test和prod。也允许你为资源设置不同的访问权限。

为什么选择K8S

K8S作为容器化应用的编排系统,已经广泛应用于大多数企业。它之所以流行的原因有以下几点:

  • 丰富的功能

它为管理容器提供了大量功能,这些功能包括弹性伸缩,自动修复,在线部署,服务发现,秘钥管理,配置管理,bin packing, storage orchestration, batch execution, access controls, log aggregation, SSH access, batch processing, and much more.

  • 庞大的社区

K8S拥有庞大的社群,在github上拥有超过66,000颗星以及2544个贡献者。网络上有大量的博客文章来介绍K8S(包括你正在读的),也有几本写的不错的书籍(比如Kubernetes In Action)来介绍K8S。它的生态系统非常丰富,有专门提供K8S服务的提供商(比如AWS的EKS),有大量开发人员为K8S研发插件和工具。

  • 可用于传统的数据中心或者云服务提供商

K8S能够应用在传统的数据中心。在传统的数据中心使用K8S的麻烦之处在于需要有专门的人准备服务器,用网线连接这些服务器,在服务器上安装K8S以及容器等等。因此在传统的数据中心搭建K8S服务不是一件容易的事情。除此之外,许多云服务商已经开始提供K8S服务(比如AWS提供了EKS,Google Cloud提供了GKE,Azure提供了AKS),使用云服务商提供的K8S服务的好处是能够直接使用,而无需关心背后的软件和硬件资源。当然你也可以将K8S部署在个人电脑上,但是会失去一些功能,比如K8S的Worker节点只有一个。

  • 技术得到了验证

K8S期初是由Google研发的,并在内部管理里了十几万台服务器。经过多年的实践以及改进最终对外发布了K8S。Google有大量互联网服务(比如Google Doc,Google Email,Google Search等等),这些服务的背后由成千上百万的容器支撑,因此为了高效管理这些容器,支持大规模伸缩以及提高可靠性,那么K8S在问世的时候就已经考虑这些特性了。

K8S的组成部分

让我们先从用户角度来审视K8S,然后逐渐深入到各个组件。从用户角度来说,K8S在用户和一族机器之间提供了一层抽象。通过这层抽象,用户只需要给K8S提供yaml文件,K8S就能够根据该文件调度资源(比如创建容器,部署应用,替换无用的资源等),如下图所示:

为了操作K8S,那么需要一个类似汽车方向盘的东西,而这个东西就是kubectl。这是K8S官方提供的命令行工具,任何操作K8S的命令,都应该通过该工具下达。用户要做的只是在yaml文件里定义:创建哪种类型的容器以及创建几个,它们需要的CPU和内存是多少等等,并通过kubectl工具将该文件发送到K8S服务,该服务自己就能根据yaml文件中的内容选择一个最优的方案来调度资源(包括选择服务器,监控节点和容器状态,弹性伸缩容器数量,重启容器等等)。

如果你站近一点审视K8S,如下图所示:

你会发现K8S由2部分组成,它们分别是Control PlaneWorker Nodes。接下来让我们看看这2部分的具体内容。

  • Control Plane

Control Plane管理着K8S背后的一族服务器。kubectl下达的命令会经过它,并由它来调度Worker Nodes。为了高可用性,Control Plane通常需要3个以上的节点来支持,每一个节点运行着以下4部分:

  1. Kubernetes API Server

Kubernetes API Server是操作K8S的入口,当你用kubectl或者发送HTTP请求时,这些操作会发送到这里。

  1. Scheduler

Scheduler的主要作用在于择优选择哪些Worker Nodes来运行容器实例。它会根据高可用性(比如试图在不同的Worker Node节点上运行相同的容器实例,确保单个节点失败了,另外一个节点依然能够提供服务),资源使用情况(比如,将容器实例创建在CPU使用较少的Worker Node上),容器实例所需的资源(比如,有的容器需要使用GPU,那么它会将容器实例创建在拥有GPU的Worker Node上)等来创建并运行容器实例。

  1. Controller Manager

每个Worker Node上运行着不同的容器实例,多个相同的容器实例运行在不同的Worker Nodes上。为了监控这些相同容器实例的运行状态,则需要对应的控制器来控制这些Worker Nodes(比如某个容器实例退出了,那么需要这个控制器创建相同的容器实例,确保相同容器实例的数量是不变的)。这些控制器就是由Controller Manager启动和运行的。用户可以通过yaml文件创建多个控制器资源,每个控制器资源会监控和管理相同的容器实例。

  1. etcd

etcd是一个分布式键值对存储系统,Control Panel会把Work Nodes的配置信息存储在这里。

  • Worker Nodes

Worker nodes(或者节点)就是连在一起的服务器,这些节点有可能是物理机或虚拟机。每一个节点可以运行一个或多个容器实例。每个节点会运行以下组件:

  1. Kubelet

kubelet是Kubernetes API Server与节点的代理。kubelet从Kubernetes API Server获取信息,通过这些信息在当前节点上创建容器实例,并监控运行的容器实例,以及替换无法正常工作的容器实例。

  1. kube-proxy

kube-proxy的作用是从Kubernetes API Server收集其它容器实例的IP地址,并将当前节点的容器实例的请求转发到其它容器实例。它的主要作用在于使容器实例发现可用的服务,从而调用这些可用的服务。

K8S的资源类型

为了让K8S服务我们的数字化产品,需要在其中创建资源。用户不会直接在K8S上创建Container实例,而是通过其它类型的资源来创建容器实例。K8S提供了不同类型的资源,它们分别是:Pod,Controller,Namespace,Service,Configuration。接下来让我们看看每一类资源的作用。

  • Pod

Pod资源是K8S的基础单元。每个pod可容纳一个或者几个相关的容器实例(比如一个Web容器实例和一个收集该Web实例日志信息的容器实例)。创建pod之前,需要考虑以下几点:

  1. pod是如何部署在Worker Node上的

用户不会直接创建pod,而会通过创建Controller(K8S的另外一类资源)来创建pod。创建pod的基本流程是:Scheduler为pod选择一个Worker Node,运行在该节点上的kubelet将会创建pod,并且在该pod上创建相关容器实例。

  1. 从逻辑概念上来说,pod就相当于一台虚拟机

从逻辑角度看待pod,它就是一台虚拟机,这台虚拟机上运行了一个或多个容器实例,每一个容器实例就相当于一个进程。同一个pod中的不同容器实例共享同一个Linux namespace,因此不同容器实例可以像同一台机器上不同的进程一样通过localhost的方式进行通信。

  1. pod可以容纳不同的却相关的容器实例

一般情况下,pod只会容纳一个容器实例。但是有一些特殊情况使得一个pod需要同时容纳多个相关的容器实例。比如一个常见的例子有:一个主的容器实例(你用Node.js编写了一个web服务)和几个附属容器实例,这几个附属容器实例分别运行了用Go编写的日志收集服务和用Ruby编写的文件归档服务,这些附属的容器实例和主的容器实例是不可分割的,此时这些容器实例就应该放置在同一个pod里。

  1. pod的运行环境是短暂的

pod的运行环境是不停地变化的,当pod从某个Worker Node迁移到另外一个Worker Node时它的运行环境是不一样的。这里的运行环境指的是磁盘上产生的信息会因为pod的迁移而变化。因此pod中的容器实例不应该依赖磁盘存储。

  • Controllers

虽然pod是K8S的基础单元,但是用户不会直接创建它们。一个pod是运行在Worker Node上的,如果这个pod因为异常退出,那么运行在该Worker Node上的kubelet会重新启动新的pod,这种特性使得K8S具有自动自愈的能力。但是,如果整个Worker Node因异常退出,那么运行在这个Worker Node上的所有Pod都会受到影响。为了使这个Worker Node上的pod迁移到另外一个Worker Node上,那么需要一个更高的逻辑单元,也就是K8S的Controller资源。这类资源可以跨Worker Node迁移Pod,比如某个Worker Node退出了,Controller资源就可以选择另外一个健康的Worker Node,并将在上面启动新的pod,从而代替已经退出的pod。每个Worker Node上面同时运行了多个pod,每个pod都会受到某一个Controller资源的管理。Deployment是K8S中常见的Controller,用户只需要在yaml文件中定义该类资源,并提交给K8S,然后K8S会自动创建一个Deployment资源。接着,Deployment资源会根据yaml文件里所定义的内容来创建pod,这些内容有:

  1. 部署什么类型的pod,这类pod的容器image是什么?
  2. 这类pod需要同时运行几份?
  3. 如果该pod需要更新,那么采取哪种更新策略?

Deployment会自动部署pod并让其运行在不同的Worker Node上,然后会一直监控这些pod的运行状态,自动选择健康的Worker Node来替换不健康的Worker Node。如果需要更新pod,那么只需要更新Deployment的yaml文件(比如更新Docker image的tag),并提交给K8S,它会根据指定的更新策略(比如rolling deployment 或 canary deployment)来更新正在运行的pod。

  • Namespaces

Namespaces是K8S的某一类资源,它允许用户为资源分区。分区的作用是为了逻辑上隔离不同的研发环境,比如一个数字化产品需要test,stage,prod环境,每一个环境都会运行一族服务器资源,为了单独操作某个环境的资源,那么需要借助Namespace来分区。在K8S中,几乎所有资源都是运行在某一个Namespace里,如果创建某类资源时没有定义Namespace,那么该资源将会创建在一个default的Namespace,这个Namespace是K8S保留的,为了使用其它Namespace,那么用户需要自己创建所需的Namespace。最后要注意的是,Namespace只是为资源从逻辑上进行了分区,并不会影响不同分区不同资源的通信和交互。

  • Services和Service Discovery

每一个pod都会有一个对应的IP地址,但是这个pod上的IP地址会经常改变,比如pod从A节点换到B节点,这些pod的IP地址就改变了。一般情况下,你不会直接与单个pod通信,而会通过一个Service资源来和许多相同的pod通信,而这个Service资源拥有固定的IP地址,它可以将请求均匀分配给背后的pod。一般情况下,一个服务会由相同的pod组成,为了高可用性,这些pod会运行在不同的Worker Node上。为了使这些pod对外提供服务,那么需要告诉K8S创建Service资源,并由该资源分配请求给背后的pod以及对外提供固定的IP地址。该Service资源的调用者可以是K8S中的资源或者是外部资源。K8S中的资源可以通过环境变量或者内置的DNS服务来发现服务。比如,一个pod启动之后它会把K8S中已有服务的域名加载到环境变量里,并通过内置的DNS服务来发现服务。假设我们部署了一个服务,创建了一个Service资源,叫backend,一个Deployment资源和许多pod。为了使用该服务,我们可以拿到这个服务的域名信息,格式为backend..svc.cluster.local,其中NAMESPACE为该Service资源所在的分区。

  • 配置和加密信息

为了支持相同容器实例在不同环境调用不同资源,那么可以借助ConfigMap,它是一个key/value键值对,value可以是简单的字符串类型或者文件内容。K8S将ConfigMap存储在etcd里,pod在启动的时候可将ConfigMap作为环境变量或者放到该pod的文件系统里,通过这种方式可以使不同环境相同的实例访问不同资源。

如果需要为pod提供一些敏感信息,比如数据库的密码,那么需要借助Kubernetes Secret。Secrets类似于ConfigMaps但是有以下特点:

当pod需要使用这些敏感信息时,K8S只会将其存储在该pod的内存里或者文件系统里,K8S确保这些敏感信息不会持久化存储。这种做法确保了敏感信息不容易泄露。除此之外,这些信息是以加密的方式存储在etcd里的。

注意: etcd的加密功能只在1.13或之后版本的K8S出现,大多数K8S服务是不支持这种加密功能的。之前版本的K8S甚至不会将敏感信息加密存储到etcd里。

在AWS上搭建K8S服务的选项

在AWS上搭建K8S服务的方式有以下3种,它们的困难等级从难到易。

  • 完全自己搭建

在AWS上完全自己搭建K8S,则需要借助EC2计算资源。你需要在EC2实例上安装Docker,K8S,并将这些实例连接成一个整体。你还需要配置Master Nodes和Worker Nodes,为每一个Node添加合适的访问权限,不仅如此,你还需要为其添加存储资源,定时更新等等。这些工作如果是给一个专业的K8S团队来实现,那么至少需要3到6个月。

  • 借助K8S工具

市面上有很多工具能够帮助你轻松在AWS上搭建K8S服务,这些工具有eksctl, kops, kubespray, kubeadm等。虽然这些工具能够帮助你通过几行命令就能创建K8S族,但是它们依然难以结合自身情况定制和管理K8S族。不仅如此,这些工具还不支持Infrastructure As Code,这就使得你没法使用版本控制来跟踪历史。与自己搭建类似,这些工具没办法帮助维护K8S族,你依然需要定期更新软件,确保K8S服务是高可用的。

  • 使用AWS的EKS服务

Amazon EKS是开箱即用的K8S服务,用户可以直接通过它创建K8S服务,并直接使用。其中的维护,更新之类的工作则全都由AWS处理,这种方案特别适合没有能力自己搭建K8S服务的团队。不过这种选项一些缺点,它的收费模式是按照每个实例每小时0.1美元计费的,除此之外,AWS无法及时将K8S的新功能添加到EKS服务。

参考

  1. Kubernetes Liveness and Readiness Probes: How to Avoid Shooting Yourself in the Foot

2cloudlab.com为企业准备产品的运行环境,只需要1天!

听起来还不错 ?

如果你所在的企业遇到了以下问题:
研发流程混乱不堪或者效率低下、经历了持续上升的运维成本、无法及时向用户发布新的服务或产品以及想使用云计算技术但缺乏经验!
那么,请毫不犹疑地

联系我们