生成资源
根据资源创建或更新创建其他资源。
generate
规则可用于在创建新资源或更新源时创建其他资源。这对于创建支持资源很有用,例如命名空间的新 RoleBindings 或 NetworkPolicies。
generate
规则像其它规则一样,支持 match
和 exclude
块。因此,可以在创建任何资源时触发该规则。还可以根据subjects、roles等匹配或排除 API 请求。
在执行 API CREATE 操作时触发 generate
规则。您可以使用 synchronize
属性,在更改时保持资源同步。当 synchronize
被设为 true
时,衍生资源会和源资源(可以定义为策略的一部分,也可以是现有资源)保持同步,并且衍生资源不能被用户修改。如果 synchronize
被设为 false
,用户可以直接修改或删除衍生资源。
注意:在 Kyverno 1.3.0 中,synchronize=true
的衍生资源可能会被其它 Kubernetes 控制器及有相应访问权限的用户修改或删除,Kyverno 将重新创建或更新资源以符合配置的策略。
当使用 generate
规则时,源资源既可以是由 Kubernetes 定义的、已存在的资源,也可以是由规则定义的新资源。如果源资源是已存在的资源,如 ConfigMap 或 Secret,将使用 clone
对象。如果源资源是规则中定义的新资源,将使用 data
对象。这些是相互排斥的,并且只能在规则中指定一个。
警告:删除包含有使用 data
对象的 generate
规则,且 synchronize=true
的策略时,将导致立即删除下游的衍生资源。包含 clone
对象的策略不受此行为的影响。
在 CustomResourceDefinitions (CRD) 中定义的 CustomResources 之前,Kubernetes 就有许多默认资源类型。Kyverno 也可以像生成 Kubernetes 默认资源一样,生成 CustomResources,但都需要给 generate
行为所依赖的 ClusterRole 授予额外的权限。要想允许 Kyverno 生成这些类型,需要修改名为 kyverno:generate
的 ClusterRole,并为其添加或更新规则以涵盖所需的资源和动词。
注意:生成自定义资源时,需要设置 apiVersion(例如 spec.generate.apiVersion
和 kind(例如 spec.generate.kind
)。
Kyverno 将创建一个名为 UpdateRequest
的中间对象,用于将工作项排队以生成最终资源。要获取生成资源的详细信息和状态,请检查 UpdateRequest
的详细信息。下面将给出 UpdateRequest
的列表。
kubectl get updaterequests -A
UpdateRequest
状态可以具有以下四个值之一:
-
Completed
:UpdateRequest 控制器完成策略中定义的资源的创建。 -
Failed
:UpdateRequest 控制器处理规则失败。 -
Pending
:请求尚未处理或资源尚未创建。 -
Skip
:通过向现有资源添加标签/注释来触发 generate 策略,而策略中未定义选择器。
使用内联数据生成 ConfigMap
此策略基于在规则中定义的 ConfigMap 为所有命名空间设置 Zookeeper 和 Kafka 连接字符串。请注意,此规则定义了 generate.data
对象,在这种情况下,该规则将使用规则清单中指定的数据创建一个名为 zk-kafka-address
的新 ConfigMap。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: zk-kafka-address
spec:
rules:
- name: k-kafka-address
match:
any:
- resources:
kinds:
- Namespace
exclude:
any:
- resources:
namespaces:
- kube-system
- default
- kube-public
- kyverno
generate:
synchronize: true
apiVersion: v1
kind: ConfigMap
name: zk-kafka-address
# 创建 namespace 时生成如下资源
namespace: "{{request.object.metadata.name}}"
data:
kind: ConfigMap
metadata:
labels:
somekey: somevalue
data:
ZK_ADDRESS: "192.168.10.10:2181,192.168.10.11:2181,192.168.10.12:2181"
KAFKA_ADDRESS: "192.168.10.13:9092,192.168.10.14:9092,192.168.10.15:9092"
克隆 ConfigMap 并传播更改
此策略中,源数据是一个已存在于 default
命名空间中名为 config-template
的 ConfigMap。请注意,当原始数据存在于 Kubernetes 中时,此处的 generate
规则将使用 generate.clone
对象。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: basic-policy
spec:
rules:
- name: Clone ConfigMap
match:
any:
- resources:
kinds:
- Namespace
exclude:
any:
- resources:
namespaces:
- kube-system
- default
- kube-public
- kyverno
generate:
# Kind of generated resource
kind: ConfigMap
# apiVersion of the generated resource
apiVersion: v1
# Name of the generated resource
name: default-config
# namespace for the generated resource
namespace: "{{request.object.metadata.name}}"
# propagate changes from the upstream resource
synchronize : true
clone:
namespace: default
name: config-template
生成 Bindings
为了让 Kyverno 生成新的 RoleBinding 或 ClusterRoleBinding 资源,它的 ServiceAccount 必须首先绑定到您尝试生成的、相同 Role 或 ClusterRole。如果不这样做,Kubernetes 会阻止请求,因为它看到来自 Kyverno ServiceAccount 可能在尝试提升权限。这不是 Kyverno 的功能,而是 Kubernetes RBAC 的工作方式。
例如,如果你想要编写一个 generate
规则,该规则会创建一个新的 RoleBinding 资源,并授予某些用户在新命名空间上的 admin
角色,Kyverno ServiceAccount 必须通过 ClusterRoleBinding 与同样的 admin 角色绑定。
为 Kyverno 的 ServiceAccount(默认名为 kyverno
)创建一个新的 ClusterRoleBinding。
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kyverno:generate-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: admin
subjects:
- kind: ServiceAccount
name: kyverno
namespace: kyverno
现在,像往常一样,创建一个 generate
规则,将名为 steven
的测试用户与新命名空间的 admin
ClusterRole 相绑定。此规则中名为 admin 的内置 ClusterRole 必须与之前 ClusterRoleBinding 中授予 Kyverno ServiceAccount 的 ClusterRole 匹配。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: steven-rolebinding
spec:
rules:
- name: steven-rolebinding
match:
any:
- resources:
kinds:
- Namespace
generate:
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
name: steven-rolebinding
namespace: "{{request.object.metadata.name}}"
data:
subjects:
- kind: User
name: steven
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: admin
apiGroup: rbac.authorization.k8s.io
新创建命名空间时,Kyverno 会生成一个名为 steven-rolebinding
的 RoleBinding,并授予用户 steven 上述新命名空间的 admin
ClusterRole。
生成 NetworkPolicy
在此示例中,新命名空间将接收到一个拒绝所有入站和出站流量的 NetworkPolicy。与第一个示例类似,generate.data 对象用于将 NetworkPolicy 资源的规范定义为覆盖模式。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: default
spec:
rules:
- name: deny-all-traffic
match:
any:
- resources:
kinds:
- Namespace
exclude:
any:
- resources:
namespaces:
- kube-system
- default
- kube-public
- kyverno
generate:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
name: deny-all-traffic
namespace: "{{request.object.metadata.name}}"
data:
spec:
# select all pods in the namespace
podSelector: {}
policyTypes:
- Ingress
- Egress
将资源与 ownerReferences 连接
在某些情况下,触发(源)资源和衍生(下游)资源需要共享相同的生命周期。也就是说,当触发资源被删除时,衍生资源也应该被删除。这样做是有价值的,因为某些资源只有在另一个资源存在时才需要,例如 LoadBalancer
类型的服务需要在某些 CNI 插件中使用特定的网络策略。虽然 Kyverno 不会在内部处理此任务,但 Kubernetes 可以通过在衍生资源中设置 ownerReferences
字段。对于下面的示例,当衍生的 ConfigMap 指定了 metadata.ownerReferences[]
对象,并定义了如下字段,包括引用触发的 Service 资源的 uid
时,就形成了所有者依赖关系。稍后,如果 Service 被删除,ConfigMap 也会被删除。有关更多详细信息,请参阅 Kubernetes 文档,包括有关这些参考范围的重要警告。命名空间级别资源不能是集群级别资源的所有者,也不允许跨命名空间引用。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: demo-ownerref
spec:
background: false
rules:
- name: demo-ownerref-svc-cm
match:
any:
- resources:
kinds:
- Service
generate:
kind: ConfigMap
apiVersion: v1
name: "{{request.object.metadata.name}}-gen-cm"
namespace: "{{request.namespace}}"
synchronize: false
data:
metadata:
ownerReferences:
- apiVersion: v1
kind: Service
name: "{{request.object.metadata.name}}"
uid: "{{request.object.metadata.uid}}"
data:
foo: bar
为现有资源生成衍生资源
在 Kyverno 1.7.0+ 中,Kyverno 支持为现有资源生成衍生资源。为现有资源生成衍生资源的策略在后台应用,根据策略中的匹配语句创建目标资源。它们也可以选择配置为在更新策略本身时应用。
在现有命名空间中生成 NetworkPolicy
默认情况下,安装时不会将策略应用于现有触发器资源。可以通过 generateExistingOnPolicyUpdate
属性配置该行为。只有 generateExistingOnPolicyUpdate
设置为 true
时,Kyverno 会在收到策略的 CREATE 和 UPDATE 事件时,为现有的触发器生成目标衍生资源。
在这个示例中,触发器资源是 Namespace
类型,将会为所有新建或已存在的 Namespace 生成一个新的 NetworkPolicy。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: generate-resources
spec:
generateExistingOnPolicyUpdate: true
rules:
- name: generate-existing-networkpolicy
match:
any:
- resources:
kinds:
- Namespace
generate:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
name: default-deny
namespace: "{{request.object.metadata.name}}"
synchronize: true
data:
metadata:
labels:
created-by: kyverno
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
为现有的 Deployment 生成 PodDisruptionBudget
下面这个策略会给已存在的或新建的 deployment 创建一个 PodDisruptionBudget
资源。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: create-default-pdb
spec:
generateExistingOnPolicyUpdate: true
rules:
- name: create-default-pdb
match:
any:
- resources:
kinds:
- Deployment
exclude:
resources:
namespaces:
- local-path-storage
generate:
apiVersion: policy/v1
kind: PodDisruptionBudget
name: "{{request.object.metadata.name}}-default-pdb"
namespace: "{{request.object.metadata.namespace}}"
synchronize: true
data:
spec:
minAvailable: 1
selector:
matchLabels:
"{{request.object.metadata.labels}}"
故障排查
要对策略应用程序故障进行故障排查,请检查 UpdateRequest
自定义资源以获取详细信息。
例如,如果未授予 Kyverno 相应的权限,您应该在 updaterequest.status 中看到此错误:
$ kubectl get ur -n kyverno
NAME POLICY RULETYPE RESOURCEKIND RESOURCENAME RESOURCENAMESPACE STATUS AGE
ur-7gtbx create-default-pdb generate Deployment nginx-deployment test Failed 2s
$ kubectl describe ur ur-7gtbx -n kyverno
Name: ur-7gtbx
Namespace: kyverno
...
status:
message: 'poddisruptionbudgets.policy is forbidden: User "system:serviceaccount:kyverno:kyverno-service-account"
cannot create resource "poddisruptionbudgets" in API group "policy" in the namespace "test"'
state: Failed