Featured image of post kind(Kubernetes IN Docker)を試した

kind(Kubernetes IN Docker)を試した

かんたんすぎる

Kubernetesの動作確認環境として, 簡単にクラスタを用意できるkindを使ってみた.


やったことのまとめ

  • kindをMacにインストールした
  • kindKubernetesクラスタを作成, 削除した
  • kindで作ったクラスタにIngress Controllerをデプロイした

つかうもの

  • macOS Mojave 10.14
  • Docker Desktop for Mac
    • Version 2.5.0.0
    • Docker version 19.03.13
    • インストール済み
  • anyenv 1.1.1
    • インストール済み
  • goenv 2.0.0beta11
    • インストール済み
  • go version go1.15.5 darwin/amd64
    • 今回入れる
  • kind v0.9.0 go1.15.5 darwin/amd64
    • 今回入れる
  • kubectl Client Version: v1.19.3
    • インストール済み

やったこと

kindってなに

kind1DockerコンテナをNodeとして動かすことでローカル環境でKubernetesクラスタを動作させるツール.

今までローカルでの動作確認にはDocker Desktopで作れるKuberentesクラスタを使ってたんだけど,
この前Kubernetes v1.20以降はDockerNodeのコンテナランタイムとして非推奨2になるとのお知らせが出ていた.

Docker DesktopKubernetesクラスタはDockerをコンテナランタイムとして使っているので, そのうち使えなくなるかも…

# Docker Desktopで立てたKubernetesクラスタのコンテナランタイムはDocker
$ kubectl get nodes -o wide --context=docker-desktop
NAME             STATUS   ROLES    AGE   VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE         KERNEL-VERSION    CONTAINER-RUNTIME
docker-desktop   Ready    master   33d   v1.19.3   192.168.65.3   <none>        Docker Desktop   5.4.39-linuxkit   docker://19.3.13

ということで, これを機にローカルでの動作確認用Kubernetesクラスタはkindで作ることにした.
(kindではNodecontainerd3をランタイムとして使っているので問題ないらしい)

Goの更新

(Goの最新版がインストールされている環境なら飛ばしてOK)

kindのクイックスタート4によるとGoの最新版を使ってね!とのことなのでせっかくだし新しいGo(1.15)をインストールする.

$ go version
go version go1.14.6 darwin/amd64

# goenvを更新
$ anyenv install goenv
anyenv: /Users/uzimihsr/.anyenv/envs/goenv already exists
Reinstallation keeps versions directories
continue with installation? (y/N) y
...
Install goenv succeeded!
Please reload your profile (exec $SHELL -l) or open a new session.

# シェルを再起動
$ exec $SHELL -l

# インストール可能なバージョンの一覧を確認
$ goenv install -l | grep 1.15
  1.15.0
  1.15beta1
  1.15rc2
  1.15.1
  1.15.2
  1.15.3
  1.15.4
  1.15.5

# Go 1.15.5をインストール
$ goenv install 1.15.5
Downloading go1.15.5.darwin-amd64.tar.gz...
-> https://golang.org/dl/go1.15.5.darwin-amd64.tar.gz
Installing Go Darwin 64bit 1.15.5...
Installed Go Darwin 64bit 1.15.5 to /Users/uzimihsr/.anyenv/envs/goenv/versions/1.15.5

# このMacで常にGo 1.15.5を使うようにする
$ goenv global 1.15.5
$ goenv rehash

# 確認
$ goenv versions
  1.12.9
  1.13.0
  1.14.6
* 1.15.5 (set by /Users/uzimihsr/.anyenv/envs/goenv/version)

$ go version
go version go1.15.5 darwin/amd64

$ echo $GOPATH
/Users/uzimihsr/go/1.15.5

OK.

kindのインストール

次にkindをインストールする.

といってもgo getで入るのでインストール自体は1行で終わっちゃう.

クッソかんたん.

# kindのインストール
$ GO111MODULE="on" go get sigs.k8s.io/kind@v0.9.0

# $GOPATH/bin/kindに入っている
$ which kind
/Users/uzimihsr/go/1.15.5/bin/kind

# 動作確認
$ kind version
kind v0.9.0 go1.15.5 darwin/amd64

クラスタの起動

いよいよKubernetesクラスタを起動する.

…これもコマンド1発でできる.

めっちゃかんたん.

# Kubernetesクラスタ(kind-kind)の作成
$ kind create cluster
Creating cluster "kind" ...
 ✓ Ensuring node image (kindest/node:v1.19.1) 🖼
 ✓ 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

Not sure what to do next? 😅  Check out https://kind.sigs.k8s.io/docs/user/quick-start/

kubectlcontextが勝手に切り替わるので, すぐにクラスタの操作もできる.

# kubectlのcontextが自動で変更されている
$ kubectl config view --minify
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://127.0.0.1:63917
  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: REDACTED
    client-key-data: REDACTED

# うまく切り替わっていない場合もkindコマンドから有効なkubeconfigを取得可能
$ kind get kubeconfig --name kind
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: ...
    server: https://127.0.0.1:63917
  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: ...

# 動作確認
$ kubectl cluster-info --context kind-kind
Kubernetes master is running at https://127.0.0.1:63917
KubeDNS is running at https://127.0.0.1:63917/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

実際にNode用のコンテナが起動していることも確認できる.

# Nodeが1つ作成されている(コンテナランタイムがcontainerd!)
$ kubectl get nodes -o wide
NAME                 STATUS   ROLES    AGE   VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE                                     KERNEL-VERSION    CONTAINER-RUNTIME
kind-control-plane   Ready    master   19m   v1.19.1   172.19.0.2    <none>        Ubuntu Groovy Gorilla (development branch)   5.4.39-linuxkit   containerd://1.4.0

# Nodeとして動いているコンテナ
$ docker container ls
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                       NAMES
24117f8d397f        kindest/node:v1.19.1   "/usr/local/bin/entr…"   21 minutes ago      Up 20 minutes       127.0.0.1:63917->6443/tcp   kind-control-plane

ちゃんとPodも動く. すごい.

# Podも作れる
$ kubectl run nginx --image=nginx
$ kubectl get pods -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP           NODE                 NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          37s   10.244.0.5   kind-control-plane   <none>           <none>

# Podの動作確認
$ kubectl run busybox --image=busybox --restart=Never --rm -it -- wget -O- 10.244.0.5:80
Connecting to 10.244.0.5:80 (10.244.0.5:80)
writing to stdout
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
-                    100% |********************************|   612  0:00:00 ETA
written to stdout
pod "busybox" deleted

Ingressの設定

簡単なPodJobの動作確認だけならこれでも良いんだけど,
クラスタ外からの動作確認がしたい場合は追加でIngressの設定が必要なので試してみる.

まずは新たなクラスタを設定ファイル5を使って作成する.
extraPortMappingsnode-labelsが設定されていることが重要らしい.

# kindのクラスタ設定ファイルの作成
$ vim config.yaml

# 新規クラスタ(kind-ingress-enabled)の起動
$ kind create cluster --name ingress-enabled --config config.yaml
Creating cluster "ingress-enabled" ...
 ✓ Ensuring node image (kindest/node:v1.19.1) 🖼
 ✓ Preparing nodes 📦
 ✓ Writing configuration 📜
 ✓ Starting control-plane 🕹️
 ✓ Installing CNI 🔌
 ✓ Installing StorageClass 💾
Set kubectl context to "kind-ingress-enabled"
You can now use your cluster with:

kubectl cluster-info --context kind-ingress-enabled

Thanks for using kind! 😊

作ったばかりのクラスタ(kind-ingress-enabled)にIngress Controllerをデプロイする6.
今回はNGINX Ingress Controller7を使用する.

# NGINX Ingress Controllerのデプロイ
$ kubectl apply --context kind-ingress-enabled -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/kind/deploy.yaml
namespace/ingress-nginx created
serviceaccount/ingress-nginx created
configmap/ingress-nginx-controller created
clusterrole.rbac.authorization.k8s.io/ingress-nginx created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
role.rbac.authorization.k8s.io/ingress-nginx created
rolebinding.rbac.authorization.k8s.io/ingress-nginx created
service/ingress-nginx-controller-admission created
service/ingress-nginx-controller created
deployment.apps/ingress-nginx-controller created
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
serviceaccount/ingress-nginx-admission created
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
role.rbac.authorization.k8s.io/ingress-nginx-admission created
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created

# 起動確認
$ kubectl wait --context kind-ingress-enabled --namespace ingress-nginx \
  --for=condition=ready pod \
  --selector=app.kubernetes.io/component=controller \
  --timeout=90s
pod/ingress-nginx-controller-6df69bd4f7-57bkk condition met

これでこのクラスタでIngressを使う準備ができた.

最後にサンプルアプリ8を動かして, Ingressの動作を確認する.

# サンプルアプリ(Pod, Service, Ingress)のデプロイ
$ kubectl apply -f https://kind.sigs.k8s.io/examples/ingress/usage.yaml
pod/foo-app created
service/foo-service created
pod/bar-app created
service/bar-service created
Warning: networking.k8s.io/v1beta1 Ingress is deprecated in v1.19+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
ingress.networking.k8s.io/example-ingress created

# リクエストに対してそれぞれfoo, barを返すPodとそれに対応したService
$ kubectl get all
NAME          READY   STATUS    RESTARTS   AGE
pod/bar-app   1/1     Running   0          33s
pod/foo-app   1/1     Running   0          33s

NAME                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/bar-service   ClusterIP   10.96.251.3     <none>        5678/TCP   33s
service/foo-service   ClusterIP   10.96.170.161   <none>        5678/TCP   33s
service/kubernetes    ClusterIP   10.96.0.1       <none>        443/TCP    16m

# /foo, /barへのトラフィックをそれぞれのServiceに振り分けるIngress
$ kubectl get ingress
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
NAME              CLASS    HOSTS   ADDRESS     PORTS   AGE
example-ingress   <none>   *       localhost   80      16m
$ kubectl describe ingress example-ingress
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
Name:             example-ingress
Namespace:        default
Address:          localhost
Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
  Host        Path  Backends
  ----        ----  --------
  *
              /foo   foo-service:5678   10.244.0.10:5678)
              /bar   bar-service:5678   10.244.0.9:5678)
Annotations:  <none>
Events:
  Type    Reason  Age                From                      Message
  ----    ------  ----               ----                      -------
  Normal  Sync    17m (x2 over 17m)  nginx-ingress-controller  Scheduled for sync

# クラスタ外から叩いて動作確認
$ curl localhost/foo
foo
$ curl localhost/bar
bar

やったぜ.

kindで立てたクラスタでもIngressを使ってクラスタ外からアクセスすることができた.

クラスタの削除

最後にクラスタをお掃除する.

これもコマンド1発なのでめちゃくちゃ簡単.

# 削除前の状態
$ kind get clusters
ingress-enabled
kind

# Node用のコンテナが2クラスタぶん存在する
$ docker container ls
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                                                                 NAMES
d5c5aa156df9        kindest/node:v1.19.1   "/usr/local/bin/entr…"   23 hours ago        Up 23 hours         0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 127.0.0.1:57487->6443/tcp   ingress-enabled-control-plane
24117f8d397f        kindest/node:v1.19.1   "/usr/local/bin/entr…"   24 hours ago        Up 24 hours         127.0.0.1:63917->6443/tcp                                             kind-control-plane

# クラスタの削除
$ kind delete cluster --name kind
Deleting cluster "kind" ...

# 一括削除も可能
$ kind delete clusters --all
Deleted clusters: ["ingress-enabled"]

# Nodeのコンテナがすべて消えている
$ docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

# kubeconfigの設定も勝手に消えている(残っているのは別途作成したDocker DesktopとMinikubeの設定のみ)
$ kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://kubernetes.docker.internal:6443
  name: docker-desktop
- cluster:
    certificate-authority: /Users/uzimihsr/.minikube/ca.crt
    server: https://192.168.99.110:8443
  name: minikube
contexts:
- context:
    cluster: docker-desktop
    user: docker-desktop
  name: docker-desktop
- context:
    cluster: minikube
    user: minikube
  name: minikube
current-context: ""
kind: Config
preferences: {}
users:
- name: docker-desktop
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
- name: minikube
  user:
    client-certificate: /Users/uzimihsr/.minikube/client.crt
    client-key: /Users/uzimihsr/.minikube/client.key

…こんなに簡単でいいのか?

おわり

kindを使ったKubernetesクラスタの作成, Ingress Controllerのデプロイ, クラスタの削除を一通り試してみた.

Ingress対応だけちょっと面倒だけどそれもほぼコピペでできるし,
基本はコマンド1行でクラスタが簡単に作れるのがすごい. 便利すぎる.

おまけ

しもべの仕事用のイスに座るのがすきなねこ