Kubernetes:构建高级应用平台与管理有状态应用
1. 构建应用平台最佳实践
1.1 平台交互性
将平台中定义的应用暴露为 Kubernetes 服务,集群内的任何应用都能使用这些应用,而无需考虑它们是否运行在高级平台中。同样,使用 Kubernetes DNS 服务器进行服务发现,高级应用平台就能连接到集群中运行的其他应用。构建封闭的平台会使其无法与外界交互,因此跨不同平台的互连性是复杂应用的常见设计模式。
1.2 构建平台的最佳实践
- 使用准入控制器 :限制和修改对集群的 API 调用。准入控制器可以验证(并拒绝无效的)Kubernetes 资源,变异准入控制器可以自动修改 API 资源,添加新的边车或其他用户可能无需知晓的更改。
- 使用 kubectl 插件 :通过向熟悉的现有命令行工具添加新工具来扩展 Kubernetes 用户体验。在极少数情况下,专门构建的工具可能更合适。
- 考虑平台用户需求 :构建平台时,要仔细考虑平台用户及其需求的演变。使事情简单易用是一个好目标,但如果这导致用户被限制,并且不重写平台外的所有内容就无法成功,那么最终将是一次令人沮丧(且不成功)的体验。
2. 管理有状态应用
2.1 有状态应用的需求演变
在容器编排的早期,目标工作负载通常是无状态应用,必要时使用外部系统存储状态。随着时间的推移,基于容器的有状态工作负载的需求成为现实,在某些情况下可能更具性能优势。Kubernetes 经过多次迭代,不仅允许将存储卷挂载到 Pod 中,而且直接管理这些卷成为编排需要存储的工作负载的重要组成部分。
2.2 卷和卷挂载
并非每个需要维护状态的工作负载都需要是复杂的数据库或高吞吐量数据队列服务。许多迁移到容器化工作负载的应用期望某些目录存在,并向这些目录读写相关信息。以下是一个使用 Kubernetes hostPath 挂载的示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-webserver
spec:
replicas: 3
selector:
matchLabels:
app: nginx-webserver
template:
metadata:
labels:
app: nginx-webserver
spec:
containers:
- name: nginx-webserver
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: hostvol
mountPath: /usr/share/nginx/html
volumes:
- name: hostvol
hostPath:
path: /home/webcontent
2.3 卷最佳实践
- 限制卷的使用 :尽量将卷的使用限制在需要多个容器共享数据的 Pod 中,例如适配器或大使类型的模式。对于此类共享模式,使用 emptyDir。
- 使用 hostDir :当基于节点的代理或服务需要访问数据时,使用 hostDir。
- 日志处理 :识别将关键应用日志和事件写入本地磁盘的服务,如果可能,将其更改为 stdout 或 stderr,并让真正支持 Kubernetes 的日志聚合系统流式传输日志,而不是依赖卷映射。
2.4 Kubernetes 存储
2.4.1 持久卷(PersistentVolume)
可以将持久卷视为支持挂载到 Pod 的任何卷的磁盘。持久卷有一个声明策略,该策略将定义卷的生命周期范围,独立于使用该卷的 Pod 的生命周期。Kubernetes 可以使用动态或静态定义的卷。要允许动态创建卷,Kubernetes 中必须定义存储类。以下是一个持久卷的示例:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv001
labels:
tier: "silver"
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /tmp
server: 172.17.0.2
2.4.2 持久卷声明(PersistentVolumeClaim)
持久卷声明是向 Kubernetes 提供 Pod 将使用的存储资源需求定义的一种方式。Pod 将引用该声明,如果存在与声明请求匹配的持久卷,它将把该卷分配给特定的 Pod。至少必须定义存储请求大小和访问模式,但也可以定义特定的存储类。还可以使用选择器来分配满足特定条件的持久卷:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClass: nfs
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
selector:
matchLabels:
tier: "silver"
2.4.3 存储类(Storage Classes)
管理员可以选择创建存储类对象,而不是提前手动定义持久卷。存储类对象定义要使用的卷插件以及该类的所有持久卷将使用的任何特定挂载选项和参数。这允许声明定义要使用的特定存储类,Kubernetes 将根据存储类参数和选项动态创建持久卷:
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: nfs
provisioner: cluster.local/nfs-client-provisioner
parameters:
archiveOnDelete: True
2.4.4 容器存储接口(CSI)和 FlexVolume
CSI 和 FlexVolume 通常被称为“树外”卷插件,它们使存储供应商能够创建自定义存储插件,而无需像如今大多数卷插件那样等待直接向 Kubernetes 代码库添加代码。CSI 插件解决了 FlexVolume 需要在集群的所有节点上安装特定驱动程序的问题,它的使用就像在集群中部署一个 Pod 一样简单。
2.5 Kubernetes 存储最佳实践
- 启用默认存储类 :如果可能,启用 DefaultStorageClass 准入插件并定义默认存储类。许多需要持久卷的应用的 Helm 图表默认使用图表的默认存储类,这允许应用在无需太多修改的情况下安装。
- 考虑集群架构 :设计集群架构时,无论是在本地还是在云提供商中,都要考虑计算层和数据层之间的区域和连接性,使用适当的标签标记节点和持久卷,并使用亲和性使数据和工作负载尽可能接近。
- 评估工作负载状态需求 :仔细考虑哪些工作负载需要在磁盘上维护状态。能否由外部服务(如数据库系统)处理,或者如果在云提供商中运行,能否由与当前使用的 API 一致的托管服务(如 MongoDB 或 MySQL 即服务)处理?
- 使应用更无状态 :确定修改应用代码以使其更无状态需要付出多少努力。
- 处理数据冗余和备份 :虽然 Kubernetes 会在调度工作负载时跟踪和挂载卷,但它尚未处理存储在这些卷中的数据的冗余和备份。CSI 规范为供应商添加了一个 API,如果存储后端支持,可以插入原生快照技术。
- 验证数据生命周期 :验证卷将保存的数据的正确生命周期。默认情况下,动态预配的持久卷的回收策略设置为在 Pod 删除时从后端存储提供商删除卷。敏感数据或可用于法医分析的数据应设置为回收。
2.6 有状态应用
2.6.1 ReplicaSet 对有状态应用的挑战
要充分理解关键差异,必须了解典型的 ReplicaSet 如何调度和管理 Pod,以及每个方面如何对传统有状态应用造成不利影响:
-
Pod 命名
:ReplicaSet 中的 Pod 在调度时会扩展并分配随机名称。
-
Pod 缩容
:ReplicaSet 中的 Pod 以任意方式缩容。
-
Pod 访问
:ReplicaSet 中的 Pod 从不通过其名称或 IP 地址直接调用,而是通过与服务的关联进行调用。
-
Pod 重启和迁移
:ReplicaSet 中的 Pod 可以随时重启并移动到另一个节点。
-
持久卷关联
:ReplicaSet 中映射了持久卷的 Pod 仅通过声明关联,但任何具有新名称的新 Pod 在重新调度时如有需要可以接管该声明。
2.6.2 StatefulSets
StatefulSets 使运行期望更可靠节点/Pod 行为的应用系统变得更容易。与 ReplicaSet 中的典型 Pod 特征相比,StatefulSets 提供了几乎完全相反的特性:
-
Pod 命名
:StatefulSet 中的 Pod 扩展时会分配顺序名称。随着集合扩展,Pod 获得序号名称,默认情况下,新 Pod 必须完全上线(通过其存活和/或就绪探针)才能添加下一个 Pod。
-
Pod 缩容
:StatefulSet 中的 Pod 按相反顺序缩容。
-
Pod 访问
:StatefulSet 中的 Pod 可以在无头服务后面通过名称单独寻址。
-
持久卷使用
:需要卷挂载的 StatefulSet 中的 Pod 必须使用定义的持久卷模板。StatefulSet 中的 Pod 声明的卷在 StatefulSet 删除时不会被删除。
以下是一个无头服务和 StatefulSet 的定义示例:
# 无头服务定义
apiVersion: v1
kind: Service
metadata:
name: mongo
labels:
name: mongo
spec:
ports:
- port: 27017
targetPort: 27017
clusterIP: None # 这创建了无头服务
selector:
role: mongo
# StatefulSet 定义
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: mongo
spec:
serviceName: "mongo"
2.7 StatefulSets 与有状态应用的关系
StatefulSets 为有状态应用提供了更可靠的调度和管理机制,解决了 ReplicaSet 在处理有状态应用时的诸多问题。通过使用 StatefulSets,可以确保有状态应用(如数据库系统)的稳定性和数据一致性。
综上所述,在使用 Kubernetes 构建应用平台和管理有状态应用时,遵循上述最佳实践和技术方案,可以提高应用的可维护性、可靠性和性能。同时,不断关注 Kubernetes 的最新发展和存储技术的创新,以适应不断变化的应用需求。
3. 有状态应用管理流程总结
3.1 有状态应用管理流程
为了更清晰地展示有状态应用在 Kubernetes 中的管理流程,下面给出一个 mermaid 格式的流程图:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
A([开始]):::startend --> B{是否需要状态存储}:::decision
B -->|是| C(评估存储需求):::process
B -->|否| D(使用无状态部署):::process
C --> E{选择存储方式}:::decision
E -->|持久卷| F(创建持久卷和声明):::process
E -->|其他| G(选择合适存储方案):::process
F --> H(创建 StatefulSet):::process
G --> H
H --> I(部署有状态应用):::process
I --> J{应用运行中}:::decision
J -->|正常| K(监控和维护):::process
J -->|异常| L(故障排查和修复):::process
K --> M([结束]):::startend
L --> K
D --> M
这个流程图展示了从开始评估应用是否需要状态存储,到最终应用运行和维护的整个过程。如果应用需要状态存储,会进一步评估存储需求,选择合适的存储方式,创建相应的资源并部署应用,最后进行监控和维护。如果应用不需要状态存储,则直接使用无状态部署。
3.2 有状态应用管理步骤对比
为了更直观地对比 ReplicaSet 和 StatefulSets 在管理有状态应用时的差异,下面给出一个表格:
| 管理方面 | ReplicaSet | StatefulSets |
| — | — | — |
| Pod 命名 | 随机分配 | 顺序分配 |
| Pod 缩容 | 任意方式 | 按相反顺序 |
| Pod 访问 | 通过服务关联 | 可通过名称单独寻址 |
| Pod 重启和迁移 | 随时进行 | 更可靠,有顺序要求 |
| 持久卷关联 | 仅通过声明,新 Pod 可接管 | 使用定义的持久卷模板,卷不随 StatefulSet 删除 |
从这个表格可以清晰地看到,StatefulSets 在管理有状态应用时提供了更可靠和有序的方式,解决了 ReplicaSet 在处理有状态应用时的一些问题。
4. 存储相关操作总结
4.1 存储操作步骤列表
在使用 Kubernetes 进行存储管理时,涉及到多个操作步骤,下面以创建持久卷、持久卷声明和存储类为例,给出操作步骤列表:
4.1.1 创建持久卷
- 编写持久卷配置文件,示例如下:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv001
labels:
tier: "silver"
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /tmp
server: 172.17.0.2
-
使用
kubectl apply -f <配置文件名>命令创建持久卷。
4.1.2 创建持久卷声明
- 编写持久卷声明配置文件,示例如下:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClass: nfs
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
selector:
matchLabels:
tier: "silver"
-
使用
kubectl apply -f <配置文件名>命令创建持久卷声明。
4.1.3 创建存储类
- 编写存储类配置文件,示例如下:
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: nfs
provisioner: cluster.local/nfs-client-provisioner
parameters:
archiveOnDelete: True
-
使用
kubectl apply -f <配置文件名>命令创建存储类。
4.2 存储操作注意事项
在进行存储操作时,还需要注意以下几点:
-
存储类选择
:选择合适的存储类对于应用的性能和可靠性至关重要。要根据应用的需求和集群的环境选择存储类。
-
资源回收策略
:不同的资源回收策略会影响数据的生命周期。对于敏感数据或需要保留的数据,要设置合适的回收策略。
-
数据备份和冗余
:虽然 Kubernetes 本身不处理数据的冗余和备份,但可以通过 CSI 规范提供的 API 进行相关操作,确保数据的安全性。
5. 总结
在 Kubernetes 环境中构建高级应用平台和管理有状态应用是一个复杂但重要的任务。通过将平台应用暴露为 Kubernetes 服务,利用准入控制器、kubectl 插件等工具,可以构建出更具交互性和易用性的应用平台。在管理有状态应用方面,了解 ReplicaSet 和 StatefulSets 的差异,合理选择存储方式,遵循存储最佳实践,可以确保有状态应用的稳定运行。
同时,通过流程图、表格和操作步骤列表等方式,可以更清晰地理解和掌握相关的技术和操作。在实际应用中,要不断根据应用的需求和集群的环境进行调整和优化,以提高应用的性能和可靠性。希望这些内容能为大家在 Kubernetes 中构建和管理应用提供有价值的参考。
超级会员免费看

被折叠的 条评论
为什么被折叠?



