我试着玩了一下Kyverno
关于这篇文章
我在业务中使用Kyverno,但只使用了部分功能,尚未完全掌握所有功能,因此我正在撰写这篇文章进行调查。
Kyverno是什么?
Kyverno是专为Kubernetes设计的策略引擎。策略指的是在创建k8s资源时的规则。例如…
-
- Podには必ず○○というLabelがついていないといけない
-
- latestタグの利用禁止
- などなど
我认为与OpenPolicyAgent相比的一个重大区别是可以不使用像Rego这样的特殊语言来定义策略。
Kyverno的功能
-
- リソースが新規作成された際に別のリソースを新規作成できる
-
- リソースが新規作成・更新された際にパッチを当てられる
- リソースの作成された際に、ポリシーに則ってるか検証し、作成を拒否することができる
我想要分别体验这些功能!
安装
由於Manifest在GitHub上已準備好,我們將使用它。
順便一提,我們將使用Kyverno的版本為v1.4.1。
$ kubectl apply -f https://raw.githubusercontent.com/kyverno/kyverno/v1.4.1/definitions/install.yaml
碰一下试试
产生资源
Generate Resources是一个功能,用于在创建或更新资源时触发创建新资源。您可以在此链接中了解更多信息:https://kyverno.io/docs/writing-policies/generate/
先试试看吧!
我认为在不同的命名空间中可能会有使用相同的机密信息的情况。
为了应对这种情况,我会编写一个策略,当命名空间被创建时,可以拷贝已存在的机密信息。
首先,在默认命名空间中创建作为源的秘密。
apiVersion: v1
kind: Secret
metadata:
name: sample-secret
namespace: default
type: Opaque
data:
password: aG9nZQo= # hoge
接下来,我们将定义一个复制此Secret的策略。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: sync-secrets
annotations:
policies.kyverno.io/title: Sync Secrets
policies.kyverno.io/category: Sample
policies.kyverno.io/subject: Secret
policies.kyverno.io/description: >-
copy sample secret from default namespace to requested namespace.
spec:
background: false
rules:
- name: sync-sample-secret
match:
resources:
kinds:
- Namespace
generate:
kind: Secret
name: sample-secret
namespace: "{{request.object.metadata.name}}"
synchronize: true
clone:
namespace: default
name: sample-secret
让我们创建一个命名空间并进行操作以确认。
$ kubectl create namespace test
namespace/test created
# 関係あるところだけ抜粋
$ kubectl get secret sample-secret -o yaml -n test
apiVersion: v1
data:
password: aG9nZQo=
kind: Secret
metadata:
name: sample-secret
namespace: test
type: Opaque
所以,我成功地做到了我想做的事情。
有疑問
我会写下尝试后出现的疑问和对应的答案。
spec.rules.generate.synchronize是什么意思?
在这个示例中,我们设置了 synchronize: true。这具体意味着什么呢?
如果资源是通过复制创建的,那么无法进行源代码管理。如果使用Yaml定义清单并在Git中进行管理,并使用GitOps,在这种情况下,可以直接编辑这些资源。为了防止这种情况,将synchronize设置为true,以便与复制的资源进行同步。
# コピーしたSecretリソースのパスワード部分変更
$ k edit secret sample-secret -n test
secret/sample-secret edited
# コピー元
$ k get secret sample-secret -o yaml -n default | grep password | head -1
password: aG9nZQo=
# コピー先。editで更新したのに元に戻ってる
$ k get secret sample-secret -o yaml -n test | grep password | head -1
password: aG9nZQo=
现在,刚才我们尝试编辑了复制的内容,那么如果我们编辑原始内容会发生什么呢?
# コピー元のSecretリソースのパスワード部分変更
$ k edit secret sample-secret -n default
secret/sample-secret edited
# コピー元
$ k get secret sample-secret -o yaml -n default | grep password | head -1
password: YWFhCg==
# コピー先
$ k get secret sample-secret -o yaml -n test | grep password | head -1
password: YWFhCg==
这个也会与之同步。很方便!
除了克隆(Clone)之外,还有哪些选项可供选择?
这次我们使用了克隆功能。
clone:
namespace: default
name: sample-secret
还可以直接按照声明的定义进行书写。
generate:
synchronize: true
kind: ConfigMap
name: zk-kafka-address
# generate the resource in the new 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"
资源变异
Mutate Resources是一种针对匹配资源应用修补程序的功能。
我想列举一些选项:
1. 我打算继续探讨下去。
2. 这次我们假设的场景是希望在一个命名空间的Pod下必须加载一个公共的ConfigMap。
首先,我们创建一个命名空间。
$ kubectl create namespace test2
namespace/test2 created
接下来,我们将创建一个要加载的ConfigMap。
apiVersion: v1
kind: ConfigMap
metadata:
name: sample-configmap
namespace: test2
data:
environment_name: staging
我们需要写一个策略,让test2中的Pod能够加载上述的ConfigMap。使得ConfigMap中的值可以变为环境变量。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: add-configmap-policy
annotations:
policies.kyverno.io/title: add configmap
policies.kyverno.io/category: Sample
policies.kyverno.io/subject: Pod
policies.kyverno.io/description: >-
Add env to pods which place to test2 namespace.
spec:
rules:
- name: "Set common environment variables"
match:
resources:
kinds:
- Pod
namespaces:
- test2
mutate:
overlay:
spec:
containers:
- (name): "*"
env:
- name: ENVIRONMENT
valueFrom:
configMapKeyRef:
name: sample-configmap
key: environment_name
最终,将创建用于测试的部署。
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deployment
namespace: test2
spec:
selector:
matchLabels:
app: test
replicas: 1
template:
metadata:
labels:
app: test
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
让我们来看看,这个部署将为创建的Pod添加了将ConfigMap中定义的值设置为环境变量的设置。
$ kubectl describe pod -n test2 test-deployment-c49854788-s2wg4 | grep -i ENVIRONMENT
Environment:
ENVIRONMENT: <set to the key 'environment_name' of config map 'sample-configmap'> Optional: false
我们成功地设置了一种可以自动插入env配置的设置。
问题
spec.rules.mutate.overlay是什么?
变异可以指定以下3种补丁的应用方式。
-
- overlay
追加・置き換えたいマニフェストを記述する方法です
Strategic Merge Patch
overlayと同じく、追加や置き換えの記述が出来ます
削除も可能です
RFC 6902 JSONPatch
リソースに対して json patchを当てる方法です。kustomizeでいう patchesJson6902
Strategi Merge Patchでは実現できない更新をしたいときに使います
例えばarrayの一部要素を書き換えたいとか
在match中可以指定什么?
详细的信息可以在这里找到:
https://kyverno.io/docs/writing-policies/match-exclude/
您可以通过资源的名称或标签来限制目标对象,并且还可以进行排除设置。
验证资源
这个功能是用来检查新的或现有资源是否符合定义的策略。
这次的情景设置是「必须在Pod中加入resources.requests/limits。如果没有加入,就不会生成Pod」。
首先,我们要撰写这个限制的策略。
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: all-containers-need-requests-and-limits
spec:
validationFailureAction: enforce
background: false
rules:
- name: check-container-resources
match:
resources:
kinds:
- Pod
namespaces:
- test2
validate:
message: "All containers must have CPU and memory resource requests and limits defined."
pattern:
spec:
containers:
- name: "*"
resources:
limits:
memory: "?*"
cpu: "?*"
requests:
memory: "?*"
cpu: "?*"
我会应用使用过的Deployment来进行变异。
然后…
$ kubectl apply -f test.yaml
Error from server: error when creating "test.yaml": admission webhook "validate.kyverno.svc" denied the request:
resource Deployment/test2/test-deployment was blocked due to the following policies
all-containers-need-requests-and-limits:
autogen-check-container-resources: 'validation error: All containers must have CPU
and memory resource requests and limits defined. Rule autogen-check-container-resources
failed at path /spec/template/spec/containers/0/resources/limits/'
# Podは作成されていない
$ kubectl -n test2 get pods
No resources found in test2 namespace.
所以,我成功完成了我想做的事情。
这是一个疑问
spec.background是什么?
如果将此设置为 true,则会对现有资源执行策略检查。
https://kyverno.io/docs/writing-policies/background/
如果现有资源违反政策,尽管现有资源保持不变,
但会创建名为ClusterPolicyReport或PolicyReport的资源。
$ kubectl get policyreport -A
NAMESPACE NAME PASS FAIL WARN ERROR SKIP AGE
test2 polr-ns-test2 0 1 0 0 0 67s
查看内部内容后,会显示错误原因。
这个 spec.background 的默认值是true,对于mutate或generate没有影响。
可以在spec.validationFailureAction中指定什么内容?
-
- enforce
ポリシー違反の場合、新規リソースの場合は、そのリソースは作成されません
audit
ポリシー違反の場合、ClusterPolicyReport または PolicyReport というリソースが作成されます
ポリシー違反でもそのリソースは作成されます
其他方便功能
这一次我没有亲自触摸,但是我会介绍一下似乎在熟练使用时很方便的功能。
变量
您可以将请求的资源信息作为变量使用。
https://kyverno.io/docs/writing-policies/variables/
还可以调用ConfigMap的信息。
这意味着可以基于ConfigMap定义的值进行验证或其他操作。
https://kyverno.io/docs/writing-policies/external-data-sources/
本题要求以中文原生方式重新表达给定的短语”前提条件”。
假设基础
如果想要进行比”match”或”exclude”更精细的条件指定,可以使用”preconditions”。
https://kyverno.io/docs/writing-policies/preconditions/