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のストレージは結構喰ってる