创建有状态工作负载StatefulSet

有状态工作负载在运行中会保存数据或状态。您可以通过容器服务控制台创建StatefulSet类型的应用,满足您快速创建有状态应用的需求。本文介绍如何创建一个Nginx的有状态应用并验证该有状态应用的数据持久化特性。

前提条件

使用镜像创建有状态的StatefulSet应用前,请确保您已经进行以下操作:

背景信息

StatefulSet包括以下特性:

场景

说明

Pod一致性

包含次序(启动、停止次序)、网络一致性。此一致性与Pod相关,与被调度到哪个节点无关。

稳定的持久化存储

通过VolumeClaimTemplate为每个Pod创建一个PV。删除或减少副本不会删除相关的存储卷。

稳定的网络标志

Pod的hostname模式为:(StatefulSet名称)-(序号)

稳定的次序

对于N个副本的StatefulSet,每个Pod都在[0,N)的范围内分配一个唯一的数字序号。

创建有状态StatefulSet应用

步骤一:配置应用基本信息

  1. 登录容器服务管理控制台,在左侧导航栏选择集群

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择工作负载 > 有状态

  3. 有状态页面,单击使用镜像创建

  4. 应用基本信息页签中,设置应用的基本信息,其中类型选择为有状态(StatefulSet)。

    配置项

    描述

    应用名称

    应用的名称。

    副本数量

    即应用包含的Pod数量,默认数量为2。

    类型

    定义资源对象的类型,可选择无状态(Deployment)有状态(StatefulSet)任务(Job)定时任务(CronJob)守护进程集(DaemonSet)

    标签

    为该应用添加一个标签,标识该应用。

    注解

    为该应用添加一个注解(Annotation)。

    时区同步

    容器与节点是否使用相同的时区。

  5. 单击下一步进入容器配置页签。

步骤二:配置容器

容器配置向导页面,配置容器的镜像、资源、端口、环境变量、健康检查、生命周期、数据卷和日志。

说明

容器1页签右侧,单击添加容器可以为应用的Pod设置多个容器。

  1. 基本配置区域,完成容器的基本配置。

    参数

    描述

    镜像名称

    • 选择镜像

      您可以单击选择镜像,选择所需的镜像。支持选择以下三种类型的镜像。

      • 容器镜像服务企业版:可以选择托管在容器镜像服务ACR中的企业版镜像。需要选择镜像所属地域,以及镜像服务实例。关于ACR的更多信息,请参见什么是容器镜像服务ACR

      • 容器镜像服务个人版:可以选择托管在容器镜像服务ACR中的个人版镜像。需要选择镜像所属地域,以及镜像服务实例。

      • 制品中心:包含应用容器化基础OS镜像、基础语言镜像、AI/大数据相关镜像,本示例以制品中心的Nginx镜像为例说明。关于制品中心的更多信息,请参见制品中心

        说明

        容器镜像服务ACR提供制品中心便于您的基础镜像使用,这些基础镜像由阿里云或者龙蜥社区做版本更新及安全修复。如果您有额外的镜像需求或者问题,请加入钉钉群33605007047进行咨询。

      您还可以填写私有镜像。填写的格式为domainname/namespace/imagename:tag

    • 选择镜像拉取策略

      ACK支持以下三种镜像拉取策略(imagePullPolicy):

      • 优先使用本地镜像(IfNotPresent):如果本地有该镜像(之前拉取过该镜像至宿主机中),则使用本地镜像,本地不存在时拉取镜像。

      • 总是拉取镜像(Always):表示每次部署或扩容都会从容器镜像服务重新拉取镜像,而不会从本地拉取镜像。

      • 仅使用本地镜像(Never):仅使用本地镜像。

      说明

      当您选中镜像拉取策略时,默认不设置镜像拉取策略。

    • 设置镜像密钥

      您可以单击设置镜像密钥,为私有镜像设置密钥以确保安全。

      • 对于ACR个人版实例,您可以通过设置镜像密钥的方式拉取容器镜像。设置密钥的更多信息,请参见创建保密字典

      • 对于ACR企业版实例,您可以通过免密组件拉取镜像。具体操作,请参见使用免密组件拉取容器镜像

    资源限制

    可指定该应用所能使用的资源上限,包括CPU、内存和Ephemeral-Storage三种资源,以防止占用过多资源。关于设置资源限制的更多信息,请参见资源画像

    所需资源

    为该应用预留资源额度,包括CPU、内存和Ephemeral-Storage三种资源,即容器独占这些资源,防止因资源不足而被其他服务或进程争夺资源,导致应用不可用。关于设置所需资源的更多信息,请参见资源画像

    容器启动项

    • stdin:表示为该容器开启标准输入。

    • tty:表示为该容器分配一个虚拟终端,以便于向容器发送信号。

    通常这两个选项是一起使用的,表示将终端(tty)绑定到容器的标准输入(stdin)上。例如,一个交互式的程序从用户获取标准输入,并显示到终端中。

    特权容器

    • 选择特权容器,则privileged=true,开启特权模式。

    • 不选择特权容器,则privileged=false,关闭特权模式。

    初始化容器

    选中该选项,表示创建一个初始化容器。

    初始化容器提供了一种机制来阻塞或延迟应用容器的启动,初始化容器执行成功后,Pod内的应用容器会并行启动。例如,检测依赖服务的可用性。初始化容器可以包括一些应用镜像中不存在的实用工具和安装脚本,用来初始化应用容器的运行环境,例如设置内核参数、生成配置文件。更多信息,请参见Init Containers

  2. 可选:端口设置区域,单击新增设置容器的端口。

    参数

    描述

    名称

    设置容器端口名称。

    容器端口

    设置暴露的容器访问端口或端口名,端口号必须介于1~65535。

    协议

    支持TCP和UDP。

  3. 可选:环境变量区域,单击新增设置环境变量。

    支持通过键值对的形式为Pod配置环境变量。用于给Pod添加环境标志或传递配置等,具体操作,请参见Pod variable

    参数

    描述

    类型

    设置环境变量的类型,支持以下类型:

    • 自定义

    • 配置项

    • 保密字典

    • 变量/变量引用

    • 资源引用

    配置项、保密字典支持对全部文件的引用,以保密字典为例。选择保密字典类型,只选择目标保密字典,则默认引用全部文件。环境变量

    对应的YAML,也引用了整个密钥(Secret)。yaml

    选择资源引用,主要使用resourceFieldRef参数,从Pod规范中引用容器已经声明的资源值,然后将这些值作为环境变量传递给容器。对应的YAML如下:

    image

    变量名称

    设置环境变量名称。

    变量/变量引用

    设置变量引用的值。

  4. 可选:健康检查区域,根据需要开启存活检查就绪检查启动探测

    更多信息,请参见配置存活、就绪和启动探测器

    参数

    请求类型

    配置说明

    • 存活检查(Liveness):用于检测何时重启容器。

    • 就绪检查(Readiness):确定容器是否已经就绪,且可以接受流量。

    • 启动探测(Startup Probes):用于检测何时启动容器。

      说明

      仅Kubernetes集群1.18及之后版本支持启动探测。

    HTTP请求

    即向容器发送一个HTTP GET请求,支持的参数包括:

    • 协议HTTP/HTTPS

    • 路径:访问HTTP Server的路径。

    • 端口:容器暴露的访问端口或端口名,端口号必须介于1~65535。

    • Http头:即HTTP Headers,HTTP请求中自定义的请求头,HTTP允许重复的Header。支持键值对的配置方式。

    • 延迟探测时间(秒):即initialDelaySeconds,容器启动后第一次执行探测时需要等待多少秒,默认为3秒。

    • 执行探测频率(秒):即periodSeconds,指执行探测的时间间隔,默认为10秒,最小为1秒。

    • 超时时间(秒):即timeoutSeconds,探测超时时间。默认1秒,最小1秒。

    • 健康阈值:探测失败后,最少连续探测成功多少次才被认定为成功。默认是1,最小值是1。对于存活检查(liveness)必须是1。

    • 不健康阈值:探测成功后,最少连续探测失败多少次才被认定为失败。默认是3,最小值是1。

    TCP连接

    即向容器发送一个TCP Socket,Kubelet将尝试在指定端口上打开容器的套接字。如果可以建立连接,容器被认为是健康的,如果不能就认为是失败的。支持的参数包括:

    • 端口:容器暴露的访问端口或端口名,端口号必须介于1~65535。

    • 延迟探测时间(秒):即initialDelaySeconds,容器启动后第一次执行探测时需要等待多少秒,默认为15秒。

    • 执行探测频率(秒):即periodSeconds,指执行探测的时间间隔,默认为10秒,最小为1秒。

    • 超时时间(秒):即timeoutSeconds,探测超时时间。默认1秒,最小1秒。

    • 健康阈值:探测失败后,最少连续探测成功多少次才被认定为成功。默认是1,最小值是1。对于存活检查(liveness)必须是1。

    • 不健康阈值:探测成功后,最少连续探测失败多少次才被认定为失败。默认是3,最小值是1。

    命令行

    通过在容器中执行探针检测命令,来检测容器的健康情况。支持的参数包括:

    • 命令行:用于检测容器健康情况的探测命令。

    • 延迟探测时间(秒):即initialDelaySeconds,容器启动后第一次执行探测时需要等待多少秒,默认为5秒。

    • 执行探测频率(秒):即periodSeconds,指执行探测的时间间隔,默认为10秒,最小为1秒。

    • 超时时间(秒):即timeoutSeconds,探测超时时间。默认1秒,最小1秒。

    • 健康阈值:探测失败后,最少连续探测成功多少次才被认定为成功。默认是1,最小值是1。对于存活检查(liveness)必须是1。

    • 不健康阈值:探测成功后,最少连续探测失败多少次才被认定为失败。默认是3,最小值是1。

  5. 可选:生命周期区域,设置容器的生命周期。

    您可以为容器的生命周期配置启动执行、启动后处理和停止前处理。具体操作,请参见配置生命周期生命周期

    参数

    描述

    启动执行

    为容器设置预启动命令和参数。

    启动后处理

    为容器设置启动后的命令。

    停止前处理

    为容器设置预结束命令。

  6. 可选:数据卷区域,增加本地存储或云存储声明PVC(Persistent Volume Claim)。

    参数

    描述

    增加本地存储

    本地存储:支持主机目录(HostPath)、配置项(ConfigMap)、保密字典(Secret)和临时目录,将对应的挂载源挂载到容器路径中。更多信息,请参见volumes

    增加云存储声明(PersistentVolumeClaim)

    支持通过PVC挂载云存储卷。在选择目标挂载源前,您需要创建云存储声明。具体操作,请参见创建持久化存储卷声明

    本例中配置了一个云存储类型的数据卷声明disk-ssd,将其挂载到容器的/tmp路径下。配置数据卷

  7. 可选:日志配置区域,进行采集配置和自定义Tag设置。

    重要

    请确保已部署Kubernetes集群,并且在此集群上已安装日志插件。

    配置项

    描述

    采集配置

    日志库:即在日志服务中生成一个对应的Logstore,用于存储采集到的日志。

    容器内日志路径:支持Stdout和文本日志。

    • Stdout:表示采集容器的标准输出日志。

    • 文本日志:表示收集容器内指定路径的日志,本例中表示收集/var/log/nginx下所有的文本日志,也支持通配符的方式。

    自定义Tag

    您还可以设置自定义Tag,设置Tag后,会将该Tag一起采集到容器的日志输出中。自定义Tag可帮助您给容器日志打上Tag,方便进行日志统计和过滤等分析操作。

  8. 单击下一步,进入高级配置向导页面。

步骤三:完成高级配置

高级配置向导页面中设置访问、伸缩、调度和标签注解。

  1. 访问设置区域,设置暴露后端Pod的方式。

    说明

    针对应用的通信需求,您可灵活进行访问设置:

    • 内部应用:对于只在集群内部工作的应用,您可以在创建服务时,根据需要选择虚拟集群IP节点端口类型的服务,来进行内部通信。

    • 外部应用:对于需要暴露到公网的应用,您可以采用两种方式进行访问设置。

      • 创建负载均衡类型的服务:您可以在创建服务时,选择负载均衡类型的服务。通过阿里云提供的负载均衡服务SLB(Server Load Balancer),使得该服务提供公网访问能力。

      • 创建路由(Ingress):通过创建路由(Ingress)提供公网访问能力。更多信息,请参见Ingress

    您可以设置暴露后端Pod的方式。本例中选择虚拟集群IP和路由(Ingress),构建一个公网可访问的Nginx应用。

    • 配置服务(Service):在服务(Service)右侧,单击创建设置服务的配置项。

      配置项

      描述

      服务名称

      输入Service(服务)的名称。

      服务类型

      选择Service类型,Service网络支持以下模式,分别对接不同来源和类型的客户端的访问,包括:

      虚拟集群IP(ClusterIP)

      虚拟集群IP(ClusterIP)主要服务于集群内部通信,仅当服务类型设置为虚拟的ClusterIP时,才支持服务实例之间的发现。通过使用无头服务Headless Service,您可以与其他服务发现机制互动,而不必依赖Kubernetes默认提供的基于ClusterIP的服务发现和负载均衡。

      负载均衡(LoadBalancer)

      说明

      新建NLB和使用已有NLB功能,目前处于灰度发布中。如需使用,请提交工单申请。

      负载均衡提供了一种方法,通过集成阿里云负载均衡器CLB(Classic Load Balancer)及网络型负载均衡NLB(Network Load Balancer),可以将集群内部应用对外暴露。相比于NodePort方式,能够显著提升应用的可用性和性能。支持如配置如下类型:

      节点端口(NodePort)

      节点端口(NodePort)提供了一种便捷的方式,使得外部用户可以通过节点的IP地址和指定的端口来访问集群中的服务。通过访问 <NodeIP>:<NodePort>,用户能够连接到NodePort服务,但是实现负载均衡的配置则需要用户自己手动完成。

      外部流量策略

      您的服务类型为节点端口负载均衡时,才能设置外部流量策略。关于外部流量策略的详细介绍,请参见Service快速入门

      • Local:流量只发给本节点的Pod。

      • Cluster:流量可以转发到集群中其他节点上的Pod。

      服务关联

      选择服务要绑定的后端应用。若不进行关联部署,则不会创建相关的Endpoints对象。关于服务关联的详细介绍,请参见services-without-selectors

      端口映射

      添加服务端口(对应Service YAML文件中的port)和容器端口(对应Service YAML文件中的targetPort),容器端口需要与后端的Pod中暴露的容器端口一致。

      注解

      为该服务添加一个注解(Annotation),配置负载均衡的参数。更多参数,请参见通过Annotation配置传统型负载均衡CLB通过Annotation配置网络型负载均衡NLB

      重要

      请勿复用集群的API Server的负载均衡实例,否则将导致集群访问异常。

      标签

      为该服务添加一个标签,标识该服务。

    • 配置路由(Ingress):在路由(Ingress)右侧,单击创建设置后端Pod的路由规则。

      配置项

      描述

      名称

      输入路由的名称。

      规则

      路由规则是指授权入站到达集群服务的规则。更多信息,请参见配置路由信息

      • 域名:输入Ingress域名。

      • 路径:指定服务访问的URL路径,默认为根路径/,本例不作配置。每个路径 (path)都关联一个backend(服务),在阿里云SLB将流量转发到backend之前,所有的入站请求都要先匹配域名和路径。

      • 服务:选择服务的名称和对应端口。

      • 开启TLS:配置安全的路由服务。具体操作,请参见Nginx Ingress高级用法

      灰度发布

      开启灰度发布开关。此处建议选择社区版。

      Ingress Class

      自定义Ingress的类。

      注解

      您可以自定义注解名称和值,也可以根据名称选择或搜索需要配置的注解。Ingress的注解请参见Annotations

      单击+添加,可对Ingress无上限地添加注解。

      标签

      标签的作用是为Ingress添加对应的标签,表示该Ingress的特点。

      单击+添加,可对Ingress无上限地添加标签。

    访问设置区域,您可以看到已创建的服务和路由,您可以单击变更删除进行二次配置。

  2. 可选:伸缩配置区域,配置是否开启指标伸缩定时伸缩,从而满足应用在不同负载下的需求。

    • 容器服务支持容器组的指标伸缩,即根据容器的CPU和内存资源占用情况自动调整容器组的数量。

      说明

      若要启用自动伸缩,您必须为容器设置所需资源,否则容器自动伸缩无法生效。

      参数

      描述

      指标

      支持CPU和内存,需要和设置的所需资源类型相同。

      触发条件

      资源使用率的百分比,超过该使用量,容器开始扩容。

      最大副本数

      该负载类型可扩容的容器数量上限。

      最小副本数

      该负载类型可缩容的容器数量下限。

    • 容器服务支持容器组的定时伸缩,即定时地对容器服务Kubernetes集群进行扩缩容。开启定时伸缩前,需先安装ack-kubernetes-cronhpa-controller组件。关于定时伸缩的详细说明,请参见步骤二:创建CronHPA任务

  3. 可选:调度设置区域,设置升级方式节点亲和性应用亲和性应用反亲和性,更多信息,请参见Affinity and anti-affinity

    说明

    亲和性调度依赖节点标签和Pod标签。您可以使用内置的标签进行调度,也可以预先为节点、Pod配置相关的标签。

    配置项

    描述

    升级方式

    升级方式包括Rollingupdate升级和OnDelete升级。更多信息,请参见StatefulSet

    节点亲和性

    设置节点亲和性,通过Worker节点的Label标签进行设置。

    节点调度支持硬约束和软约束(Required/Preferred),以及丰富的匹配表达式(In, NotIn, Exists, DoesNotExist. Gt, and Lt):

    • 必须满足,即硬约束,一定要满足,对应requiredDuringSchedulingIgnoredDuringExecution,效果与NodeSelector相同。本例中Pod只能调度到具有对应标签的Worker节点。您可以定义多条硬约束规则,但只需满足其中一条。

    • 尽量满足,即软约束,不一定满足,对应preferredDuringSchedulingIgnoredDuringExecution。调度会尽量调度Pod到具有对应标签的Node节点。您还可以为软约束规则设定权重,具体调度时,若存在多个符合条件的节点,权重最大的节点会被优先调度。您可以定义多条软约束规则,但必须满足全部约束,才会进行调度。

    应用亲和性

    决定应用的Pod可以和哪些Pod部署在同一拓扑域。例如,对于相互通信的服务,可通过应用亲和性调度,将其部署到同一拓扑域(如同一个主机)中,减少它们之间的网络延迟。

    根据节点上运行的Pod的标签(Label)来进行调度,支持硬约束和软约束,匹配的表达式有:In, NotIn, Exists, DoesNotExist

    • 必须满足,即硬约束,一定要满足,对应requiredDuringSchedulingIgnoredDuringExecution,Pod的亲和性调度必须要满足后续定义的约束条件。

      • 命名空间:该策略是依据Pod的Label进行调度,所以会受到命名空间的约束。

      • 拓扑域:即topologyKey,指定调度时作用域,这是通过Node节点的标签来实现的,例如指定为kubernetes.io/hostname,那就是以Node节点为区分范围;如果指定为beta.kubernetes.io/os,则以Node节点的操作系统类型来区分。

      • 选择器:单击选择器右侧的加号按钮,您可以添加多条硬约束规则。

      • 查看应用列表:单击应用列表,弹出对话框,您可以在此查看各命名空间下的应用,并可以将应用的标签导入到亲和性配置页面。

      • 硬约束条件:设置已有应用的标签、操作符和标签值。本例中,表示将待创建的应用调度到该主机上,该主机运行的已有应用具有app:nginx标签。

    • 尽量满足,即软约束,不一定满足,对应preferredDuringSchedulingIgnoredDuringExecution。Pod的亲和性调度会尽量满足后续定义的约束条件。对于软约束规则,您可以配置每条规则的权重,其他配置规则与硬约束规则相同。

      说明

      权重:设置一条软约束规则的权重,介于1~100,通过算法计算满足软约束规则的节点的权重,将Pod调度到权重最大的节点上。

    应用反亲和性

    决定应用的Pod不与哪些Pod部署在同一拓扑域。应用非亲和性调度的场景包括:

    • 将一个服务的Pod分散部署到不同的拓扑域(如不同主机)中,提高服务本身的稳定性。

    • 给予Pod一个节点的独占访问权限来保证资源隔离,保证不会有其他Pod来分享节点资源。

    • 把可能会相互影响的服务的Pod分散在不同的主机上。

    说明

    应用非亲和性调度的设置方式与亲和性调度相同,但是相同的调度规则代表的意思不同,请根据使用场景进行选择。

    调度容忍

    容忍被应用于Pod,允许这个Pod被调度到相应的污点上。

    调度到虚拟节点

    设置是否调度到虚拟节点,仅ACK集群Pro版支持,如果您的集群中没有虚拟节点,则无法设置该配置项。关于如何将Pod调度至虚拟节点,请参见指定ECS和ECI的资源分配

  4. 可选:标签和注释区域,单击添加设置容器组的标签和注释。

    参数

    描述

    Pod标签

    为该Pod添加一个标签,标识该应用。

    Pod注解

    为该Pod添加一个注解(Annotation)。

  5. 单击创建

步骤四:查看应用

  1. 创建成功后,默认进入创建完成页面,会列出应用包含的对象,您可以单击查看应用详情进行查看。

  2. 单击左上角返回列表,进入有状态副本集列表页面,查看创建的StatefulSet应用。

相关操作

查看有状态工作负载详情

  1. 登录容器服务管理控制台,在左侧导航栏选择集群

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择工作负载 > 有状态

  3. 有状态页面顶部,选择待查看应用的命名空间,即可查看对应命名空间下的有状态工作负载。

  4. 有状态页面,单击目标应用名称或目标应用操作列下的详情,即可查看有状态工作负载详情。

说明

在有状态列表中单击标签字段,输入对应应用标签的keyvalue,单击确定后可过滤列表中的应用。

在应用详情页面,您可以编辑、伸缩、查看YAML、重新部署、刷新应用。

操作项

描述

编辑

在应用详情页面单击编辑,您可以修改应用信息。

伸缩

在应用详情页面单击伸缩,您可以修改所需容器组数量。

以创建的Nginx应用为例,验证服务的伸缩性。

  1. 选择目标Nginx应用,单击右侧伸缩

  2. 在弹出的对话框中,将容器组数量设置为3,您可发现扩容时,扩容容器组的排序依次递增;反之,进行缩容时,先按Pod次序从高到低进行缩容。这体现StatefulSet中Pod的次序稳定性。

  3. 单击左侧导航栏中的存储卷来满足Pod的需求 > 存储声明,会显示随着应用扩容,会随着Pod创建新的云存储卷。缩容后,已创建的PV和PVC不会被删除。

查看YAML

在应用详情页面单击查看Yaml,您可以更新下载另存为YAML文件。

重新部署

在应用详情页面单击重新部署,您可以重新部署应用。

刷新

在应用详情页面单击刷新,您可以刷新应用。

在左侧导航栏单击集群,单击目标集群名称或目标集群操作列下的详情,选择工作负载 > 有状态,在有状态页面单击目标应用名称或目标应用操作列下的详情

说明

在无状态列表中单击标签字段,输入对应应用标签的keyvalue,单击确定后可过滤列表中的应用。

在应用详情页面,您可以编辑、伸缩、查看YAML、重新部署、刷新应用。

编辑已创建的有状态工作负载

有状态页面的目标应用操作列下,单击更多后,您可以进行以下操作:

操作项

描述

查看Yaml

查看应用的YAML内容。

重新部署

重新部署应用。

节点亲和性

为应用设置节点亲和性。更多信息,请参见调度配置

调度容忍

设置应用的容忍策略。更多信息,请参见调度配置

日志

查看应用的日志信息。

删除

删除应用。

批量重新部署应用

有状态页面下方,通过选择批量重新部署可以实现多个应用的重新部署。

验证StatefulSet应用的持久化存储特性

连接到Master节点,执行以下命令,验证持久化存储特性。

  1. 执行以下命令在云盘中创建临时文件。

    kubectl exec nginx-1 -- ls /tmp            #列出该目录下的文件lost+found。
    kubectl exec nginx-1 -- touch /tmp/statefulset         #增加一个临时文件statefulset。
    kubectl exec nginx-1 -- ls /tmp

    预期输出:

    lost+found
    statefulset
  2. 执行以下命令删除Pod,验证数据持久性。

    kubectl delete pod nginx-1

    预期输出:

    pod"nginx-1" deleted
  3. 过一段时间,待Pod自动重启后,验证数据持久性,证明StatefulSet应用的高可用性。

    kubectl exec nginx-1 -- ls /tmp   #数据持久化存储lost+found。

    预期输出:

    statefulset

相关文档

关于StatefulSet应用的更多信息,请参见Kubernetes有状态服务-StatefulSet使用最佳实践