DockerでKubernetesを動かす。
何をいってるかわからないかもしれないけど、コンテナをK8sノードとして動かすものです。
下の図のような感じで、Kubernetesノードとして動作するコンテナがDockerで動く、というものです。
(なので、podがこのコンテナの中で動く、、というDocker in Docker構成の親戚みたいな感じ)

VMに比べたコンテナの特性として、作成がとても高速なので、作って捨てるサイクルが速い使い方には最適です。
以下、Quick Startに沿ってクラスタを作った作業ログなので、実際にやるときは公式ドキュメント見ること。(お約束)
8/1夜追記: ツイッターで頂いた認証情報と使い方(ストレージ・ポート関連)に関して追記。
必要な環境
- Dockerインストール済み
- 操作したいユーザーで
dockerがsudo無しで実行できる kubectlは別途インストールする
2番目のsudoについては、kind実行時にsudoを付与すれば構築(k8sコンテナの起動)はできるけど、自動で設定されるクラスタ設定($HOME/.kube/config)がrootユーザーに行われるので、設定コピーするか、 後述のkubectlの実行もsudo付けるなど、いろいろと面倒なので、kind get kubeconfigで設定情報を取得して$KUBECONFIGに設定するか、dockerをsudo無しで実行できるようにしておけばクラスタ構築時に実行したユーザーの$HOME/.kube/configを更新してくれるので楽。
[zaki@cloud-dev kind]$ sudo gpasswd -a zaki docker ユーザ zaki をグループ docker に追加
このあと1度ログアウト・ログインし直せば、sudoなしでdockerが実行できるはず。
(準備)CLIインストール
まずCLIツールkindが必要です。
バイナリをダウンロードするか、go getでインストールします。
今回はお手がるにバイナリのダウンロードで。
(Go環境がまだ無いホストだった)
[zaki@cloud-dev kind]$ curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.8.1/kind-linux-amd64
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 97 100 97 0 0 176 0 --:--:-- --:--:-- --:--:-- 176
100 629 100 629 0 0 594 0 0:00:01 0:00:01 --:--:-- 614k
100 9900k 100 9900k 0 0 2125k 0 0:00:04 0:00:04 --:--:-- 3508k
[zaki@cloud-dev kind]$ chmod +x kind
[zaki@cloud-dev kind]$ sudo mv kind /usr/local/bin/
[zaki@cloud-dev kind]$ kind --version kind version 0.8.1 [zaki@cloud-dev kind]$ kind version kind v0.8.1 go1.14.2 linux/amd64
[zaki@cloud-dev kind]$ kind --help
kind creates and manages local Kubernetes clusters using Docker container 'nodes'
Usage:
kind [command]
Available Commands:
build Build one of [node-image]
completion Output shell completion code for the specified shell (bash, zsh or fish)
create Creates one of [cluster]
delete Deletes one of [cluster]
export Exports one of [kubeconfig, logs]
get Gets one of [clusters, nodes, kubeconfig]
help Help about any command
load Loads images into nodes
version Prints the kind CLI version
Flags:
-h, --help help for kind
--loglevel string DEPRECATED: see -v instead
-q, --quiet silence all stderr output
-v, --verbosity int32 info log verbosity
--version version for kind
Use "kind [command] --help" for more information about a command.
クラスタ作成
デフォルト
設定を特に指定せずにクラスタ作成すると、最新安定板(現在はv1.18.2)のシングルノードクラスタになります。
before
[zaki@cloud-dev ~]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[zaki@cloud-dev ~]$ time kind create cluster Creating cluster "kind" ... ✓ Ensuring node image (kindest/node:v1.18.2) 🖼 ✓ Preparing nodes 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 Set kubectl context to "kind-kind" You can now use your cluster with: kubectl cluster-info --context kind-kind Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community 🙂 real 2m34.551s user 0m0.861s sys 0m0.738s [zaki@cloud-dev ~]$
できました。わずか2分半です。このスピードはすごい。
そして表示がちょっとかわいい。
$HOME/.kube/configも更新されるので、すぐにkubectlが実行可能。
[zaki@cloud-dev ~]$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* kind-kind kind-kind kind-kind
kubernetes-admin@kubernetes kubernetes kubernetes-admin
[zaki@cloud-dev ~]$ kubectl get node NAME STATUS ROLES AGE VERSION kind-control-plane NotReady master 38s v1.18.2 [zaki@cloud-dev ~]$ kubectl get pod -A NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-66bff467f8-lj9gx 0/1 Pending 0 30s kube-system coredns-66bff467f8-ncqj8 0/1 Pending 0 30s kube-system etcd-kind-control-plane 1/1 Running 0 39s kube-system kindnet-h92x5 1/1 Running 0 29s kube-system kube-apiserver-kind-control-plane 1/1 Running 0 39s kube-system kube-controller-manager-kind-control-plane 1/1 Running 0 39s kube-system kube-proxy-9g546 1/1 Running 0 29s kube-system kube-scheduler-kind-control-plane 1/1 Running 0 39s local-path-storage local-path-provisioner-bd4bb6b75-dhkxs 0/1 Pending 0 30s
クラスタ作成直後はまだCoreDNSとストレージがPending状態で、ノードもNotReadyになっています。
このときのDockerコンテナの状態はこの通り。
[zaki@cloud-dev ~]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 850b8661017a kindest/node:v1.18.2 "/usr/local/bin/entr…" About a minute ago Up About a minute 127.0.0.1:40679->6443/tcp kind-control-plane [zaki@cloud-dev ~]$
しばらく待てば、PodはすべてRunningとなり、ノードもReadyに遷移します。
[zaki@cloud-dev ~]$ kubectl get pod -A NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-66bff467f8-lj9gx 1/1 Running 0 54s kube-system coredns-66bff467f8-ncqj8 1/1 Running 0 54s kube-system etcd-kind-control-plane 1/1 Running 0 63s kube-system kindnet-h92x5 1/1 Running 0 53s kube-system kube-apiserver-kind-control-plane 1/1 Running 0 63s kube-system kube-controller-manager-kind-control-plane 1/1 Running 0 63s kube-system kube-proxy-9g546 1/1 Running 0 53s kube-system kube-scheduler-kind-control-plane 1/1 Running 0 63s local-path-storage local-path-provisioner-bd4bb6b75-dhkxs 1/1 Running 0 54s [zaki@cloud-dev ~]$ kubectl get node NAME STATUS ROLES AGE VERSION kind-control-plane Ready master 76s v1.18.2
ストレージも使用可能(名前的にhost pathですかね)
[zaki@cloud-dev ~]$ kubectl get sc NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE standard (default) rancher.io/local-path Delete WaitForFirstConsumer false 85s
ノードの情報(describe抜粋)
Addresses: InternalIP: 172.20.0.2 Hostname: kind-control-plane Capacity: cpu: 4 ephemeral-storage: 37202180Ki hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 7990132Ki pods: 110 Allocatable: cpu: 4 ephemeral-storage: 37202180Ki hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 7990132Ki pods: 110 System Info: Machine ID: 3580f7d61b0e4da9818e0b8438b770ad System UUID: e9fe840f-ee00-4ff3-9a38-4efe44b08ff5 Boot ID: 7e6869fe-fda7-4841-ae79-99860e101bef Kernel Version: 3.10.0-1062.el7.x86_64 OS Image: Ubuntu 19.10 Operating System: linux Architecture: amd64 Container Runtime Version: containerd://1.3.3-14-g449e9269 Kubelet Version: v1.18.2 Kube-Proxy Version: v1.18.2 PodCIDR: 10.244.0.0/24
マルチノードクラスタの作成
複数のコンテナを起動することで、kindでもマルチノードクラスタを作成することができます。
また、作成済みクラスタがある場合でも、追加のクラスタを作成も可能。
前述のシングルノードクラスタ"kind"がある状態で、2個目のクラスタをマルチノードで作成してみます。
マルチノードクラスタを作成するには、こちら。
YAMLの定義ファイルを作成し、そのファイルを--configで指定すればOK
検証環境で割とよく作りがちなコントロールプレーンが1台、ワーカーが2台であれば以下の通り。
kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane - role: worker - role: worker
この内容のYAMLファイルを作成し、kind create clusterを実行。
--configでYAMLファイルを指定し、あと--nameでクラスタ名も指定。(省略時は"kind"になる)
[zaki@cloud-dev kind]$ time kind create cluster --config multinode.yaml --name multicluster Creating cluster "multicluster" ... ✓ Ensuring node image (kindest/node:v1.18.2) 🖼 ✓ Preparing nodes 📦 📦 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 ✓ Joining worker nodes 🚜 Set kubectl context to "kind-multicluster" You can now use your cluster with: kubectl cluster-info --context kind-multicluster Thanks for using kind! 😊 real 2m28.784s user 0m1.553s sys 0m1.146s
"Preparing nodes"で作成されるノード分のアイコンが出るんだけど、何度見てもこれ食パンに見えるんだよね。。

.kube/configも更新されます。
[zaki@cloud-dev kind]$ kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
kind-kind kind-kind kind-kind
* kind-multicluster kind-multicluster kind-multicluster
kubernetes-admin@kubernetes kubernetes kubernetes-admin
[zaki@cloud-dev kind]$ kc get node NAME STATUS ROLES AGE VERSION multicluster-control-plane Ready master 2m57s v1.18.2 multicluster-worker Ready <none> 2m25s v1.18.2 multicluster-worker2 Ready <none> 2m23s v1.18.2 [zaki@cloud-dev kind]$ kc get pod -A NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-66bff467f8-mgj67 1/1 Running 0 2m39s kube-system coredns-66bff467f8-t8jkx 1/1 Running 0 2m39s kube-system etcd-multicluster-control-plane 1/1 Running 0 2m50s kube-system kindnet-g4qdv 1/1 Running 0 2m39s kube-system kindnet-hqz66 1/1 Running 1 2m25s kube-system kindnet-s2g9n 1/1 Running 0 2m27s kube-system kube-apiserver-multicluster-control-plane 1/1 Running 0 2m50s kube-system kube-controller-manager-multicluster-control-plane 1/1 Running 1 2m50s kube-system kube-proxy-gflzl 1/1 Running 0 2m39s kube-system kube-proxy-jml42 1/1 Running 0 2m25s kube-system kube-proxy-t8v69 1/1 Running 0 2m27s kube-system kube-scheduler-multicluster-control-plane 1/1 Running 1 2m50s local-path-storage local-path-provisioner-bd4bb6b75-wxg42 1/1 Running 0 2m39s
Kubernetesバージョンの指定
検証環境などでバージョン指定したい場合も設定のYAMLに記述します。
(未指定だと最新安定板になり、2020.08.01時点でv1.18.2になる)
バージョン番号だけ指定できれば楽そうだけど、kindでは「指定バージョン用のイメージとそのsha256ハッシュ値を指定」すればOK。
例えばv1.15(v1.15.11)の3ノードクラスタであれば以下の通り。
kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 nodes: - role: control-plane image: kindest/node:v1.15.11@sha256:6cc31f3533deb138792db2c7d1ffc36f7456a06f1db5556ad3b6927641016f50 - role: worker image: kindest/node:v1.15.11@sha256:6cc31f3533deb138792db2c7d1ffc36f7456a06f1db5556ad3b6927641016f50 - role: worker image: kindest/node:v1.15.11@sha256:6cc31f3533deb138792db2c7d1ffc36f7456a06f1db5556ad3b6927641016f50
クラスタ作成
[zaki@cloud-dev kind]$ kind create cluster --config multinode-v1.15.11.yaml --name multi-1.15 Creating cluster "multi-1.15" ... ✓ Ensuring node image (kindest/node:v1.15.11) 🖼 ✓ Preparing nodes 📦 📦 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 ✓ Joining worker nodes 🚜 Set kubectl context to "kind-multi-1.15" You can now use your cluster with: kubectl cluster-info --context kind-multi-1.15 Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community 🙂
[zaki@cloud-dev kind]$ kubectl get node NAME STATUS ROLES AGE VERSION multi-1.15-control-plane Ready master 2m12s v1.15.11 multi-1.15-worker Ready <none> 91s v1.15.11 multi-1.15-worker2 Ready <none> 92s v1.15.11
この通り、v1.15.11でデプロイされています。
指定可能なバージョン(というかイメージ)は全ての一覧表はちょっとなさそうだけど、Releaseページから該当イメージの記載を探す感じ。
もしくは、GitHubのkindest/nodeイメージのタグ一覧から探してもよさそう。
kindのクラスタ管理
クラスタ情報
kind get clustersでクラスタ一覧を見れます。
[zaki@cloud-dev kind]$ kind get clusters kind multi-1.15 multicluster
クラスタ名を指定せずにcreateすると、クラスタ名はkindになります。
2個目、3個目のクラスタを作成すれば、一覧に追加されます。
認証情報
kindで作成したクラスタの認証情報(kubeconfig)はkind get kubeconfigで取得できます。
STDOUTに出力されるので、ファイルに保存して$KUBECONFIGを設定すればkubectl使ってクラスタにアクセスできます。
[zaki@cloud-dev kind]$ sudo kind get kubeconfig
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: ......
server: https://127.0.0.1:38366
name: kind-kind
contexts:
- context:
cluster: kind-kind
user: kind-kind
name: kind-kind
current-context: kind-kind
kind: Config
preferences: {}
users:
- name: kind-kind
user:
client-certificate-data: ........
client-key-data: ........
dockerの実行にsudoが必要な場合はkindにもsudoが(内部でDocker操作するため)必要だけど、↑の認証情報を$KUBECONFIGに設定すれば、Kubernetesへのアクセスはsudoは不要です。
カレントディレクトリにkubeconfig.yaml 吐いてシェルの$KUBECONFIGにはそっちを優先させる設定させておくと楽です。
— nwiizo (@nwiizo) 2020年8月1日
$ kind get kubeconfig --name kyaml2go > kubeconfig.yaml
$ kubectl version --kubeconfig= kubeconfig.yaml
参考というかやってるそれですhttps://t.co/39snHvhAod
クラスタ削除
[zaki@cloud-dev kind]$ kind delete cluster --name multi-1.15 Deleting cluster "multi-1.15" ...
kind上のクラスタ状態、ノード用コンテナ、~/.kube/configの該当設定など諸々が削除されます。
LoadBalancer Service
デフォルトでは使用できないけど、MetalLBを導入してL2設定で簡単に使えるようになります。
MetalLBの3つのマニフェストをデプロイし、
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/namespace.yaml kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/metallb.yaml # On first install only kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"
コンテナのネットワークに合わせて、LoadBalancer Service用のIPアドレスを設定したConfigMapのマニフェストをデプロイします。
apiVersion: v1 kind: ConfigMap metadata: namespace: metallb-system name: config data: config: | address-pools: - name: default protocol: layer2 addresses: - 172.20.220.1-172.20.220.49
アドレスについては後述。
multiclusterとmulti-1.15の二つのクラスタにHTTPサーバーとLoadBalancer Serviceをデプロイし、ホストOSからcurlした例
[zaki@cloud-dev kind]$ kc get svc -n sample-app --context=kind-multicluster NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE sample-http2 LoadBalancer 10.108.20.215 172.20.220.1 80:30287/TCP 26s [zaki@cloud-dev kind]$ kc get svc -n sample-app --context=kind-multi-1.15 NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE sample-http2 LoadBalancer 10.99.250.121 172.20.220.50 80:30988/TCP 6m30s [zaki@cloud-dev kind]$ curl 172.20.220.50 <html><body><h1>It works!</h1></body></html> [zaki@cloud-dev kind]$ curl 172.20.220.1 <html><body><h1>It works!</h1></body></html>
そしてさらに"kind"クラスタ(本記事で一番最初に作ったオプション未指定のクラスタ)に何もしないCentOS7 podをデプロイし、そこから上記の2クラスタ上にあるHTTPサーバーへcurlしてみる。
[zaki@cloud-dev kind]$ kc run app-pod --image=centos:7 --context=kind-kind -- tail -f /dev/null pod/app-pod created [zaki@cloud-dev kind]$ kc get pod --context=kind-kind NAME READY STATUS RESTARTS AGE app-pod 1/1 Running 0 28s [zaki@cloud-dev kind]$ kc exec --context=kind-kind -it app-pod -- bash [root@app-pod /]# curl 172.20.220.50 <html><body><h1>It works!</h1></body></html> [root@app-pod /]# curl 172.20.220.1 <html><body><h1>It works!</h1></body></html> [root@app-pod /]#
この通り、クラスタまたいだ通信もOK (後述)
Dockerネットワーク
kindでクラスタ作ると、kind用のDockerネットワークが自動で作成される。
[zaki@cloud-dev kind]$ docker network ls NETWORK ID NAME DRIVER SCOPE f28d1c1cb87b 2nd-network bridge local bfb2b89e5a15 bridge bridge local 4a5b091ec94b host host local 11a5b9bc6a2c kind bridge local # <- これ 7a62608ea9c3 my-network bridge local 86ed4375e66a none null local
これはクラスタごとでなく、全クラスタで共通っぽい。
(何かオプション指定で別のネットワークを作成できるかもしれないけど、少なくともデフォルトでは共通)
なので、基本的に全クラスタ全ノードは同じネットワーク上に存在する構成になる。
手元の環境だとアドレス設定はこんな感じ
[zaki@cloud-dev kind]$ docker network inspect kind
[
{
"Name": "kind",
"Id": "11a5b9bc6a2c9938b54fa1fe9e84e05fa9eaa3883a0eda927cbb42c687ba7bc5",
"Created": "2020-08-01T11:10:50.769278063+09:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": true,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.20.0.0/16",
"Gateway": "172.20.0.1"
},
{
"Subnet": "fc00:f853:ccd:e793::/64"
}
]
},
[...]
MetalLBに使用するアドレスは、このサブネットに含まれる値を適当に(他と重複しないように)設定すればとりあえず動く。(16ビットマスクなので、相当なことが無い限り重複はしないはず。。)
Dockerのネットワークについてはこちらの資料も参照(ステマ)
朝活ブログのつもりが昼過ぎまで時間かかってしまった(笑)
kind使う場合の注意点
確かに、言われてみると Kind を思い通りに扱うにはある程度アーキテクチャを知っている必要がある。Kubernetes が初めてで Docker もさほど慣れてない人がいきなり触ると、extraPortMapping とか load コマンドとか、あと Node に docker コマンドがない (crictl を使う)とかで戸惑うかもしれない。 https://t.co/QkLCteYCVr
— チェシャ猫 (@y_taka_23) 2020年8月1日
kindだとホストとのポートマッピングが難しいの分かります。
— id (@ido_kara_deru) 2020年8月1日
NodePortとホストのポートの対応関係を管理しないといけないし、ポートマッピングの設定はクラスタ構築時に行う関係上、新しいポートを開けるのが大変 https://t.co/6GG6e9zCrZ
あとはDocker Imageを内部に持つので、複数クラスタ使ってるとディスクフルになりやすいです。通信量もかかるし。
— id (@ido_kara_deru) 2020年8月1日
確かにホストOSのストレージは結構喰ってる