Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What are the problem?
Organization

Kyvernoをさわってみた

この記事について

業務でKyvernoを使ってますが、一部機能しか使っておらず
全機能を把握できてないため調査のためにこの記事を書いてます。

Kyvernoとは

KyvernoとはKubernetes向けのポリシーエンジンです。
ポリシーとはk8sリソースを作成する際のルールです。
例えば・・・

  • Podには必ず○○というLabelがついていないといけない
  • latestタグの利用禁止
  • などなど

OpenPolicyAgentとの大きな違いとして、
Regoのような特別な言語を用いずにポリシーを定義できる点だと思います。

Kyvernoでできること

  • リソースが新規作成された際に別のリソースを新規作成できる
  • リソースが新規作成・更新された際にパッチを当てられる
  • リソースの作成された際に、ポリシーに則ってるか検証し、作成を拒否することができる

これらの機能をそれぞれ触ってみたいと思います!

インストール

マニフェストがGitHubで用意されてるのでそれを使います。
ちなみに今回使うKyvernoのバージョンは v1.4.1 です。

$ kubectl apply -f https://raw.githubusercontent.com/kyverno/kyverno/v1.4.1/definitions/install.yaml

さわってみた

Generate Resources

Generate Resourcesとは、リソースの新規作成 or 更新されたのをトリガーに
新たなリソースを作成する機能です。
https://kyverno.io/docs/writing-policies/generate/

とりあえずやってみましょう!

各Namespaceで同じSecret情報を使いたいことがあると思います。
そういうシーンを想定して、Namespaceが作成されたのをトリガーにすでに存在するSecretをコピーするポリシーを書いてみます。

まずコピー元となるSecretをdefault namespaceに作成します。

secret-sample.yaml
apiVersion: v1
kind: Secret
metadata:
  name: sample-secret
  namespace: default
type: Opaque
data:
  password: aG9nZQo= # hoge

次にこのSecretをコピーするポリシーを定義します。

secret-copy-policy.yaml
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

ではNamespaceを作成して動作を確認してみましょう。

$ 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をしてる場合、このリソースは直接編集できてしまいます。
それを防止するために、synchronizetrue にすると、コピー元のリソースと同期をしてくれます。

コピー先を編集して同期されるか確認する
# コピーした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という機能を使いました。

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

Mutate Resourcesとは、マッチしたリソースに対してパッチをあてる機能です。
https://kyverno.io/docs/writing-policies/mutate/

ではさわって行きたいと思います。
今回想定するシーンは、「あるNamespace配下のPodには必ず共通するConfigMapを読み込ませたい」です。

ではまずNamespaceを作成しましょう。

$ kubectl create namespace test2
namespace/test2 created

次に読み込ませたいConfigMapを作成します。

configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: sample-configmap
  namespace: test2
data:
  environment_name: staging

次に test2 配下のPodに対して上記ConfigMapを読み込ませるポリシーを書きましょう。
ConfigMapに記載されている値が環境変数になるような感じで!

add-configmap-policy.yaml
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

最後にテスト用のDeploymentを作成します。

test.yaml
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

このDeploymentで作成される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とは?

mutateは以下の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/

リソースの名前やラベルでも対象を制限できますし、除外設定も行えます。

Validate Resources

新規・既存リソースが定義したポリシーを満たしているかを検査する機能です。

今回想定するシーンは「Podには必ずresources.requests/limitsを入れる。入れてない場合Podを生成しない」です。
まずその制限をするポリシーを書きます。

require-req-limit-policy.yaml
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: "?*"

mutateのとき使った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で定義した値を元にValidationを行ったりすることができるというものです。
https://kyverno.io/docs/writing-policies/external-data-sources/

前提条件

matchexclude よりもさらに細かい条件指定を行いたい場合に
preconditions というものが使えます。
https://kyverno.io/docs/writing-policies/preconditions/

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
2
Help us understand the problem. What are the problem?