Kubernetes v1.17.0がリリース されましたね。
本稿では、v1.17 のエンハンスの中で、地味ながらちょっと嬉しいかもしれない kubeadm token list の -o オプション の対応について記載します。
kubeadm token list とは
まず、 kubeadm token list とは kubeadmがクラスター構築時に生成する bootstrapトークンの一覧を表示する機能です。 kubadm init --upload-certs 実施後に実行すると下記のように表示されます。
# kubeadm token list
TOKEN                     TTL       EXPIRES                     USAGES                   DESCRIPTION                                           EXTRA GROUPS
tup37m.6cbrgvz60biqj3j5   1h        2019-12-11T21:14:55+09:00   <none>                   Proxy for managing TTL for the kubeadm-certs secret   <none>
xvir4m.dgu8wdowa19pbj6d   23h       2019-12-12T19:14:55+09:00   authentication,signing   <none>                                                system:bootstrappers:kubeadm:default-node-token
kubadm init --upload-certs によって、 2つの bootstrapトークンが生成されていることがわかります。上記の1つめは、Secret kubeadm-certs に対してTTLを設定するための bootstrap トークンです(TTLはデフォルト2時間)。ちなみに kubeadm-certs はマスターノードをjoinする際に必要となる、証明書の情報を暗号化して保持しています。2つ目はノードをjoinする際のtokenとして利用することになります(TTLはデフォルト24時間)。
なお、この2つのトークンは、実際には kubeadm で作成したクラスターのSecretとして登録されているので、 kubectl で確認することもできます。
# kubectl get secret -n kube-system --field-selector=type=bootstrap.kubernetes.io/token
NAME                     TYPE                            DATA   AGE
bootstrap-token-tup37m   bootstrap.kubernetes.io/token   4      50m
bootstrap-token-xvir4m   bootstrap.kubernetes.io/token   6      50m
kubeadm token list -o
さて、ここまでは以前のバージョンでもできたのですが、 v1.17 になってやっと -o オプションが対応されました。ヘルプを見てみましょう。
# kubeadm token list -h | grep '\-o'
  -o, --experimental-output string    Output format. One of: text|json|yaml|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file. (default "text")
-o オプションによっていくつかフォーマットが選べることがわかります。 -o json をつけて実行してみましょう。
# kubeadm token list -o json
{
    "kind": "BootstrapToken",
    "apiVersion": "output.kubeadm.k8s.io/v1alpha1",
    "token": "tup37m.6cbrgvz60biqj3j5",
    "description": "Proxy for managing TTL for the kubeadm-certs secret",
    "expires": "2019-12-11T12:14:55Z"
}
{
    "kind": "BootstrapToken",
    "apiVersion": "output.kubeadm.k8s.io/v1alpha1",
    "token": "xvir4m.dgu8wdowa19pbj6d",
    "expires": "2019-12-12T10:14:55Z",
    "usages": [
        "authentication",
        "signing"
    ],
    "groups": [
        "system:bootstrappers:kubeadm:default-node-token"
    ]
}
たしかに json で結果が得られることがわかります。これなら、 なにか別のツールでbootstrapトークンの情報が必要なときに、容易に情報を取得可能になることでしょう。これは便利そう…ですね!
joinしてみる
さて、token がわかったので joinを実行するためには kubeadm token list -o xxxx で得られた値を指定するだけで行けそうにも見えますが、もうひと工夫必要になります。 kubeadm join では --token の指定の他に、通常は --discovery-token-ca-cert-hash の指定が必要となります。 --discovery-token-ca-cert-hash は KubernetesクラスタのCA証明書の公開鍵のハッシュです。
--discovery-token-ca-cert-hash の値を採取するためにはいくつか方法はありますが、 たとえばKubernetesクラスタにjoin済みのノード内(CA証明書が /etc/kubernetes/pki/ca.crt に格納されている前提)で下記を実行すると取得できます。
# openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
aa7b901857a20600ad12c84ea746d7f774a139db9fe369a6e3e25a0b7973a695
上記で得られたハッシュと、join用のbootstrapトークンを指定することで kubeadm join することができます。たとえば、下記のとおりです。
# kubeadm join <Kubernetes APIのアドレス>:6443 \
    --token xvir4m.dgu8wdowa19pbj6d \
    --discovery-token-ca-cert-hash sha256:aa7b901857a20600ad12c84ea746d7f774a139db9fe369a6e3e25a0b7973a695
ちなみに、 おすすめはしませんが --discovery-token-ca-cert-hash の代わりに --discovery-token-unsafe-skip-ca-verification を指定しても可能ではあります。
また、マスターノード(2台目以降)の join の場合は上記に追加で --control-plane の指定と --certificate-key (Secret kubeadm-certs 内の証明書データの復号鍵) が必要になります。 --certificate-key の値は、kubeadm init 時に控えていない場合は、どこにも保存されていないので、再度 kubeadm init phase upload-certs --upload-certs を行う必要があります。
# kubeadm init phase upload-certs --upload-certs
[upload-certs] Storing the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
[upload-certs] Using certificate key:
2cb2de7f3c08ed89d941da3a3b9c141ca3685c1d18da9dfca6ad4e416afc0f24
# kubeadm join <Kubernetes APIのアドレス>:6443 \
    --token xvir4m.dgu8wdowa19pbj6d \
    --discovery-token-ca-cert-hash sha256:aa7b901857a20600ad12c84ea746d7f774a139db9fe369a6e3e25a0b7973a695 \
    --control-plane \
    --certificate-key 2cb2de7f3c08ed89d941da3a3b9c141ca3685c1d18da9dfca6ad4e416afc0f24
ただし、 kubeadm init は現状まだ -o 指定はできません。そのため、この出力を機械的にパースして --certificate-key の値を取得するのは、json等の出力と比べてややハードルが上がります。 代替手段としては、 kubeadm init を実施する前に予め別の方法で --certificate-key を用意しておく事もできたりはしますが…。
まとめ
kubeadm token list -o によって出力フォーマットを指定できることがわかりました。
ただし、現状 -o オプションは kubeadm では kubeadm token list と kubeadm version でしか対応していません。例えば kubeadm init 等でも同様の対応をされれば他のツール等の組み合わせが更に実現しやすくなることでしょう。 KEP を読むと他のコマンドの -o 対応も検討はされているようなので、今後の対応が気になるところです。
