前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 Kyverno 定义 Kubernetes 策略

使用 Kyverno 定义 Kubernetes 策略

作者头像
崔秀龙
发布2019-07-22 15:50:28
1.1K0
发布2019-07-22 15:50:28
举报
文章被收录于专栏:伪架构师

Kubernetes 的日常使用过程中,在对象提交给集群之前,我们会有很多机会,很多方法对资源的 Yaml 定义进行检查和处理。很多读者应该也会知道,资源提交之后,还有机会使用 Admission Controller 对资源动动手脚,这其中其实有很多可以提炼出来的标准动作,可以用统一的控制器来进行处理,Kyverno 就是这样一个工具。有了 Kyverno 的帮助,YAML 程序员可以根据条件对资源进行筛选,符合条件的资源可以:

  • 验证资源:对资源定义进行检查,不符合条件的资源拒绝创建,从而保证集群资源的合规性。
  • 修改资源:在资源定义中进行注入,强制资源部分行为的一致性。
  • 生成资源:在资源创建时,同时创建相关的资源。

安装

安装过程是很简单的,安装清单文件位于 https://github.com/nirmata/kyverno/raw/master/definitions/install.yaml,使用 kubectl 直接部署即可:

代码语言:javascript
复制
$ kubectl create -f https://github.com/nirmata/kyverno/raw/master/definitions/install.yaml
customresourcedefinition.apiextensions.k8s.io/policies.kyverno.io created
namespace/kyverno created
service/kyverno-svc created
serviceaccount/kyverno-service-account created
clusterrolebinding.rbac.authorization.k8s.io/kyverno-admin created
deployment.extensions/kyverno created

有一点需要注意的是资源的类型范围,可以在主进程的命令行参数中设定不需要处理的资源类型,缺省设置为:

代码语言:javascript
复制
  containers:
    - name: kyverno
      image: nirmata/kyverno:latest
      args: ["--filterKind","Node,Event,APIService,Policy,TokenReview,SubjectAccessReview"]
      ports:

策略定义

安装完成后,就可以编写策略了,策略的规则不算复杂,具体格式可以从 install.yaml 中的 CRD 定义里面推断出来。

代码语言:javascript
复制
apiVersion : kyverno.io/v1alpha1
kind: Policy
metadata:
  name: sample-policy
spec:
  rules: # 规则数组,spec 的唯一下级
  - name: check-rule-1
    resource: # 定义选择条件,限制生效范围
      kinds: # 生效对象类型数组,必要字段
      - Deployment
      - StatefulSet
      namespace: default  # 命名空间
      name: "*" # 资源名称
      selector: # 用更加复杂一点的方式来定义选择方式
        matchLabels: # 精确匹配标签
          app: some-app
        matchExpressions: # 表达式匹配标签
          key: "operator"
          operator: In
          values:
          - v2
          - v3
    validate:
      ...
    mutate:
      ...
    generate:
      ...

resource 部分是固定的,而 validate mutate generate 三个动作则各有各的结构。

下面用几个例子来演示一下他的功能。

验证资源(validate)

定义一个限制特定命名空间下镜像地址的策略如下:

代码语言:javascript
复制
apiVersion : kyverno.io/v1alpha1
kind: Policy
metadata:
  name: check-registries
spec:
  rules:
  - name: check-registries
    resource:
      kinds:
      - Deployment
      namespace: default
    validate:
      message: "Registry is not allowed"
      pattern:
        spec:
          template:
            spec:
              containers:
              - name: "*"
                image: "docker.io/citizenstig/*"

这个策略文件中,pattern 部分和我们要处理的 deployment 文档结构一致,其中支持通配符,可以用它来对目标进行校验,这里我们要求 default 命名空间中的 Deplyment 对象,containers 下的 image 字段必须符合 docker.io/citizenstig/* 的通配符要求。

例如下面的的 Deployment 就无法创建:

代码语言:javascript
复制
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: httpbin
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: httpbin
        version: v1
    spec:
      containers:
        - name: httpbin
          image: citizenstig/httpbin
          imagePullPolicy: IfNotPresent
代码语言:javascript
复制
$ kubectl apply -f httpbin.yaml
Error from server: error when creating "httpbin.yaml": admission webhook "nirmata.kyverno.validating-webhook" denied the request:
Policy check-registries failed with following rules;rulename: check-registries;Rule check-registries: Validation has failed, err Failed to validate value citizenstig/httpbin with pattern docker.io/citizenstig/*. Path: /spec/template/spec/containers/0/image/.

但是如果我们换个命名空间就没问题了:

代码语言:javascript
复制
$ kubectl create ns free
kunamespace/free created
$ kubectl apply -f httpbin.yaml -n free
deployment.extensions/httpbin created

又或者我们不用 Deployment,直接创建 Pod:

代码语言:javascript
复制
apiVersion: v1
kind: Pod
metadata:
  name: static-httpbin
spec:
  containers:
    - name: httpbin
      image: citizenstig/httpbin

果然就能够创建成功了:

代码语言:javascript
复制
$ kubectl apply -f pod.yaml
pod/static-httpbin created

这样的绕过自然是我们不想要的,但是可以改变策略,把限制做到 Pod 上:

代码语言:javascript
复制
  rules:
  - name: check-registries
    resource:
      kinds:
      - Pod
      namespace: default
    validate:
      message: "Registry is not allowed"
      pattern:
        spec:
          containers:
          - name: "*"
            image: "docker.io/citizenstig/*"

这样更新之后,不管是 Deployment 还是静态 Pod 都无法通过了。

如果使用 kubectl edit deploy httpbinimage 字段修改为 docker.io/citizenstig/httpbin,就能看到 deployment 能够正常工作了。

或者我们可以要求所有 Pod 都必须指定 CPU 限制:

代码语言:javascript
复制
validate:
  message: "resources/limits is needed."
  pattern:
    spec:
      template:
        spec:
          containers:
          - resources:
              limits:
                cpu: "*"

这个策略提交之后,上面的 Deploy 就再次无法部署了:

代码语言:javascript
复制
$ kubectl apply -f httpbin.yaml
Error from server: error when creating "httpbin.yaml": admission webhook "nirmata.kyverno.validating-webhook" denied the request:
...
Path: /spec/template/spec/containers/0/resources/limits/. Expected map[string]interface {}, found <nil>.

修改清单,加入资源限制,即可满足条件。

修改资源(mutate)

这里也可以做类似自动注入的内容,例如我们可以要求所有 default 命名空间中的 Deployment,如果 deployment 标签中有 io=heavy,则分配到 ssd=true 的节点上。

代码语言:javascript
复制
apiVersion : kyverno.io/v1alpha1
kind: Policy
metadata:
  name: assign-ssd
spec:
  rules:
  - name: assign-ssd
    resource:
      kinds:
      - Deployment
      namespace: default
      selector:
        matchLabels:
          io: heavy
    mutate:
      overlay:
        spec:
          template:
            spec:
              nodeSelector:
                ssd: true

修改一下上面的 Deployment,加上标签:

代码语言:javascript
复制
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: httpbin
  labels:
    io: heavy
spec:
...

提交到集群之后,查看变更结果:

代码语言:javascript
复制
$ kubectl get deployments httpbin -o yaml
apiVersion: extensions/v1beta1
kind: Deployment
...
    spec:
...
      dnsPolicy: ClusterFirst
      nodeSelector:
        ssd: "true"

看到多出来的 nodeSelector 字段,如果查看 Pod 信息,也会发现这个 Deployment 的所有 Pod 都分配到了指定的节点上。

创建资源(generate)

有时候我们在 Kubernetes 上创建资源的时候,可能希望同时提供一些缺省资源,例如一个新的命名空间,我们希望其中包含缺省的 Configmap 或者 SA 或者资源限制。

例如我们要在新建 test-n 的命名空间的同时,创建名为 dummy 的 sa。

代码语言:javascript
复制
apiVersion : kyverno.io/v1alpha1
kind: Policy
metadata:
  name: auto-sa
spec:
  rules:
  - name: auto-sa
    resource:
      kinds:
      - Namespace
      name: "test-*"
    generate:
      kind: ServiceAccount
      name: dummy
      data:
        spec: {}
        metadata:
          labels:
            source: "webhook"

这个策略生效后,每次我们创建形如 test-* 的命名空间,其中都会生成对应的名为 dummy 的 ServiceAccount,并且有标签:source=webhook

Generate 还提供了复制对象的方法,例如每个新命名空间中都应该复制一个名为 connConfigmap,就可以使用如下策略:

代码语言:javascript
复制
apiVersion : kyverno.io/v1alpha1
kind: Policy
metadata:
  name: auto-cm
spec:
  rules:
  - name: auto-cm
    resource:
      kinds:
      - Namespace
      name: "test-*"
    generate:
        kind: ConfigMap
        name: conn
        clone:
          namespace: default
          name: conn

随意验证一下:

代码语言:javascript
复制
$ kubectl create configmap conn \
    --from-literal=mysql=mysql \
    --from-literal=mongodb=mongodb
configmap/conn created
$ kubectl create ns test-6
namespace/test-6 created
$ kubectl get cm,sa -n test-6
NAME             DATA   AGE
configmap/conn   2      6s

NAME                     SECRETS   AGE
serviceaccount/default   1         7s
serviceaccount/dummy     1         6s

这里会发现,随着新的命名空间的创建,新的 SA 和 CM 也都出现了。

结论

相对于其他的类似工具,Kyverno 在灵活、强大和易用之间取得了一个很好的平衡,不需要太多学习时间,就能够提供相当方便的功能,官网提供了大量的针对各种场景的样例,非常值得一看。

参考链接

  • 项目主页: https://kyverno.io/
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 伪架构师 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 安装
  • 策略定义
  • 验证资源(validate)
  • 修改资源(mutate)
  • 创建资源(generate)
  • 结论
  • 参考链接
相关产品与服务
容器镜像服务
容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档