minikube で作成したクラスタ内の TLS が有効になっている etcd へのアクセス方法
Written by @ryysud Jan 30, 2019 17:56 · 2761 words · 6 minutes read
TL;DR
TLS が無効になっている etcd へのアクセス方法
$ kubectl exec --namespace kube-system etcd-minikube etcdctl cluster-health
TLS が有効になっている etcd へのアクセス方法
$ kubectl exec --namespace kube-system etcd-minikube -- \
etcdctl \
--endpoints https://127.0.0.1:2379 \
--ca-file /var/lib/minikube/certs/etcd/ca.crt \
--key-file /var/lib/minikube/certs/etcd/healthcheck-client.key \
--cert-file /var/lib/minikube/certs/etcd/healthcheck-client.crt \
cluster-health
etcd v3 に格納されたデータの確認方法
# etcd が稼働している Pod に接続
$ kubectl exec --namespace kube-system -it etcd-minikube ash
# key の一覧を取得
$ ETCDCTL_API=3 etcdctl \
--endpoints https://127.0.0.1:2379 \
--cacert /var/lib/minikube/certs/etcd/ca.crt \
--key /var/lib/minikube/certs/etcd/healthcheck-client.key \
--cert /var/lib/minikube/certs/etcd/healthcheck-client.crt \
get / --prefix --keys-only \
| sed '/^\s*$/d'
# key を元に value を取得
$ ETCDCTL_API=3 etcdctl \
--endpoints https://127.0.0.1:2379 \
--cacert /var/lib/minikube/certs/etcd/ca.crt \
--key /var/lib/minikube/certs/etcd/healthcheck-client.key \
--cert /var/lib/minikube/certs/etcd/healthcheck-client.crt \
get -w fields /registry/apiregistration.k8s.io/apiservices/v1
はじめに
minikube を使ってクラスタを起動する際に、指定する Kubernetes のバージョンによって、クラスタ内で稼働する etcd の TLS が有効になるケース(新しいバージョンは基本的に TLS 有効)があります。TLS の 無効/有効 に応じて etcd へのアクセス方法が異なるため、今回は TLS の 無効/有効 に応じた etcd へのアクセス方法を紹介します。
指定する Kubernetes のバージョンによって etcd の TLS 無効/有効 が異なる例
例1: TLS が無効になっているケース( Kubernetes v1.8.0 )
minikube で起動した VM 内に配置されている etcd の manifest を見ると、command で列挙されている etcd コマンドに TLS を有効にするのに必要なパラメータ が渡っておらず、TLS が無効になっていることがわかります。
$ minikube start --kubernetes-version=v1.8.0
$ minikube ssh sudo cat /etc/kubernetes/manifests/etcd.yaml
/etc/kubernetes/manifests/etcd.yaml の内容
apiVersion: v1
kind: Pod
metadata:
annotations:
scheduler.alpha.kubernetes.io/critical-pod: ""
creationTimestamp: null
labels:
component: etcd
tier: control-plane
name: etcd
namespace: kube-system
spec:
containers:
- command:
- etcd
- --listen-client-urls=http://127.0.0.1:2379
- --advertise-client-urls=http://127.0.0.1:2379
- --data-dir=/data/minikube
image: gcr.io/google_containers/etcd-amd64:3.0.17
livenessProbe:
failureThreshold: 8
httpGet:
host: 127.0.0.1
path: /health
port: 2379
scheme: HTTP
initialDelaySeconds: 15
timeoutSeconds: 15
name: etcd
resources: {}
volumeMounts:
- mountPath: /data/minikube
name: etcd
hostNetwork: true
volumes:
- hostPath:
path: /data/minikube
type: DirectoryOrCreate
name: etcd
status: {}
TLS が無効になっているケースでの etcd へのアクセス方法はとてもシンプルです。
まずは etcd が稼働している Pod に接続します。
$ kubectl get pods --namespace kube-system --server-print=false
NAME READY STATUS RESTARTS AGE
etcd-minikube 1/1 Running 0 4m38s
kube-addon-manager-minikube 1/1 Running 0 3m47s
kube-apiserver-minikube 1/1 Running 0 3m21s
kube-controller-manager-minikube 1/1 Running 0 4m36s
kube-dns-545bc4bfd4-4fxrp 3/3 Running 0 4m30s
kube-proxy-nd5k8 1/1 Running 0 4m30s
kube-scheduler-minikube 1/1 Running 0 3m42s
storage-provisioner 1/1 Running 0 4m29s
$ kubectl exec --namespace kube-system -it etcd-minikube ash
クライアント側の kubectl のバージョンとクラスタ側のバージョンに乖離がある(今回のケースだと kubectl が v1.13.2 でクラスタが v1.8.0 だった)と kubectl get pods
がエラーになるため --server-print=false
を付与していますが、おまじないだと思って頂いて構いません。当記事のスコープ外なので割愛しますが、興味がある方は kubernetes#65575 を参照ください。
Pod に接続したら、etcdctl コマンドを実行するだけです。特別なオプションは必要ありません。
$ etcdctl cluster-health
member 8e9e05c52164694d is healthy: got healthy result from http://127.0.0.1:2379
cluster is healthy
↑ だとデフォルトで etcd v2 api を使用していますが、etcd v3 api を使用してコマンドを実行したい場合には ETCDCTL_API=3
を付与して実行してください。
$ ETCDCTL_API=3 etcdctl endpoint health
127.0.0.1:2379 is healthy: successfully committed proposal: took = 5.651756ms
Pod に接続したことを確認して etcdctl を実行するという、少し冗長な手順を踏みましたが、もちろん以下のようにワンライナーでのアクセスも可能です。
$ kubectl exec --namespace kube-system etcd-minikube etcdctl cluster-health
member 8e9e05c52164694d is healthy: got healthy result from http://127.0.0.1:2379
cluster is healthy
例2: TLS が有効になっているケース( Kubernetes v1.13.2 )
例1と同じように etcd の manifest を見ると、command で列挙されている etcd コマンドに TLS を有効にするのに必要なパラメータ が渡っており、TLS が有効になっていることがわかります。
$ minikube start --kubernetes-version=v1.13.2
$ minikube ssh sudo cat /etc/kubernetes/manifests/etcd.yaml
/etc/kubernetes/manifests/etcd.yaml の内容
apiVersion: v1
kind: Pod
metadata:
annotations:
scheduler.alpha.kubernetes.io/critical-pod: ""
creationTimestamp: null
labels:
component: etcd
tier: control-plane
name: etcd
namespace: kube-system
spec:
containers:
- command:
- etcd
- --advertise-client-urls=https://192.168.99.108:2379
- --cert-file=/var/lib/minikube/certs/etcd/server.crt
- --client-cert-auth=true
- --data-dir=/data/minikube
- --initial-advertise-peer-urls=https://192.168.99.108:2380
- --initial-cluster=minikube=https://192.168.99.108:2380
- --key-file=/var/lib/minikube/certs/etcd/server.key
- --listen-client-urls=https://127.0.0.1:2379,https://192.168.99.108:2379
- --listen-peer-urls=https://192.168.99.108:2380
- --name=minikube
- --peer-cert-file=/var/lib/minikube/certs/etcd/peer.crt
- --peer-client-cert-auth=true
- --peer-key-file=/var/lib/minikube/certs/etcd/peer.key
- --peer-trusted-ca-file=/var/lib/minikube/certs/etcd/ca.crt
- --snapshot-count=10000
- --trusted-ca-file=/var/lib/minikube/certs/etcd/ca.crt
image: k8s.gcr.io/etcd:3.2.24
imagePullPolicy: IfNotPresent
livenessProbe:
exec:
command:
- /bin/sh
- -ec
- ETCDCTL_API=3 etcdctl --endpoints=https://[127.0.0.1]:2379 --cacert=/var/lib/minikube/certs//etcd/ca.crt
--cert=/var/lib/minikube/certs//etcd/healthcheck-client.crt --key=/var/lib/minikube/certs//etcd/healthcheck-client.key
get foo
failureThreshold: 8
initialDelaySeconds: 15
timeoutSeconds: 15
name: etcd
resources: {}
volumeMounts:
- mountPath: /data/minikube
name: etcd-data
- mountPath: /var/lib/minikube/certs//etcd
name: etcd-certs
hostNetwork: true
priorityClassName: system-cluster-critical
volumes:
- hostPath:
path: /var/lib/minikube/certs//etcd
type: DirectoryOrCreate
name: etcd-certs
- hostPath:
path: /data/minikube
type: DirectoryOrCreate
name: etcd-data
status: {}
TLS が有効になっているので、例1と同じ方法では etcd にアクセスすることができません。
$ kubectl get pods --namespace kube-system
NAME READY STATUS RESTARTS AGE
coredns-86c58d9df4-58g5x 1/1 Running 0 9m12s
coredns-86c58d9df4-8kkvt 1/1 Running 0 9m12s
etcd-minikube 1/1 Running 0 8m25s
kube-addon-manager-minikube 1/1 Running 0 8m13s
kube-apiserver-minikube 1/1 Running 0 8m32s
kube-controller-manager-minikube 1/1 Running 0 8m30s
kube-proxy-59npq 1/1 Running 0 9m12s
kube-scheduler-minikube 1/1 Running 0 8m21s
storage-provisioner 1/1 Running 0 9m9s
$ kubectl exec --namespace kube-system -it etcd-minikube ash
$ etcdctl cluster-health
cluster may be unhealthy: failed to list members
Error: client: etcd cluster is unavailable or misconfigured; error #0: malformed HTTP response "\x15\x03\x01\x00\x02\x02"
; error #1: dial tcp 127.0.0.1:4001: getsockopt: connection refused
error #0: malformed HTTP response "\x15\x03\x01\x00\x02\x02"
error #1: dial tcp 127.0.0.1:4001: getsockopt: connection refused
TLS が有効になっているケースでの etcd へのアクセス方法
やり方は単純で etcdctl を実行する際に、TLS で接続するのに必要な証明書や鍵( manifest に記載されているものを指定 )を渡すことでアクセスが可能となります。
まずは Pod に接続する。
$ kubectl exec --namespace kube-system -it etcd-minikube ash
証明書と鍵のペアは、どれを使っても構いませんが今回は healthcheck-client.*
を利用していきます。
$ ls -l /var/lib/minikube/certs/etcd
total 32
-rw-r--r-- 1 root root 1017 Jan 30 10:30 ca.crt
-rw------- 1 root root 1675 Jan 30 10:30 ca.key
-rw-r--r-- 1 root root 1094 Jan 30 10:30 healthcheck-client.crt
-rw------- 1 root root 1679 Jan 30 10:30 healthcheck-client.key
-rw-r--r-- 1 root root 1131 Jan 30 10:30 peer.crt
-rw------- 1 root root 1679 Jan 30 10:30 peer.key
-rw-r--r-- 1 root root 1131 Jan 30 10:30 server.crt
-rw------- 1 root root 1679 Jan 30 10:30 server.key
etcd v2 api を使用する場合は以下。
$ etcdctl \
--endpoints https://127.0.0.1:2379 \
--ca-file /var/lib/minikube/certs/etcd/ca.crt \
--key-file /var/lib/minikube/certs/etcd/healthcheck-client.key \
--cert-file /var/lib/minikube/certs/etcd/healthcheck-client.crt \
cluster-health
member 3d406acc885c8ae6 is healthy: got healthy result from https://192.168.99.108:2379
cluster is healthy
etcd v3 api を使用する場合は以下。
バージョンが異なるので渡すパラメータ名も微妙に異なることに注意してください。
$ ETCDCTL_API=3 etcdctl \
--endpoints https://127.0.0.1:2379 \
--cacert /var/lib/minikube/certs/etcd/ca.crt \
--key /var/lib/minikube/certs/etcd/healthcheck-client.key \
--cert /var/lib/minikube/certs/etcd/healthcheck-client.crt \
endpoint health
https://127.0.0.1:2379 is healthy: successfully committed proposal: took = 1.348576ms
ワンライナーで実行したいなら以下となります。
$ kubectl exec --namespace kube-system etcd-minikube -- \
etcdctl \
--endpoints https://127.0.0.1:2379 \
--ca-file /var/lib/minikube/certs/etcd/ca.crt \
--key-file /var/lib/minikube/certs/etcd/healthcheck-client.key \
--cert-file /var/lib/minikube/certs/etcd/healthcheck-client.crt \
cluster-health
member 3d406acc885c8ae6 is healthy: got healthy result from https://192.168.99.108:2379
cluster is healthy
etcd v3 に格納されたデータの確認方法( 2019-02-04 追記 )
当記事を作成後に自分がハマったことを追記という形で書きなぐっておきます。
etcd v3 内のデータを確認するために先述の方法を試みたところ、想定通りの結果を得ることができないことに気付きました。以下のコマンドで何も出力されない事象が発生…orz
$ kubectl exec --namespace kube-system etcd-minikube -- etcdctl --version
etcdctl version: 3.2.24
API version: 2
$ kubectl exec --namespace kube-system etcd-minikube -- \
etcdctl \
--endpoints https://127.0.0.1:2379 \
--ca-file /var/lib/minikube/certs/etcd/ca.crt \
--key-file /var/lib/minikube/certs/etcd/healthcheck-client.key \
--cert-file /var/lib/minikube/certs/etcd/healthcheck-client.crt \
ls --recursive
困ったので調べたところ、以下の Issue/Blog に辿り着きました。
これらの Issue/Blog を確認してみると、どうやら etcd は v2 と v3 でデータ構造が変更になったようで、v3 ではディレクトリ構造を取っていないため etcdctl ls
でデータが確認できなかったというオチでした。そもそも etcd v3 に対して etcd v2 api でアクセスするのは避けた方が良かったと反省しました…。
なのでここから etcd v3 api を使う方法をまとめていきます。
まずは Pod に接続します。
$ kubectl exec --namespace kube-system -it etcd-minikube ash
etcd v3 api を使うと格納されたデータを確認することができます。
$ ETCDCTL_API=3 etcdctl \
--endpoints https://127.0.0.1:2379 \
--cacert /var/lib/minikube/certs/etcd/ca.crt \
--key /var/lib/minikube/certs/etcd/healthcheck-client.key \
--cert /var/lib/minikube/certs/etcd/healthcheck-client.crt \
get / --prefix --keys-only
/registry/apiregistration.k8s.io/apiservices/v1.
/registry/apiregistration.k8s.io/apiservices/v1.apps
/registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io
...略
改行が煩わしければ、sed で改行を削除しましょう。
$ ETCDCTL_API=3 etcdctl \
--endpoints https://127.0.0.1:2379 \
--cacert /var/lib/minikube/certs/etcd/ca.crt \
--key /var/lib/minikube/certs/etcd/healthcheck-client.key \
--cert /var/lib/minikube/certs/etcd/healthcheck-client.crt \
get / --prefix --keys-only \
| sed '/^\s*$/d'
/registry/apiregistration.k8s.io/apiservices/v1.
/registry/apiregistration.k8s.io/apiservices/v1.apps
/registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io
...略
折角なので、適当なデータの中身を見てみると謎の文字列が出力されました。
$ ETCDCTL_API=3 etcdctl \
--endpoints https://127.0.0.1:2379 \
--cacert /var/lib/minikube/certs/etcd/ca.crt \
--key /var/lib/minikube/certs/etcd/healthcheck-client.key \
--cert /var/lib/minikube/certs/etcd/healthcheck-client.crt \
get /registry/services/specs/kube-system/kube-dns
/registry/services/specs/kube-system/kube-dns
k8s
v1Service�
�
kube-dns
kube-system"*$05915be6-26b3-11e9-bf52-080027f6af9d2����Z
k8s-apkube-dnsZ%
kubernetes.io/cluster-servicetrueZ
kubernetes.io/nameKubeDNSb
...略
etcdctl get
のアウトプットフォーマットを指定できる -w
オプションで人間が見やすい形で出力してみます。
$ ETCDCTL_API=3 etcdctl \
--endpoints https://127.0.0.1:2379 \
--cacert /var/lib/minikube/certs/etcd/ca.crt \
--key /var/lib/minikube/certs/etcd/healthcheck-client.key \
--cert /var/lib/minikube/certs/etcd/healthcheck-client.crt \
get --help \
| grep '\-w'
-w, --write-out="simple" set the output format (fields, json, protobuf, simple, table)
fields, json, protobuf, simple, table がサポートされているようなので、今回は fields でデータを出力してみると、想定通りデータを確認することができました。
$ ETCDCTL_API=3 etcdctl \
--endpoints https://127.0.0.1:2379 \
--cacert /var/lib/minikube/certs/etcd/ca.crt \
--key /var/lib/minikube/certs/etcd/healthcheck-client.key \
--cert /var/lib/minikube/certs/etcd/healthcheck-client.crt \
get -w fields /registry/services/specs/kube-system/kube-dns
"ClusterID" : 8171695754847566219
"MemberID" : 1666036459694192939
"Revision" : 221802
"RaftTerm" : 2
"Key" : "/registry/services/specs/kube-system/kube-dns"
"CreateRevision" : 193
"ModRevision" : 193
...略
地味にハマってたので原因が判明して本当に良かったです。おしまい。
さいごに
プチハマりして備忘録としてまとめたものが誰かの役に立てたら幸いです。