以下の内容はhttps://tech.guitarrapc.com/entry/2021/01/01/050203より取得しました。


WSL2 環境でのローカル Kubernetes クラスタ構築を検討した話

私はローカル環境のKubernetesにDocker Desktop for Windowsを用いています。

Minikubeやkubeadm、k3s、kind、microk8sなど各種クラスタ構成がある中で、WSL2にローカルのクラスタ環境を他で組んだ場合の違いを改めてみておくことにしました。

今回はローカルKubernetesクラスタの構成にMinikubeを用いて構築してみて、最終的にどれがいいかの所感です。

概要

Windows/WSLで共通のコードベースをWindowsにファイルを置きつつ、「WindowsとWSLでファイルマウントして」「docker-composeも使って」「Kubernetesも使いたい」という環境だとDocker Desktop (Hyper-V) + WSL1が現時点ではおすすめ。 Docker DesktopのKubernetes Clusterは、展開も極めて容易でlocal docker registryが共用され、Windows/WSLの両方からアクセスが容易なのでとてもいいです。Minikubeやkindと比べても何気に構成も奇をてらっていないのもいいです。今後のdockershimsに対する同行が気になります。

  • Docker Desktop (Hyper-V) + WSL1がストレスなく快適。WSL1 Ubuntuでのdocker volumeマウントだけ注意
  • Docker Desktop (WSL2) + WSL2は、Kubernetesは快適だがdocker-composeでファイルマウント、dockerアプリのWebレスポンスが絶望なので無理筋
  • Minikubeをdocker-driverでWSL2に建てる場合、Windowsからのアクセスはminikube tunnelでLoad Balancerをトンネルする以外は手がない、悲しい
  • Docker Desktop (Hyper-V) + WSL2はホストdockerイメージの共有ができず、大変に厳しいものがある

半年余りWSL2で組んでいましたが、Minikubeの結果も受けたうえで、Hyper-V + WSL1に戻しました。 2020年はWSL2で喜び、WSL2に泣いた。 2021年がどうなるのか... WSL2の9Pが劇的改善、vmmem/COM SurrogateのCPUあげあげも解消したら最高ですね、WSL2に戻ります。

なお、Linux 上でファイル操作が完結するなら WSL2 が圧倒的におすすめです。WSL と違って妙な制約一切ないので WSL2 最高。Windows と Linux でファイル操作をまたぐ頻度、ファイル量がほぼないなら WSL2 でいいでしょう。

はじめに

この記事の視点は利用用途に強く依存しています。私と同じ使い方をしたい方でないとまったく違う検討結果になると予想されます。

環境

  • Windows 10 Pro 20H2
  • Docker for Windows 3.0.0
  • Ubuntu 20.04 on WSL2

期待する利用方法

  • WindowsからWSLにたてたKubernetesのIngress/LoadBalancerへのアクセスを行う
  • Kubernetesより簡便に動作確認を行う環境としてdocker-composeも同様の構成で動かす

NOTE: WSL内部からの Kubernetes アクセスのしやすさは評価対象ではない。

Kubernetes のローカルクラスター構成

ローカルのKubernetes Cluster構成には選択肢がいくつかあります。 この記事ではMinikube on WSL2で見ていきますがちらっと見ておきましょう。

NOTE: おおむね今のローカルKubernetesクラスタの選択肢はなんとなくここをみていただくとして。

  • kind
  • microk8s
  • k3s
  • k3d

それぞれWSL2と組み合わせて動作させる方法があるので興味ある人はみるといいでしょう。

NOTE: kind は LoadBalancer に対応していないので、こういう用途では使いにくいのを付記しておきます。インストールは本当に簡単なのですが。

https://kind.sigs.k8s.io/docs/user/using-wsl2/

https://wsl.dev/wsl2-microk8s/

https://gist.github.com/ibuildthecloud/1b7d6940552ada6d37f54c71a89f7d00

https://wsl.dev/wsl2-k3d-arkade/

WSL2ではなく、ホストOSにKubernetesクラスターを組むのも十分に有用な方法です。 Windows/macOSで最も簡便、かつ構成の組みなおしも用意なのはDocker DesktopのKubernetesクラスターでしょう。

https://docs.docker.com/docker-for-Windows/#kubernetes

VMに建てるという意味では、MinikubeをHyper-V/Virtual Boxで入れるという手もあります。(よくやられているやつ) minikubeに限らず、WSL2で建てるのとVMで建てるのは概念が同じなので、どれもそういった方法を提供しています。

https://kubernetes.io/ja/docs/tasks/tools/install-minikube/

Minikube on WSL2 のインストール

WSL2で起動したUbuntu 20.04にMinikubeを入れて、Minikubeの自動起動をsystemdにさせることろまで構築します。 おおむねKubernetesブログに沿ってみていきましょう。

https://kubernetes.io/blog/2020/05/21/wsl-docker-kubernetes-on-the-Windows-desktop/

記事ではDocker DesktopのWSL2 Integrationを有効にしていますが、dockerのファイルマウントの遅さを排除するためHyper-Vのまま動作させます。

Hyper-Vバックエンドの場合、WSL2 Ubuntuにはdocker /docker-compose / kubectlは入らないので、Ubuntuには自分で入れましょう。

systemd の構成

Minikubeは--vm-driver=noneの場合systemdが必要ですが、dockerの場合不要です。

--vm-driver=dockerでも、WSL2ログインごとにminikube起動をやっていられない + SysV Initを用意するのもつらいという場合、WSL2でSystemdを動かしてminikube.serviceを作って調整してもいいでしょう。

NOTE: もちろん、.bashrc で適当に開始させてもいいでしょう。

systemdをWSL2に入れる方法は、Kubernetesのminikubeブログやいい記事が紹介しています。

https://qiita.com/matarillo/items/f036a9561a4839275e5f

これでsystemdの起動が確認できます。

systemdで自動起動するためのminikube.serviceは適当にこんな感じで。

[Unit]
Description=Runs minikube on startup
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/bin/minikube start --vm-driver=docker --addons ingress --kubernetes-version v1.18.0
ExecStop=/usr/local/bin/minikube stop
User={{ ansible_user_id }}
Group={{ ansible_user_id }}

[Install]
WantedBy=multi-user.target

systemdを構成する場合、genieではなくenter-systemd-namespaceスクリプトの方がカスタマイズしやすいのでおすすめです。 例えば、systemdにするとWindowsからのWSL2ログイン時にbash loginをするため/mnt/Windowsパスが維持されず~/になってしまいますが、enter-systemd-namespaceでbash login前に今のパスを保持しておいて、ログイン後に自動的にcdするなどの対処が取れます。

minikube の動作確認

minikubeをdocker driverで起動させてみます。

minikube start --vm-driver=docker

minikubeの起動が確認できます。

$ minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
timeToStop: Nonexistent
$ kubectl get node
NAME       STATUS   ROLES    AGE   VERSION
minikube   Ready    master   21h   v1.18.0

$ k get pod -A
NAMESPACE     NAME                                        READY   STATUS      RESTARTS   AGE
kube-system   coredns-66bff467f8-tmqw6                    1/1     Running     1          21h
kube-system   etcd-minikube                               1/1     Running     1          21h
kube-system   ingress-nginx-admission-create-49j8v        0/1     Completed   0          21h
kube-system   ingress-nginx-admission-patch-cwrkz         0/1     Completed   0          21h
kube-system   ingress-nginx-controller-6f5f4f5cfc-9hw8f   1/1     Running     1          21h
kube-system   kube-apiserver-minikube                     1/1     Running     1          21h
kube-system   kube-controller-manager-minikube            1/1     Running     1          21h
kube-system   kube-proxy-72482                            1/1     Running     1          21h
kube-system   kube-scheduler-minikube                     1/1     Running     1          21h
kube-system   storage-provisioner                         1/1     Running     3          21h

minikube on WSL2 の面倒な点

minikubeを--vm-driver=docker-driverで起動した場合に面倒なのは2点です。

  1. minikubeのdocker registryにpushしないといけない
  2. ingressにWindowsホストからアクセスできない

minikubeをdocker driverで起動した場合、minikubeのdocker registryはUbuntuとは別に構成されます。 そのため、bashログイン時にeval $(minikube docker-env)をする必要があるので注意です。

minikubeをdocker driverで起動した場合、ingressのAddressはdockerドライバーで起動したminikube ipのアドレスになります。 localhostではないため、WindowsからWSL2への直接のアクセスはできません。 この場合、Service: LoadBalancerにしておくとminikube tunnelでlocalhostにトンネルされるのでWindowsからアクセス可能になります。

余談: なぜローカル Kubernetes 環境を必要とするのか

開発環境、開発ブランチ環境に対応するKubernetesがあるとき、なぜローカルのKubernetesは必要なのかという話があります。

私はKubernetesの管理者であり、Devでもあるので、ローカル開発は何にもまして最速でプロダクトに期待する動作を確認する必須の場といえます。 ローカル開発はPoCであり、実際の運用環境とくらべて構成要素はミニマムだったりクラウド依存のなさなど差異もあるでしょう。 しかし、想定するアプリ動作を満たす場としては最適であり、常にメンテされていくべきと考えています。 また、自分のみに閉じているという意味でもローカル開発環境は整備する価値があります。 Kubernetesに各種Operator/Controllerを入れて動作させる場合は、ローカルKubernetesがない状況で、Devなどに展開するのは開発効率の面からみて避けたいものです。

ただしこれらの前提として、実際に動作する環境とかけ離れた構成になることは望ましくありません。 例えば、ローカルKubernetesではIngressに何かしらの制約がありLoad Balancerにする、といった状況は絶対的に避けたいものです。 運用環境とかけ離れ、期待する動作環境をローカルに作れず、メンテもできない場合、そのローカルKubernetes環境はむしろ害悪になるので避けたいものがあります。

別の視点としてKubernetesの管理者という前提がない場合、ローカルKubernetesである必然性はありません。 例えば、通常のアプリコードを書いて動かすだけにおいては、Kubernetesだろうとどこででもいいからコードがデプロイされて動作すればいいです。 というかKubernetesとか知りたくないし、ぐらいでもいいでしょう。

Kubernetesの管理をしつつDevもする身としては、ローカルKubernetes環境はほしいものですが、メンテできるか、その構成は今のスタンダードとずれていないかが気になります。Minikubeはそういう意味ではスタンダードですが、悩ましい側面も多いですね。

kind on WSL2 はどうなのか

インストールはスムーズです。minikubeより楽。 ただし、kindはLoad Balancerに対応していないので使いにくさは否めません。

おまけ: WSL環境の選定

WSLには、WSL1とWSL2があり、この2つはホストOSのWindowsとの相互利用で結構な違いがあります。 KubernetesをWSLに建てる場合、これは大きな違いになります。

https://docs.microsoft.com/ja-jp/Windows/wsl/compare-versions

WSL2 なのか WSL1 なのか

選択肢はおおむね2択ではないでしょうか。

  • WSL2のみで利用し純粋にLinuxとほぼ同様に扱いたい、WSL2とWindowsは速度面などで気にならない場合、WSL2 + Docker on WSL2がいいでしょう
  • WindowsとWSL2のファイルマウント1 の9Pに由来する遅さ、Docker on WSL2のパフォーマンス制約、ホストOSのCPU/メモリ負荷が気になり許容できない場合、WSL1がいいでしょう

別の構成として、DockerのみHyper-Vで動かし、WSL2でUbuntuを動かすことも考えられます。 この場合、docker利用時のファイルマウントの遅さは生じず、WSL2のUbuntuはLinux同様に扱えますがホストWindowsのDockerは共有できません。(tls:localhost:2375がだめなんですよね)

WSL2 でないといけないのか WSL1 ではだめなのか

Windows/WSLの相互利用時のパフォーマンス、docker volumeのマウントの取捨選択になります。 私の利用ケースはWindowsとWSLの相互利用がメインなので、WSL2よりもWSL1のほうが望ましいとなります。

ファイルマウント、ホストCPU負荷の両面でWSL1は優れています。 一方で、純粋なLinuxとして使うには細かな差異とdocker動作の制約が大きなハンデになります。(エラーもでないので罠に感じやすい)

WSL2

ほとんどのケースで問題ないことが多いでしょうが、パフォーマンス制約は軽く見るのを避けるほうがいいでしょう。

NOTE: Zen3 5900X + PCIE 4.0 NVMe でCPU負荷は無視できます。しかしWindowsホストファイルのマウントはどうしようもなく遅く回避策が現状ありません。

回避不可能なWindowsホストとのファイルボリュームマウント制約、そしてCPU負荷 (vmmem / COM Surrogate) があることに注意です。

NOTE: .wslconfing でメモリ、CPUの上昇をある程度止められますが十分に負荷が大きいので厄介です。

ただ、WSL2 UbuntuとDocker WSL2でDocker registryも共有され、docker/kubectlも入ってくるので非常に使いやすいです。

WSL1

WSLでdocker volumeマウントできない制約があります。また、単純なWSL内部のファイルアクセスもWSL2に比べて格段に遅いので注意がいります。

NOTE: docker実行はWindows でdocker run している限りは起こらないので回避策はあります。

WSL2と違って、Windowsホストに対するパフォーマンスペナルティがなく、WSLでの動作制約があるだけなのはバランスがいい選択になります。

WSL Ubuntuからdockerを使うには、Docker Desktopでtls:localhost:2375を開放して、WSLのDOCKER_HOSTにします。 これでWindowsのdocker registryがWSL Ubuntuでも共有されるので、使い勝手の面で非常に楽になります。

おまけ: Kubernetes のインストール先の検討

ホストOSのWindowsでKubernetesクラスターを組んだ場合、Windows/WSLの両方からアクセスしても問題ありません。 WSL2でKubernetesを組んだ場合、WindowsからのアクセスにはWSL2のlocalhostでアクセスできる必要があります。

こういう意味では、Windowsホストにサクッとクラスターを組んで、いつでも爆破できる状況を作るのが最も使いやすいでしょう。

Docker Desktop for Windowsなら、Settings画面からKubernetes Clusterのファクトリーリセット、再構成も用意なのでいいでしょう。


  1. それに伴うネットワーク速度の遅さも発生する



以上の内容はhttps://tech.guitarrapc.com/entry/2021/01/01/050203より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14