じゃあ、おうちで学べる

本能を呼び覚ますこのコードに、君は抗えるか

出勤前に kubewebhook を入門していくかと思ったら時間がないので手順だけ シュッと書く

「新しいビジネス様式 byGMO」と謳って在宅勤務を継続しながら出社勤務を再開したのですがあまりにも出社から遠のいた結果、何時に家を出れば何時に会社に到着するのか分からなくなった結果、めちゃくちゃ早く会社についたのでブログを書こうかと思う

はじめに

Kubewebhook とは、Kubernetesexternal admission webhooks を作成するための小さなGoフレームワークです。

Kubewebhookを使用すると、Webhookの検証と変更を非常に高速に行うことができ、主にWebhook自体のドメインロジックに焦点を当てることができます。

特徴としては下記があります

  • Ready for mutating and validating webhook kinds (compatible with CRDs).
  • Easy and testable API.
  • Simple, extensible and flexible.
  • Multiple webhooks on the same server.
  • Webhook metrics (RED) for Prometheus with Grafana dashboard included.
  • Webhook tracing with Opentracing.
  • Type specific (static) webhooks and multitype (dynamic) webhooks.

github のissues にも記載ありますが数ヶ月間本番環境で使用されているらしく 弊社() でも本番利用しております。本番運用で以下に運用していくかはk8s-webhook-example などをみていくつかのシステムに適合していくつかのエラー処理さえ追加すればよいのではないかなーって思います。

環境構築

cluster の構築

 kind create cluster --name kubewebhook                                                                                                                                                   2250ms
Creating cluster "kubewebhook" ...
 ✓ Ensuring node image (kindest/node:v1.18.2) 🖼
 ✓ Preparing nodes 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
Set kubectl context to "kind-kubewebhook"
You can now use your cluster with:

kubectl cluster-info --context kind-kubewebhook

Have a nice day!

cluster の確認

$ kind get clusters
kubewebhook
# コンフィグの生成
$ kind get kubeconfig --name kubewebhook
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS*****************************LS0tLQo=
    server: https://127.0.0.1:35765
  name: kind-kubewebhook
contexts:
- context:
    cluster: kind-kubewebhook
    user: kind-kubewebhook
  name: kind-kubewebhook
current-context: kind-kubewebhook
kind: Config
preferences: {}
users:
- name: kind-kubewebhook
  user:
    client-certificate-data: LS0tLS1*************************************************************************S0tLQo=
    client-key-data: LS0tLS1CRUd******************************************0tCg==
$  kind get kubeconfig --name kubewebhook  > kubeconfig.yaml
$ kubectl version  --kubeconfig=kubeconfig.yaml
Client Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.0", GitCommit:"9e991415386e4cf155a24b1da15becaa390438d8", GitTreeState:"clean", BuildDate:"2020-03-25T14:58:59Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"18", GitVersion:"v1.18.2", GitCommit:"52c56ce7a8272c798dbc29846288d7cd9fbae032", GitTreeState:"clean", BuildDate:"2020-04-30T20:19:45Z", GoVersion:"go1.13.9", Compiler:"gc", Platform:"linux/amd64"}

証明書発行

自己証明書、つまりオレオレ証明書を作って利用します。subj を設定しないとちゃんと設定しないと上手く動作しませんのでご注意ください。

$ openssl genrsa -out webhookCA.key 2048
$ openssl req -new -key ./webhookCA.key -subj "/CN=pod-annotate-webhook.default.svc" -out ./webhookCA.csr
$ openssl x509 -req -days 365 -in webhookCA.csr -signkey webhookCA.key -out webhook.crt
$ kubectl create secret generic \
    pod-annotate-webhook-certs \
    --from-file=key.pem=./webhookCA.key \
    --from-file=cert.pem=./webhook.crt \
    --dry-run -o yaml > ./deploy/webhook-certs.yaml

証明書をデプロイ

先程、生成したシークレットをデプロイします。

$ kubectl apply -f ./deploy/webhook-certs.yaml

Webhookをデプロイします

Docker のビルドとKind での読み込みをやってからWebhook を受け取る処理と設定の変更を行ってくれるサーバーをデプロイします。 main.go の中で下記のような感じでPod に追加したいラベルや情報を付与していきます。

    if pod.Labels == nil {
        pod.Labels = make(map[string]string)
    }
    pod.Labels["webhook"] = "true"
$ docker build . -t kubewebhook
$ kind load docker-image kubewebhook:latest --name kubewebhook
$ kubectl apply -f ./deploy/webhook.yaml

Webhookを登録します

詳しくはDynamic Admission Control などをご覧ください。

$ kubectl apply -f ./deploy/webhook-registration.yaml

テストについて

このような よくあるyaml をデプロイします

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-test
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx

デプロイしたら "mutated": "true"および"mutator": "pod-annotate" がデプロイされているのが分かります。

$ kubectl apply -f ./deploy/test-deployment.yaml
$ kubectl get pod --show-labels
NAME                                    READY   STATUS    RESTARTS   AGE     LABELS
nginx-test-f89759699-2f4pv              1/1     Running   0          3m51s   app=nginx,pod-template-hash=f89759699,webhook=true
nginx-test-f89759699-hkxs9              1/1     Running   0          3m51s   app=nginx,pod-template-hash=f89759699,webhook=true
nginx-test-f89759699-mj9bg              1/1     Running   0          3m51s   app=nginx,pod-template-hash=f89759699,webhook=true
pod-annotate-webhook-64fcdc7758-lgbtd   1/1     Running   0          5m5s    app=pod-annotate-webhook,pod-template-hash=64fcdc7758
$ kubectl get pods/nginx-test-f89759699-mj9bg -o json |  jq '.metadata.annotations' 
{
  "mutated": "true",
  "mutator": "pod-annotate"
}

検証自体はかなり前にやっていたのですがそのログをかき集めた形になるので多少雑になったのですが時間があれば普通に解説のブログ書きます。終わり。

github.com