シェル演算子の紹介:Kubernetesの演算子をさらに簡単にする

Kubernetesの演算子機能と 、簡単な演算子を自分で記述する方法についての記事がすでにブログにあります 。 今回は、オペレータの作成を非常に簡単なレベルに引き上げるオープンソースソリューションに注目したいと思います。 シェルオペレータに精通してください!



なんで?



シェル演算子の考え方は非常に単純です。Kubernetesオブジェクトからイベントをサブスクライブし、これらのイベントを受け取ったら、外部プログラムを起動して、イベントに関する情報を提供します。







クラスターの運用中に、適切な方法で自動化することを望んでいる小さなタスクが現れ始めたときに、その必要性が生じました。 ご存知のように、演算子はGolangで作成した方がよいですが、これらの小さなタスクはすべて単純なbashスクリプトの助けを借りて解決されました。 明らかに、このような小さなタスクごとに本格的なオペレーター開発に投資することは非効率的です。



15分でオペレーター



Kubernetesクラスタで自動化できるものの例と、シェル演算子がどのように役立つかを見てみましょう。 例は次のようになります:Dockerレジストリにアクセスするためにシークレットを複製します。



プライベートレジストリの画像を使用するポッドは、マニフェストに、レジストリにアクセスするためのデータを含む秘密へのリンクを含める必要があります。 この秘密は、ポッドを作成する前に各ネームスペースで作成する必要があります。 これを手動で行うことはかなり可能ですが、動的な環境を設定すると、1つのアプリケーションの名前空間が大きくなります。 また、アプリケーションも2〜3でない場合は、秘密の数が非常に多くなります。 そして、秘密についてもう1つ、キーを変更して、レジストリに時々アクセスしたいと思います。 その結果、ソリューションとしての手動操作完全に無効になります-シークレットの作成と更新を自動化する必要があります。



簡単な自動化



N秒ごとに1回実行され、名前空間でシークレットをチェックするシェルスクリプトを作成します。シークレットがない場合は作成されます。 このソリューションの利点は、cronのシェルスクリプトのように見えることです。これは、古典的で理解可能なアプローチです。 欠点は、起動間の間隔で新しい名前空間を作成できることであり、しばらくの間はポッドの起動でエラーが発生するため、シークレットなしで残ります。



シェル演算子による自動化



スクリプトを正しく機能させるには、ネームスペースイベントが追加されたときに、従来のcron起動を起動に置き換える必要があります。この場合、使用する前にシークレットを作成できます。 これをシェル演算子で実装する方法を見てみましょう。



まず、スクリプトを解析しましょう。 シェル演算子の観点からのスクリプトはフックと呼ばれます。 --config



フラグを使用した起動時の各フックは、シェルオペレーターにそのバインディング、つまり トリガーする必要があるイベント。 この場合、 onKubernetesEvent



を使用しonKubernetesEvent







 #!/bin/bash if [[ $1 == "--config" ]] ; then cat <<EOF { "onKubernetesEvent": [ { "kind": "namespace", "event":["add"] } ]} EOF fi
      
      





ここでタイプnamespace



オブジェクトを追加( add



)するためのイベントに興味があることを説明しnamespace







次に、イベントが発生したときに実行されるコードを追加する必要があります。



 #!/bin/bash if [[ $1 == "--config" ]] ; then #  cat <<EOF { "onKubernetesEvent": [ { "kind": "namespace", "event":["add"] } ]} EOF else # : # ,  namespace  createdNamespace=$(jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH) #      kubectl create -n ${createdNamespace} -f - <<EOF apiVersion: v1 kind: Secret metadata: ... data: ... EOF fi
      
      





いいね! 結果は、小さくて美しいスクリプトです。 イメージを「復活」させるには、イメージを準備してクラスターで実行するという2つのステップが残っています。



フック付きの画像を準備する



スクリプトを見ると、 kubectl



およびjq



いることjq



。 つまり、イメージには次のものが必要です。フック、イベントを監視してフックを起動するシェル演算子、およびフックで使用されるコマンド(kubectlおよびjq)。 Hub.docker.comには、シェルオペレーター、kubectl、jqがパッケージ化された既製のイメージが既にあります。 単純なDockerfile



フックを追加することは残っていDockerfile







 $ cat Dockerfile FROM flant/shell-operator:v1.0.0-beta.1-alpine3.9 ADD namespace-hook.sh /hooks $ docker build -t registry.example.com/my-operator:v1 . $ docker push registry.example.com/my-operator:v1
      
      





クラスターの起動



もう一度、フックを見てみましょう。今回は、クラスターで実行するアクションとオブジェクトを書き出します。



  1. 名前空間イベントをサブスクライブします
  2. 実行されている場所以外の名前空間にシークレットを作成します。


画像を起動するポッドには、これらのアクションの許可が必要であることがわかります。 これは、独自のServiceAccountを作成することで実行できます。 許可はClusterRoleおよびClusterRoleBindingの形式で実行する必要があります。 クラスタ全体のオブジェクトに興味があります。



YAMLの最終的な説明は次のようなものです。



 --- apiVersion: v1 kind: ServiceAccount metadata: name: monitor-namespaces-acc --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRole metadata: name: monitor-namespaces rules: - apiGroups: [""] resources: ["namespaces"] verbs: ["get", "watch", "list"] - apiGroups: [""] resources: ["secrets"] verbs: ["get", "list", "create", "patch"] --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: monitor-namespaces roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: monitor-namespaces subjects: - kind: ServiceAccount name: monitor-namespaces-acc namespace: example-monitor-namespaces
      
      





単純な展開の形式で、組み立てられたイメージを実行できます。



 apiVersion: extensions/v1beta1 kind: Deployment metadata: name: my-operator spec: template: spec: containers: - name: my-operator image: registry.example.com/my-operator:v1 serviceAccountName: monitor-namespaces-acc
      
      







便宜上、シェルオペレーターが起動され、作成されたマニフェストが適用される別の名前空間が作成されます。



 $ kubectl create ns example-monitor-namespaces $ kubectl -n example-monitor-namespaces apply -f rbac.yaml $ kubectl -n example-monitor-namespaces apply -f deployment.yaml
      
      







それだけです。シェル演算子が起動し、名前空間作成イベントをサブスクライブし、必要に応じてフックを起動します。







したがって、 単純なシェルスクリプトはKubernetesの実際の演算子になり 、クラスターの一部として機能します。 そして、これらすべて-Golangでオペレーターを開発する複雑なプロセスなし:







このテーマには別のイラストがあり......




次の出版物のいずれかで、その意味をより詳しく明らかにします。 更新 (2019年5月1日):「 Kubernetesの拡張と拡張(レビューおよびビデオレポート) 」を参照してください。


フィルタリング



オブジェクトの追跡は適切ですが、多くの場合、オブジェクトの一部のプロパティの変更(展開内のレプリカ数の変更、オブジェクトのラベルの変更など)に対応する必要があります。



イベントが到着すると、シェル演算子はオブジェクトのJSONマニフェストを受け取ります。 このJSONで関心のあるプロパティを選択し、変更された場合にのみフックを開始できます。 これを行うには、 jqFilter



フィールドがjqFilter



れます。ここで、JSONマニフェストに適用されるjq式を指定する必要があります。



たとえば、Deploymentオブジェクトのラベルの変更に対応するには、 labels



フィールドをmetadata



フィールドからフィルターする必要があります。 設定は次のようになります。



 cat <<EOF { "onKubernetesEvent": [ { "kind": "deployment", "event":["update"], "jqFilter": ".metadata.labels" } ]} EOF
      
      





jqFilterの次の式は、Deploymentの長いJSONマニフェストをラベル付きの短いJSONに変換します。







シェル演算子は、この短いJSONが変更され、他のプロパティへの変更が無視された場合にのみフックをトリガーします。



フック起動コンテキスト



フック構成では、イベントのいくつかのオプションを指定できます-たとえば、Kubernetesからのイベントの2つのオプションと2つのスケジュール:



 {"onKubernetesEvent":[ {"name":"OnCreatePod", "kind": "pod", "event":["add"] }, {"name":"OnModifiedNamespace", "kind": "namespace", "event":["update"], "jqFilter": ".metadata.labels" } ], "schedule": [ { "name":"every 10 min", "crontab":"0 */10 * * * *" }, {"name":"on Mondays at 12:10", "crontab": "0 10 12 * * 1" ]}
      
      





小さな余談:はい、シェル演算子はcrontabスタイルのスクリプトの実行をサポートします。 詳細については、 ドキュメントをご覧ください。



フックが起動された理由を区別するために、シェルオペレーターは一時ファイルを作成し、そのパスをBINDING_CONTEXT_TYPE



変数でBINDING_CONTEXT_TYPE



BINDING_CONTEXT_TYPE



ます。 ファイルには、フックが開始された理由のJSON記述が含まれています。 たとえば、10分ごとに、フックは次の内容で開始されます。



 [{ "binding": "every 10 min"}]
      
      





...そして月曜日に、これから始まります:



 [{ "binding": "every 10 min"}, { "binding": "on Mondays at 12:10"}]
      
      





onKubernetesEvent



より多くのJSON onKubernetesEvent



ます。 オブジェクトの説明が含まれています。



 [ { "binding": "onCreatePod", "resourceEvent": "add", "resourceKind": "pod", "resourceName": "foo", "resourceNamespace": "bar" } ]
      
      





フィールドの内容は、名前から理解できます 。詳細については、 ドキュメントを参照してください 。 jqを使用してresourceName



フィールドからリソース名を取得する例は、すでにシークレットを複製するフックに示されています。



 jq -r '.[0].resourceName' $BINDING_CONTEXT_PATH
      
      





同様に、残りのフィールドを取得できます。



次は?



プロジェクトリポジトリの/ examplesディレクトリには、クラスターで実行する準備ができているフックの例があります。 フックを作成するときは、それらを基礎として使用できます。



Prometheusを使用したメトリックの収集がサポートされています-使用可能なメトリックについては、 METRICSセクションで説明しています。



ご想像のとおり、シェルオペレーターはGoで記述され、オープンソースライセンス(Apache 2.0)で配布されます。 GitHubでプロジェクトを開発する際の支援、星、問題、プルリクエストに感謝します。



秘密のベールを開き、シェルオペレーターはシステムのごく一部であり、Kubernetesクラスターにインストールされたアドオンを最新の状態に保ち、さまざまな自動アクションを実行できることもお知らせします。 サンクトペテルブルクで開催されるHighLoad ++ 2019で月曜日にこのシステムについて詳しく説明しました。このレポートのビデオとトランスクリプトは間もなく公開されます。



このシステムの残りの部分を開く計画があります:アドオン演算子と、フックとモジュールのコレクションです。 ところで、アドオンオペレーターはGitHubで既に利用可能ですが、そのドキュメントは準備中です。 モジュールのコレクションのリリースは夏に予定されています。



お楽しみに!



PS



ブログもご覧ください。






All Articles