1
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

Organization

Kyvernoとは:CNCF LandscapeのSandbox Projectに飛び込む

CNCF Landscape内のあるプロジェクトで活動の第一歩を踏み出したので、その模様をお伝えします。本記事が同じような興味を持ってる方の参考になればと思います。

image.png

本記事で得られること

  • CNCFの新しいSandbox ProjectであるKyvernoの概要
  • 成長が早いCloud Native界隈のOSSプロジェクトに参加するとどうなるか、の疑似体験

本活動の動機

近頃Cloud Native周辺の動向をウォッチしている。本も買ってお勉強したり、オンラインになったのを機にKubeConに参加して色々セッションを聴いていると、何か自分で手を動かしてみたくなってくるのだが、特に仕事でもCloud Nativeな技術(K8s)に触れる機会は今のところなく、個人的にマイクロサービスとしてK8s上で動かして何かしたい、ということも見当たらない。ということで、数あるCNCFのプロジェクトのどれかに個人的に参加してみることにした。が、星の数ほどあるCNCF Landscape上のプロジェクトの中から、参加するプロジェクトを決めるだけで悩ましい。ということで、CNCFに加わって一番日の浅いSandbox Projectの中から選択してみることにした。

https://www.cncf.io/sandbox-projects/
https://github.com/cncf/toc/blob/master/docs/PROJECTS.csv

Project Accepted Stage About
SchemaHero 11/10/2020 Sandbox A Kubernetes operator for declarative database schema management
Cloud Development Kit for Kubernetes (cdk8s) 11/10/2020 Sandbox Define Kubernetes native apps and abstractions using object-oriented programming
cert-manager 11/10/2020 Sandbox Automatically provision and manage TLS certificates in Kubernetes
OpenKruise 11/10/2020 Sandbox Automate everything on Kubernetes
Tinkerbell 11/10/2020 Sandbox a flexible bare metal provisioning engine
Pravega 11/10/2020 Sandbox Streaming Storage Platform
Kyverno 11/10/2020 Sandbox Kubernetes Native Policy Management

利用言語とプロジェクトがターゲットとしている技術エリア、コミュニティの規模などから、Kyvernoをチョイスした。素人ながらPolicy managementにおいて現在Open Policy Agent(OPA)というのがソリューションの1つとして良く目にするが、OPAがK8sに限らず利用できるソリューションであるのに対して、K8s Nativeな形で機能を提供するという方向性にチャレンジ精神を感じたのも選択理由の1つだったりする。

Kyvernoとは

Kubernetesの中ではPolicy Mangementといくつか種類があり、ポッド間のネットワークトラフィックをセキュアに保つためのNetwork Policy、ポッドの権限やアクセスポリシーを制御するPod Security Policy、リソースの使用量を管理するQuotas and Limit Rangeがある。Kyvernoでカバーする範囲はPod Security Policyに該当し、Kubernetes上で動かす各ワークロードの設定をクラスタ全体で一貫したルールに則って運用したい場合に向いている。近年では、各企業が社内の開発部隊向けに自社のKubernetesプラットフォームを立ち上げて運用しているケースが多くある。このような社内システムを運用するプラットフォームチームが、社内の運用ルールを全チーム横断で展開する場合などに、本機能が有効である。

たとえば、Kubernetesクラスタをセキュアにするために実施すべき10のプラクティスなどをポリシーとしてリソース化して、あらゆる操作に当てはめると漏れなく、最低限の対策が展開できる。

まずはコミュニティにアクセスしてみる

コミュニケーションのチャネルはGoogle Group(ML)とSlackと月1回のCommunity Meetings。
Google GroupはMeeting連絡程度にしか使われておらず、Slackが主な模様。slack.k8s.io にサインアップして #kyverno チャンネルへ。

すぐにレスポンスをくれて、good first issueなissueを更新してくれて、手の付けやすいissueの用意までしてくれた。とてもinclusiveである。

image.png

ということでログレベルの修正タスクからチャレンジしてみることにする。

環境のセットアップ

kindでclusterを立ち上げる

今まではDocker Desktop For WindowsのKubernetesクラスタをWSL2環境から使っていたが、最近観た以下のKubeConのチュートリアルセッション(おすすめ!)で使っていたkind上でkyvernoを触ってみる。

kyvernoのインストール

Custom Resource DefinitionであるKyvernoはhelmで簡単にインストールができた

ポリシーリソースの構造を簡単に学ぶ

上記の図で十分ではあると思うが、Policyは1つ以上のRuleブロックで構成されており、各Ruleブロックでは適用するリソースの条件をMatchブロックに記述し、ヒットした際のアクションをMutate,Validate or Generateで記述する構造になっている。

簡単な動作テスト

Kubernetes上で動かすアプリケーションには以下のようなラベルをメタデータとして持つことを推奨しているが、決して必須ではない。ラベルがないからクラスタ上で動作しない、ということはない。が、組織内の運用上のルールで、外部ツールとの連携や効率的な情報のクエリを可能にするために、特定のメタデータについては入力必須とするようなポリシーをクラスタ横断的に制定したい場合の例である。

クラスタ上のあらゆるPodに対して、app.kubernetes.io/nameのラベル付与を強制するポリシーになる。

# require-labels.yaml
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-labels
spec:
  validationFailureAction: enforce
  rules:
  - name: check-for-labels
    match:
      resources:
        kinds:
        - Pod
    validate:
      message: "label `app.kubernetes.io/name` is required"
      pattern:
        metadata:
          labels:
            app.kubernetes.io/name: "?*"

これを適用する。

$ kubectl create -f require-labels.yaml
clusterpolicy.kyverno.io/require-labels created

試しにメタデータを一切付与せずにコマンドラインからnginxのdeploymentを作成すると、以下の通りValidation errorとなって、deploymentに失敗する。validationFailureActionauditにすると警告ログだけ残してdeploymentは成功するようにもできる。

$ kubectl create deployment nginx --image=nginx
error: failed to create deployment: admission webhook "nirmata.kyverno.resource.validating-webhook" denied the request:

resource Deployment/default/nginx was blocked due to the following policies

require-labels:
  autogen-check-for-labels: 'Validation error: label `app.kubernetes.io/name` is required; Validation rule autogen-check-for-labels failed at path /spec/template/metadata/labels/app.kubernetes.io/name/'

一方、同じコマンドにラベルを付与するオプションを追加するとエラーもなく、deploymentによってpodの生成に成功する。

$ kubectl run nginx --image nginx --labels app.kubernetes.io/name=nginx
pod/nginx created

まずは問題の再現から

issueは、ログレベルをerrorからinfoに修正するというものだ。まずは問題の事象を再現させて、それでコレをこんな風に直すよ、みたいな感じでコミュニティと会話しながら進めていこうと思う。K8s初級者にとっては、1つ目のハードルである事象の再現だ。

早速出てきたAnti Affinityであるが、アプリケーションの可用性を少しでも高めるためにレプリカは、異なるホスト上に配置すべし、というプラクティスであると理解。逆に通信性能観点で同一ゾーンへの展開を強制するのがAffinityらしい。

再現テストをするのに、さっそくローカルのクラスタを複数ノード構成に手直しが必要か。といっても簡単に変更できた。

$ cat kind.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
  - role: control-plane
  - role: worker
  - role: worker
$ kind create cluster --config ./kind.yaml
$ k get nodes
NAME                 STATUS   ROLES    AGE    VERSION
kind-control-plane   Ready    master   117s   v1.19.1
kind-worker          Ready    <none>   87s    v1.19.1
kind-worker2         Ready    <none>   87s    v1.19.1

まずは何もポリシー適用せずに複数レプリカをデプロイしてみる。

# multi-replicas-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: busybox
    distributed: required
  name: busybox
spec:
  replicas: 2
  selector:
    matchLabels:
      app: busybox
      distributed: required
  template:
    metadata:
      labels:
        app: busybox
        distributed: required
    spec:
      containers:
      - image: busybox:1.28
        name: busybox
        command: ["sleep", "9999"]

すると既に各ノードに分散してポッドがデプロイされていることが分かる。何回か試したが、毎回各ノードにポッドが1つずつデプロイされる。ポリシーがなくても良くないか?

$ kubectl apply -f multi-replicas-deploy.yaml
deployment.apps/busybox created
$ kubectl get pod -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP           NODE           NOMINATED NODE   READINESS GATES
busybox-6c4fc5bbb7-cxnql   1/1     Running   0          14s   10.244.1.8   kind-worker2   <none>           <none>
busybox-6c4fc5bbb7-hnppd   1/1     Running   0          14s   10.244.2.6   kind-worker    <none>           <none>

とりあえず、一度deploymentを削除してanti-affinityを強制するポリシーを適用してみる。結果はポリシー適用前と変わらなかったが、このポリシーが条件にヒットしたリソースをmutateするルールなので、deploymentのマニフェストを再確認するとコマンドからapplyしたマニフェストに対して、anti-affinityの設定が追加されていることが分かった。

$ git clone https://github.com/kyverno/kyverno.git
$ kubectl apply -f kyverno/samples/more/create_pod_antiaffinity.yaml
$ kubectl get pod -o wide
NAME                       READY   STATUS    RESTARTS   AGE   IP           NODE           NOMINATED NODE   READINESS GATES
busybox-847bbfdbdc-w465p   1/1     Running   0          27s   10.244.1.9   kind-worker2   <none>           <none>
busybox-847bbfdbdc-w55ft   1/1     Running   0          27s   10.244.2.7   kind-worker    <none>           <none>
$ kubectl get deployments.apps busybox -o yaml
    ...
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - busybox
              topologyKey: kubernetes.io/hostname
            weight: 1
    ...

で、この状態からkyvernoのログを確認すると、issueにあった症状が確認されました。

E1211 17:34:12.069581       1 notequal.go:36] EngineMutate "msg"="Failed to resolve variable" "error"="could not find variable request.object.metadata.labels.app at path " "kind"="Deployment" "name"="kyverno" "namespace"="kyvernotest" "policy"="insert-podantiaffinity" "rule"="insert-podantiaffinity" "variable"=null

ログの出力個所から辿って、プログラムの構造も少しだけ理解したので、ログレベルをinfoに変えて動かしてみることにする。が、ソースからkyvernoをインストールする方法が分からない。から、さっそくコミュニティに聞いてみることにした。

  • Github上のwiki曰く、kustomizeをインストールしてレポジトリのルートにてmake releaseを実行すると、ローカルにdefinitions/install.yamlができるので、これを改めapplyするとローカルビルドのkyvernoがデプロイできるようである。

最後に

時間の都合上、issueの途中で本記事は一旦終わることにする。記事前半で見て頂けたかと思うが、コミュニティは非常に反応が早く、急に現れたKubernetes初級者の私にも時間を割いて丁寧に対応してくれた(と思っている)。新しいプロジェクトに限らず、もし興味があるプロジェクトがあるようであれば、門戸を叩いてみることを是非お勧めしたい。
本記事はissueクローズまで五月雨ではあるが更新していきたい。

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
Sign upLogin
1
Help us understand the problem. What are the problem?