Kubernetes 有状态应用管理与访问控制详解
1. 有状态应用与 Operator 概述
在 Kubernetes 中,StatefulSets 使得复杂的有状态数据系统成为可行的工作负载。不过,Kubernetes 对 StatefulSet 中运行的工作负载理解有限,像备份、故障转移、领导者注册、新副本注册和升级等复杂操作,在以 StatefulSet 运行时需要仔细考虑。
1.1 Operator 简介
早期,CoreOS 的站点可靠性工程师(SREs)为 Kubernetes 创建了名为 Operator 的云原生软件。其初衷是将运行特定应用的领域知识封装到扩展 Kubernetes 的特定控制器中。例如,在 StatefulSet 控制器基础上构建,以实现对 Cassandra 或 Kafka 的部署、扩展、升级、备份和常规维护操作。最初创建的一些 Operator 用于 etcd 和 Prometheus,它们可以处理 Prometheus 或 etcd 实例的正确创建、备份和恢复配置,就像管理 Pod 或 Deployment 一样,是新的 Kubernetes 管理对象。
直到最近,Operator 大多是 SRE 或软件供应商为特定应用创建的一次性工具。2018 年年中,RedHat 创建了 Operator Framework,它是一套包含 SDK 生命周期管理器和未来模块的工具,可实现计量、市场和注册表等功能。
Operator 不仅适用于有状态应用,由于其自定义控制器逻辑,更适合复杂的数据服务和有状态系统。虽然它在 Kubernetes 领域仍是新兴技术,但正逐渐受到众多数据管理系统供应商、云提供商和 SRE 的关注。可以查看 OperatorHub 获取最新的精选 Operator 列表。
1.2 有状态应用配置示例
以下是一个有状态应用的配置示例:
replicas: 3
template:
metadata:
labels:
role: mongo
environment: test
spec:
terminationGracePeriodSeconds: 10
containers:
- name: mongo
image: mongo:3.4
command:
- mongod
- "--replSet"
- rs0
- "--bind_ip"
- 0.0.0.0
- "--smallfiles"
- "--noprealloc"
ports:
- containerPort: 27017
volumeMounts:
- name: mongo-persistent-storage
mountPath: /data/db
- name: mongo-sidecar
image: cvallance/mongo-k8s-sidecar
env:
- name: MONGO_SIDECAR_POD_LABELS
value: "role=mongo,environment=test"
volumeClaimTemplates:
- metadata:
name: mongo-persistent-storage
annotations:
volume.beta.kubernetes.io/storage-class: "fast"
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 2Gi
1.3 StatefulSet 和 Operator 最佳实践
大型分布式有状态应用可从 Kubernetes StatefulSets 和 Operator 中受益。以下是基于当前能力的最佳实践:
-
谨慎使用 StatefulSets
:有状态应用通常需要更深入的管理,而编排器目前还难以很好地处理。
-
创建无头服务
:StatefulSet 的无头服务不会自动创建,必须在部署时创建,以便将 Pod 作为独立节点进行寻址。
-
按需分配持久卷
:应用需要有序命名和可靠扩展时,不一定需要分配持久卷。
-
处理无响应节点上的 Pod
:如果集群中的节点无响应,StatefulSet 中的 Pod 不会自动删除,而是在宽限期后进入 Terminating 或 Unknown 状态。清除这些 Pod 的方法有:从集群中移除节点对象、kubelet 恢复工作并直接删除 Pod 或使用 Operator 强制删除 Pod。强制删除应作为最后手段,要确保删除 Pod 的节点不会重新上线,避免集群中出现同名 Pod。可以使用
kubectl delete pod nginx-0 --grace-period=0 --force
强制删除 Pod。
-
处理强制删除后仍处于 Unknown 状态的 Pod
:即使强制删除 Pod,它仍可能处于 Unknown 状态。可以使用
kubectl patch pod nginx-0 -p '{"metadata":{"finalizers":null}}'
向 API 服务器打补丁,删除条目并使 StatefulSet 控制器创建新的 Pod 实例。
-
使用 preStop 钩子
:运行具有领导者选举或数据复制确认过程的复杂数据系统时,使用 preStop 钩子在 Pod 优雅关闭前正确关闭连接、强制进行领导者选举或验证数据同步。
-
考虑使用 Operator
:对于复杂的数据管理系统,可查看是否有可用的 Operator 来帮助管理应用的复杂生命周期组件。如果是内部开发的应用,可考虑将其打包为 Operator 以增加可管理性,例如参考 CoreOS Operator SDK。
2. 准入控制概述
控制对 Kubernetes API 的访问对于确保集群安全以及为所有用户、工作负载和组件实施策略和治理至关重要。准入控制器是实现这一目标的重要功能。
2.1 准入控制器是什么
准入控制器位于 Kubernetes API 服务器请求流中,在认证和授权阶段之后接收请求。它们用于在将请求对象保存到存储之前对其进行验证或修改(或两者兼有)。验证型准入控制器不能修改请求对象,而修改型准入控制器可以。
2.2 准入控制器的重要性
准入控制器的使用可分为以下三类:
| 类别 | 描述 | 示例 |
| ---- | ---- | ---- |
| 策略和治理 | 强制执行策略以满足业务需求 | - 开发命名空间仅可使用内部云负载均衡器
- 所有 Pod 中的容器必须有资源限制
- 为所有资源添加预定义的标准标签或注释
- 所有 Ingress 资源仅使用 HTTPS |
| 安全 | 确保集群安全 | 使用 PodSecurityPolicy 准入控制器控制 Pod 规范中的安全敏感字段,如拒绝特权容器或使用主机文件系统的特定路径;使用准入 Webhook 实施更精细或自定义的安全规则 |
| 资源管理 | 为集群用户提供最佳实践 | - 确保所有 Ingress 完全限定域名(FQDN)符合特定后缀
- 确保 Ingress FQDN 不重叠
- 所有 Pod 中的容器必须有资源限制 |
2.3 准入控制器类型
准入控制器分为标准和动态两类:
-
标准准入控制器
:编译到 API 服务器中,作为每个 Kubernetes 版本的插件提供,需要在启动 API 服务器时进行配置。
-
动态准入控制器
:可在运行时配置,在核心 Kubernetes 代码库之外开发。唯一的动态准入控制类型是准入 Webhook,它通过 HTTP 回调接收准入请求。
Kubernetes 提供了 30 多个准入控制器,可通过
--enable-admission-plugins
标志启用。推荐的默认设置如下:
--enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,DefaultTolerationSeconds,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,Priority,ResourceQuota,PodSecurityPolicy
其中,
MutatingAdmissionWebhook
和
ValidatingAdmissionWebhook
本身不实现准入逻辑,而是用于配置集群内运行的 Webhook 端点,转发准入请求对象。
2.4 配置准入 Webhook
准入 Webhook 的主要优点之一是可动态配置。以下是 ValidatingWebhookConfiguration 和 MutatingWebhookConfiguration 资源清单示例:
ValidatingWebhookConfiguration 示例
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
name: ## 资源名称
webhooks:
- name: ## 准入 Webhook 名称,准入审查拒绝时会显示给用户
clientConfig:
service:
namespace: ## 准入 Webhook Pod 所在的命名空间
name: ## 用于连接准入 Webhook 的服务名称
path: ## Webhook URL
caBundle: ## PEM 编码的 CA 证书包,用于验证 Webhook 的服务器证书
rules: ## 描述 API 服务器必须发送给此 Webhook 的资源/子资源的操作
- operations:
- ## 触发 API 服务器发送请求的特定操作(如 create、update、delete、connect)
apiGroups:
- ""
apiVersions:
- "*"
resources:
- ## 按名称指定的特定资源(如 deployments、services、ingresses)
failurePolicy: ## 定义如何处理访问问题或未识别的错误,必须为 Ignore 或 Fail
MutatingWebhookConfiguration 示例
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
metadata:
name: ## 资源名称
webhooks:
- name: ## 准入 Webhook 名称,准入审查拒绝时会显示给用户
clientConfig:
service:
namespace: ## 准入 Webhook Pod 所在的命名空间
name: ## 用于连接准入 Webhook 的服务名称
path: ## Webhook URL
caBundle: ## PEM 编码的 CA 证书包,用于验证 Webhook 的服务器证书
rules: ## 描述 API 服务器必须发送给此 Webhook 的资源/子资源的操作
- operations:
- ## 触发 API 服务器发送请求的特定操作(如 create、update、delete、connect)
apiGroups:
- ""
apiVersions:
- "*"
resources:
- ## 按名称指定的特定资源(如 deployments、services、ingresses)
failurePolicy: ## 定义如何处理访问问题或未识别的错误,必须为 Ignore 或 Fail
这两个资源除了
kind
字段不同外,其他基本相同。后端的区别是:MutatingWebhookConfiguration 允许准入 Webhook 返回修改后的请求对象,而 ValidatingWebhookConfiguration 不允许。不过,定义 MutatingWebhookConfiguration 并仅进行验证也是可以的,但要考虑安全问题,遵循最小权限原则。
此外,ValidatingAdmissionWebhooks 和 MutatingAdmissionWebhooks 不会对 ValidatingWebhookConfiguration 和 MutatingWebhookConfiguration 对象的准入请求进行调用,避免集群进入不可恢复状态。
2.5 准入控制最佳实践
-
准入插件顺序
:在当前支持的 Kubernetes 版本中,通过
--enable-admission-plugins指定的准入插件顺序不再重要。但在准入 Webhook 中,顺序有一定影响。请求的准入或拒绝是逻辑与关系,即任何一个准入 Webhook 拒绝请求,整个请求都会被拒绝并返回错误。同时,修改型准入控制器总是在验证型准入控制器之前运行。 - 避免修改相同字段 :配置多个修改型准入 Webhook 时,由于无法控制请求流顺序,应避免修改相同字段,以免产生意外结果。建议配置验证型准入 Webhook 确认修改后的资源清单是否符合预期。
-
失败策略
:准入 Webhook 配置资源中的
failurePolicy字段定义了 API 服务器在准入 Webhook 出现访问问题或遇到未识别错误时的处理方式。可设置为Ignore或Fail。Ignore表示继续处理请求,Fail表示拒绝整个请求。忽略关键准入 Webhook 可能导致业务依赖的策略未应用到资源而用户却不知情,可在 API 服务器无法访问准入 Webhook 时发出警报。Fail可能会因准入 Webhook 问题拒绝所有请求,应将规则范围限定为特定资源请求,避免应用于所有资源。 -
避免复杂逻辑
:编写自己的准入 Webhook 时,要注意其决策和响应时间会直接影响用户/系统请求。所有准入 Webhook 调用配置了 30 秒超时,超时后
failurePolicy生效。避免使用复杂逻辑或依赖外部系统处理准入/拒绝逻辑,以免影响用户体验。 -
作用域配置
:准入 Webhook 可通过
NamespaceSelector字段指定作用的命名空间。该字段默认匹配所有命名空间,可使用matchLabels字段匹配特定命名空间标签。建议始终使用该字段,实现每个命名空间的显式选择。 -
避免在系统命名空间运行
:
kube-system是所有 Kubernetes 集群共有的保留命名空间,运行系统级服务。建议不要对该命名空间的资源运行准入 Webhook,可通过NamespaceSelector字段实现。对于其他集群运行所需的系统级命名空间也应如此。 - 使用 RBAC 锁定配置 :创建 MutatingWebhookConfiguration 和 ValidatingWebhookConfiguration 是集群的根级操作,必须使用基于角色的访问控制(RBAC)进行适当锁定,否则可能导致集群故障或应用工作负载遭受注入攻击。
- 避免发送敏感数据 :准入 Webhook 对于用户来说是黑盒,不清楚其如何存储和操作请求。在发送请求负载时要考虑数据敏感性,如 Kubernetes 秘密或 ConfigMaps 可能包含敏感信息,应将资源规则范围限定为验证和/或修改所需的最小资源,避免泄露敏感信息。
3. 授权概述
在 Kubernetes 中,授权在认证后但准入前进行。授权通常用于回答“这个用户是否能够对这些资源执行这些操作”的问题。后续将进一步探讨如何配置不同的授权方式。
以上介绍了 Kubernetes 中有状态应用管理、准入控制和授权的相关内容,掌握这些知识有助于更好地管理和保护 Kubernetes 集群。
3.1 授权模块与配置
Kubernetes 提供了多种授权模块,不同的授权模块适用于不同的场景和需求。以下是常见的几种授权模块:
| 授权模块 | 描述 | 适用场景 |
| ---- | ---- | ---- |
| Node | 基于节点的授权,用于授权 kubelet 对 API 服务器的访问 | 节点层面的资源访问控制 |
| ABAC(Attribute-Based Access Control) | 基于属性的访问控制,根据用户、资源和环境的属性来决定是否授权 | 需要灵活的属性匹配和复杂策略的场景 |
| RBAC(Role-Based Access Control) | 基于角色的访问控制,通过定义角色和角色绑定来授权 | 广泛应用于多用户、多角色的集群环境 |
| Webhook | 通过调用外部的 Webhook 服务来进行授权决策 | 与外部身份验证和授权系统集成的场景 |
3.1.1 RBAC 配置示例
RBAC 是 Kubernetes 中最常用的授权方式,下面是一个简单的 RBAC 配置示例:
# 创建一个角色
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
# 创建一个角色绑定
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
namespace: default
subjects:
- kind: User
name: jane
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
上述配置创建了一个名为
pod-reader
的角色,该角色具有获取、监视和列出 Pod 的权限。然后创建了一个角色绑定
read-pods
,将用户
jane
绑定到该角色上,使得用户
jane
可以在
default
命名空间中执行与
pod-reader
角色相关的操作。
3.1.2 授权配置流程
配置授权的一般流程如下:
1.
确定授权需求
:明确需要控制哪些用户对哪些资源执行哪些操作。
2.
选择授权模块
:根据需求选择合适的授权模块,如 RBAC、ABAC 等。
3.
定义资源和操作
:确定需要保护的资源(如 Pod、Service 等)以及允许的操作(如创建、删除、更新等)。
4.
创建角色或策略
:根据选择的授权模块,创建相应的角色、策略或规则。
5.
绑定角色或策略
:将角色或策略绑定到用户、用户组或服务账户上。
6.
测试和验证
:使用测试用户或服务账户进行操作,验证授权配置是否生效。
3.2 授权与准入控制的协同工作
授权和准入控制在 Kubernetes 中协同工作,共同保障集群的安全性和合规性。以下是它们的工作流程 mermaid 流程图:
graph LR
A[用户请求] --> B[认证]
B --> C[授权]
C -->|授权通过| D[准入控制]
C -->|授权失败| E[拒绝请求]
D -->|准入通过| F[保存到存储]
D -->|准入失败| E
从流程图可以看出,用户请求首先经过认证,确认用户身份的合法性。然后进行授权,判断用户是否有权限执行请求的操作。如果授权通过,请求进入准入控制阶段,由准入控制器对请求对象进行验证和修改。只有当准入控制也通过时,请求对象才会被保存到存储中;否则,请求将被拒绝。
3.3 授权最佳实践
- 最小权限原则 :为用户和服务账户分配最小的必要权限,避免过度授权。例如,只授予用户执行其工作所需的特定资源和操作权限。
- 定期审查和更新 :随着集群的发展和业务需求的变化,定期审查和更新授权配置,确保其仍然符合安全和合规要求。
- 使用命名空间隔离 :利用命名空间将不同的工作负载和用户进行隔离,为每个命名空间设置独立的授权策略,提高管理效率和安全性。
- 监控和审计 :启用授权相关的监控和审计功能,记录用户的操作和授权决策,以便及时发现和处理异常行为。
4. 总结
Kubernetes 中的有状态应用管理、准入控制和授权是保障集群安全、稳定运行的重要组成部分。通过合理使用 StatefulSets 和 Operator,可以更好地管理有状态应用的复杂生命周期;利用准入控制器可以在 API 服务器层面实施策略和治理,确保资源的创建和修改符合规定;而授权模块则可以精确控制用户和工作负载对资源的访问权限。
在实际应用中,需要根据具体的业务需求和安全要求,选择合适的技术和配置方式,并遵循最佳实践进行操作。同时,要不断学习和关注 Kubernetes 的最新发展,及时调整和优化集群的管理和安全策略,以应对不断变化的挑战。
希望本文介绍的内容能够帮助你更好地理解和应用 Kubernetes 中的这些关键技术,提升集群的管理水平和安全性。
超级会员免费看
1119

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



