背景とか目的
- 最近Kubernetesを使って、色々試したいことが多い。
- 一発コマンドでマルチクラスタを作って、きれいさっぱりさよならしたい。
- 物理マシン数台でclusterを構築したり、管理するのがめんどくさい。
- 自分の開発マシンだけでマルチノードクラスタを立ち上げて、アプリの動作を確認したい。
Kindとは
K
ubernetes IN
D
ocker らしいです。少しだけ概要にも触れておきます。
Kubernetesのノードとしてdockerコンテナを起動しています。dockerコンテナ一つがKubernetesのノードとして割り当てられます。
dockerコンテナの中(仮想的なノードの中)ではコンテナランタイム(containerd)が起動しています。このコンテナランタイムがKubernetesのコンポーネントやアプリケーションをコンテナとして管理しています。dockerコンテナの中ではkubeletが起動してコンテナインスタンスをノードと勘違いさせています。
dockerコンテナ内でコンテナランタイムとkubeletが動作することで、コンテナの中でコンテナ制御を行えるようにしています。
ホストからのコマンド通信(例えばkubectl)はport mappingされて最終的にはdockerコンテナ内のapi-serverに通信するようにしています。
環境と事前準備
Ubuntu 20.04で動作確認しています。
まず、Dockerをインストールします。(docker.ceでもOK)
> sudo apt install docker.io
dockerがちゃんとインストールされたか確認します。
> docker version
Client:
Version: 20.10.12
API version: 1.41
Go version: go1.16.2
Git commit: 20.10.12-0ubuntu2~20.04.1
Built: Wed Apr 6 02:14:38 2022
OS/Arch: linux/amd64
Context: default
Experimental: true
Server:
Engine:
Version: 20.10.12
API version: 1.41 (minimum version 1.12)
Go version: go1.16.2
Git commit: 20.10.12-0ubuntu2~20.04.1
Built: Thu Feb 10 15:03:35 2022
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.5.9-0ubuntu1~20.04.1
GitCommit:
runc:
Version: 1.1.0-0ubuntu1~20.04.1
GitCommit:
docker-init:
Version: 0.19.0
GitCommit:
次にKubernetesをインストールします。
> sudo apt install apt-transport-https curl
> curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add
> sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main"
> sudo apt install kubeadm kubelet kubectl kubernetes-cni
> kubectl version --client=true --short
Flag --short has been deprecated, and will be removed in the future. The --short output will become the default.
Client Version: v1.24.0
Kustomize Version: v4.5.4
Kindでクラスタ構築
Kindをインストール
> go install sigs.k8s.io/kind@v0.12.0
> kind version
kind v0.12.0 go1.18.1 linux/amd64
シングルノードクラスタ作成と削除
> kind create cluster
> kubectl cluster-info --context kind-kind
Kubernetes control plane is running at https://127.0.0.1:39857
CoreDNS is running at https://127.0.0.1:39857/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
これだけです。これでシングルノードのクラスタが構築されています。
> kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
kind-control-plane Ready control-plane,master 72s v1.23.4 172.18.0.2 <none> Ubuntu 21.10 5.13.0-40-generic containerd://1.5.10
KindはKubernetesを起動するときにconfigを${HOME}/.kube/config
に追加し、ホストのポート6443をコンテナとして起動したapi-serverへマッピングしているため、ホストマシンからkubectl
にてクラスタを管理することも可能です。
> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
10e90347f982 kindest/node:v1.23.4 "/usr/local/bin/entr…" 55 seconds ago Up 52 seconds 127.0.0.1:39857->6443/tcp kind-control-plane
kind-control-plane
がKubernetesのcontrol-planeとして起動していることがわかります。
kind delete cluster
Deleting cluster "kind" ...
削除するときはこれだけです。
ただ、これだとシングルノードのマスターだけなのでさみしい。。。
なのでマルチノードクラスタをcontainerで作ってみます。(あくまで物理マシンは一台です。)
マルチノードクラスタ
以下のyamlをkindコマンドに渡して、マルチノードクラスタを作成します。
> cat multi-node.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
> kind create cluster --config=multi-node.yaml
Creating cluster "kind" ...
✓ Ensuring node image (kindest/node:v1.23.4) 🖼
✓ Preparing nodes 📦 📦 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
✓ Joining worker nodes 🚜
Set kubectl context to "kind-kind"
You can now use your cluster with:
kubectl cluster-info --context kind-kind
Not sure what to do next? 😅 Check out https://kind.sigs.k8s.io/docs/user/quick-start/
すると、Kubernetesのノードとして複数のdockerコンテナが起動して、マルチノードクラスタを構築できます。
> kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
kind-control-plane Ready control-plane,master 59s v1.23.4 172.18.0.3 <none> Ubuntu 21.10 5.13.0-40-generic containerd://1.5.10
kind-worker Ready <none> 34s v1.23.4 172.18.0.4 <none> Ubuntu 21.10 5.13.0-40-generic containerd://1.5.10
kind-worker2 Ready <none> 34s v1.23.4 172.18.0.2 <none> Ubuntu 21.10 5.13.0-40-generic containerd://1.5.10
> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
026f6377ccb8 kindest/node:v1.23.4 "/usr/local/bin/entr…" About a minute ago Up About a minute kind-worker2
cbf0ef62fc77 kindest/node:v1.23.4 "/usr/local/bin/entr…" About a minute ago Up About a minute kind-worker
84c9aab0833c kindest/node:v1.23.4 "/usr/local/bin/entr…" About a minute ago Up About a minute 127.0.0.1:41081->6443/tcp kind-control-plane
次にアプリ(Pods)をデプロイしてみます。
Kindに渡すyamlを少し修正して、ホストポート30070からWebにつなげるようにしておきます。
> cat multi-node.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraPortMappings:
- containerPort: 30080
hostPort: 30070
- role: worker
- role: worker
> kind create cluster --config=multi-node.yaml
...
KubernetesのServiceとしてポート30080を設定し、Podのポート80とマッピングしておきます。アプリケーションはDockerHubにあるnginxを利用します。
> cat app-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: web-nginx
name: web-nginx
spec:
replicas: 3
selector:
matchLabels:
app: web-nginx
template:
metadata:
labels:
app: web-nginx
spec:
containers:
- image: nginx
name: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: web-nginx
spec:
selector:
app: web-nginx
type: NodePort
ports:
- port: 80
nodePort: 30080
> kubectl create -f app-nginx.yaml
すると、kubectlでPod/Serviceが以下のように起動できたことが確認できます。
> kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
web-nginx-585955c9c8-hkrk4 1/1 Running 0 73s 10.244.1.3 kind-worker2 <none> <none>
web-nginx-585955c9c8-jrccb 1/1 Running 0 73s 10.244.1.2 kind-worker2 <none> <none>
web-nginx-585955c9c8-kz49v 1/1 Running 0 73s 10.244.2.2 kind-worker <none> <none>
> kubectl get services -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5m46s <none>
web-nginx NodePort 10.96.10.179 <none> 80:30080/TCP 110s app=web-nginx
port mappingは30070(host) --- 30080(k8s service) --- 80(pod)になっているので、http:/ホストマシンのIP/:30070/
にブラウザでアクセスすると以下が見えます。
これ以降は補足情報になりますが、
> docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
05fca9ee8e9e kindest/node:v1.23.4 "/usr/local/bin/entr…" 4 minutes ago Up 4 minutes 0.0.0.0:30072->30080/tcp kind-worker2
8abd9d1e1926 kindest/node:v1.23.4 "/usr/local/bin/entr…" 4 minutes ago Up 4 minutes 127.0.0.1:40971->6443/tcp, 0.0.0.0:30070->30080/tcp kind-control-plane
b557b30529b4 kindest/node:v1.23.4 "/usr/local/bin/entr…" 4 minutes ago Up 4 minutes 0.0.0.0:30071->30080/tcp kind-worker
なぜアプリケーションpodsのコンテナがホストから見えないかというと、dockerコンテナの中のcontainerdで管理されているからです。例えば、上記のデプロイメントの場合、アプリケーションPodは、kind-worker もしくは kind-worker2 のノードで起動していることがわかります。
一旦dockerコマンド(docker exec -it [container id] /bin/bash
とか)を利用して、ホストマシンからkind-workerに乗り込みます。(これは特定のノードの中にログインした状態と同じです。)
dockerコンテナの中にはdockerはいないので、ctr
コマンドを使ってcontainerd
が管理するコンテナをチェックします。
> ctr -n k8s.io container list
CONTAINER IMAGE RUNTIME
32c712d22a7f60bec95c4d2d51c9d0057222fbd4d032a5f351bea7675188ef84 k8s.gcr.io/pause:3.6 io.containerd.runc.v2
40a7ef598849e6709d11e0c6ae8bda1ac3047c0ee9f6b3e8cdfc7dcdcbac1cd8 k8s.gcr.io/kube-proxy:v1.23.4 io.containerd.runc.v2
93496727074f147a1446d91d887d3e64a7d55710cec583e46de861fb84840628 k8s.gcr.io/pause:3.6 io.containerd.runc.v2
943d7c26a01f3aef786c3f26e731a52362c6ec8844283d1a6bb83081c25c1a89 docker.io/kindest/kindnetd:v20211122-a2c10462 io.containerd.runc.v2
9a157042a8068975b92fc8091b73e5180936265612bd73a86a3905bb40ba857a k8s.gcr.io/pause:3.6 io.containerd.runc.v2
ea2c62477b749ef208f11c108a1396bbebca64c00398b8a5a169555af157ebc4 docker.io/library/nginx:latest io.containerd.runc.v2
上記の通り、Kubenretesのコンポーネント群とアプリケーションPod(nginx)が起動していることがわかります。
namespaceがk8s.gcr.ioになっていますが、調べ方はこちらを参照ください
最後にすべての過去を消し去ります。
> kind delete cluster
Deleting cluster "kind" ...