应用容器化转型系列 - 容器部署的常见形态
「执笔人」品高股份 cloud native 资深架构师:继承
概述
在应用上云的过程中,选择适合的部署方式至关重要。前文提到过,容器技术的诞生为应用奠定了构建和运行的标准,并且直接的推动了微服务实践的飞速发展,微服务的应用大多由数十个、甚至上百个单元构成。在传统架构中,编排上百个部署单元的复杂度是非常高的,与之相对的是巨大的运维成本。而容器技术伴生的容器编排技术,可以很好的解决微服务的部署编排问题,让上百个部署单元的运维能力变得极易获取。
关于容器编排调度框架,Kubernetes 无疑是事实上的领导者,本文主要针对 Kubernetes 的应用部署实践进行探讨,例如应用的部署模式,无状态或有状态,守护程序等不同的部署方式,以及其应用场景,方便正在做或者刚开始进行容器化转型的读者能够对容器部署的常见方式有一个概要的了解,方便进行部署决策。
应用部署模式
无状态应用部署
无状态应用(Deployment)是指不依赖于特定部署状态的应用,每个请求可以独立处理。这种类型的应用可以水平扩展,提高应用的性能和可用性。
举例说明一个无状态应用的部署场景,比如一个网站的后端服务。使用 Kubernetes 部署无状态应用可以通过使用 Deployment 对多副本的容器进行扩展和管理,并通过暴露 Service 实现负载均衡。
在这个示例中,我们可以创建一个 Deployment 来定义应用的副本数、容器镜像和其他配置。Kubernetes 会自动创建和管理这些 Pod,确保应用的可用性。同时,通过创建 Service 来公开应用,Kubernetes 会自动分配一个可访问的虚拟 IP,并通过负载均衡将请求分发到后端的 Pod 上。
Service 可能是一个集群内部的 IP 地址,或者宿主机管理网络的一个代理端口,还可以与外部的负载均衡联动,这取决于应用要暴露自己的服务给谁去调用。
无状态应用的部署可以借助 Kubernetes 提供的多种功能来实现,以下是相关概念的详细说明:
Pod 和 Deployment:Pod 是 Kubernetes 中最小的可调度单元,可以包含一个或多个容器。使用 Deployment 控制器可以定义应用的期望状态,Kubernetes 会确保按需创建、扩展和管理 Pod 的副本。
ReplicaSet: 副本控制器是 Kubernetes 无状态应用的一个关键的功能模块,通过 ReplicaSet 可以有效控制副本数量等于期望的数量,比如弹性或者副本扩缩都是靠 副本控制器的功能完成的。
Service:Service 充当了应用的入口,为应用提供了一个虚拟 IP 和负载均衡功能。Service 可以将请求动态地分发给后端 Pod,从而实现高可用和负载均衡。
水平扩展:通过调整 Deployment 的副本数,可以实现无状态应用的水平扩展。Kubernetes 会自动增加或减少 Pod 的数量,根据负载情况来调整应用的容量。
无状态应用是 Kubernetes 最先支持的应用,也是最为云原生的应用,微服务通过完全无状态化,可以将应用的部署成本降到最低。企业应用在进行微服务化改造的过程中,应该致力于增加无状态应用的比例,尽可能减少应用层的状态,将这些状态交给消息中间件、数据库、存储层去解决。
有一种更加容易上手,并且快速完成应用容器化转型,并取得突出成果的方式: 企业可以对应用进行分类,先完成无状态应用的容器化,将那些错综复杂的陈旧应用暂时搁置在虚拟机或物理机中,而无状态应用的规模化部署,可以快速的积累容器化运维运营经验,并发挥其弹性、负载、敏捷的特点,为业务产生实际客观的价值。而针对那些有状态的应用,可以在第二阶段,通过使用有状态应用 (Statefulset) 的方式进行部署。
有状态应用部署
有状态应用 (Statefulset) 是指应用需要访问和保留特定的状态或数据的应用,比如数据库服务。在部署有状态应用时,需要考虑数据的持久化、网络标识和有序部署等问题。
示例
举例说明一个有状态应用的部署场景,比如一个使用 MySQL 数据库的应用。在 Kubernetes 中,可以使用 StatefulSet 来管理有状态应用的部署。StatefulSet 提供了唯一的网络标识、有序部署和稳定的持久化存储。
在这个示例中,我们可以创建一个 StatefulSet 来定义 MySQL 数据库的副本数、容器镜像和其他配置。Kubernetes 会自动创建和管理这些有状态的 Pod,为每个 Pod 分配唯一的网络标识和稳定的持久化存储卷。
有状态应用(StatefulSet)会为 Pod 设置启动顺序,并给每个 Pod 设置唯一的网络标识,为每一个 Pod 挂载独立的存储卷。通过这种标识能力,使得 mysql-0 和 mysql-1 可以承担不同的角色,比如 master 和 slave。
功能介绍
有状态应用具备以下功能特性:
有序的 Pod 编号:Pod 的创建是按自增序列部署的,例如 mysql-0,mysql-1。
稳定的网络标识:每个 Pod 都拥有一个基于其顺序索引的稳定的主机名,在 pod 中执行 hostname 可以得到固定不变的 hostname。
稳定有序的存储:有状态应用的 PVC 声明,会为每一个 pod 副本创建独立的卷,并且每次重建 Pod 都会按照固定的顺序挂载。
有序扩容缩容: 有状态应用的副本扩容和缩容都是有顺序的,并且是一个一个串行进行的,其扩容会按顺序逐个增加,而缩容会按倒序逐个回收。
结合无头服务: 有状态应用可以结合无头服务,对每一个 Pod 进行访问,例如部署一个叫做 mysql 的无头服务,可以通过 mysql-0.mysql 只访问 mysql-0 的 Pod , 通过 mysql-1.mysql 只访问 mysql-1 ,这种能力便于有状态应用组建集群
有状态应用(Statefulset)中的状态到底指的是什么呢?是这种应用会持久化数据吗?但是所有的容器都能够持久化数据,例如 Deployment,Kubernetes 是一个容器编排框架,它解决的是容器的部署问题,那么可以认为其关心的状态是容器的部署状态,包括启动顺序,唯一网络标识,独立的存储卷等。而我们的应用生态中,存在大量的需要维持部署状态的场景。例如像 etcd、mysql、redis 等。
以网络标识为例,Deployment 并不需要,它一般通过负载均衡提供访问,并不关心请求到哪一个副本中,而 mysql 这类服务,对应用来说有明确的访问目标,比如应用要写 master,读取 slave,而网络标识就是为了解决这个场景。 它对于应用部署状态的维护非常重要,以至于 Kubernetes 专门设计了 Headless 的服务(无头服务) 来专门配合使用。
在 Kubernetes 的编排框架中,还有像守护程序(DaemonSet)、定时任务(CronJob)、一次性任务(Job)等用来声明不同的容器部署行为的编排类型。而在编排类型之外,对于部署拓扑关系,Kubernetes 也提供了丰富的工具供应用使用。
应用部署拓扑
在传统虚拟机或云主机的应用生态中,云主机的创建具有各种不同的拓扑部署策略,例如云主机有些要分散,比如分散节点、分散集群、分散可用区,甚至分散数据中心,同样的有些也要就近,例如应用编组业务,为了减少网络开销,要部署在同一个单元中。总结来说是一种亲和和反亲和的部署需求。
除此之外,还根据应用的特点,有些会指定节点,例如要部署到不同 CPU 架构的 IAAS 节点上,部署到不同性能的服务器上,部署到不同存储的服务器上等;
对应到容器上,诸如 CPU 架构、机器性能、GPU 算力、物理拓扑等诉求同样存在,并且由于部署单元的大幅度增加,部署的复杂度远远超过虚拟机的部署拓扑场景。Kubernetes 编排框架为此设计了丰富的调度能力:
通用调度机制
Kubernetes 原生就支持了例如节点选择、污点与容忍度、亲和性与反亲和性等多种部署策略,通过声明式的应用描述,可以简便的描述上述算力选择和拓扑位置的部署场景,并且由于部署声明 “ 一次创建,处处运行 ”的特点,使得应用的调度更为便利。
反亲和性: 应用彼此之间调度到不同的节点
亲和性:应用尽量调度到同一个节点
调度框架
如果以上通用的调动方法还不能满足应用的部署场景,Kubernetes 还提供了编排框架,允许应用自定义调度器,实现差异化的调度。
简单来说,它包含过滤和打分两个环节,以及许多接入点,允许应用在任意一个调度环节中自定义自己的逻辑,以达到影响容器调度结果的目的。
举例来说,对于一些网络敏感的业务,我们可以通过监控数据分析出网络带宽较为空闲的节点,通过将其分数调高,反之则分数调低,以达到期望业务调度到这种类型的节点上的调度目标。同样的,还有些 CPU 密集的,或者内存密集的业务,都可以有同样的处理方式。
(有一种说法是 Kubernetes 是一种面向研发的框架,它的开放性和可扩展性,对于研发人员来说,非常的友好。)
总结
在本文中,我们介绍了 Kubernetes 的不同部署方式,包括无状态应用部署、有状态应用部署,以及应用部署拓扑的常见方法和场景,每种部署方式都有其特点和适用场景,企业可以根据自身需求选择合适的部署策略。通过合理的部署和管理方式,可以更好地利用 Kubernetes 的优势,实现应用的高可用性、可扩展性和灵活性。
评论