k8s 環境を M1/M2 Mac に作る
こんにちは、プラットフォームエンジニアをやっている t.g. です。
こないだ kubenetes をきちんと触る機会に恵まれました。そのときの備忘録的にローカル Mac に k8s 環境を用意する手順を残しておきます。
kubernetes 環境は「ほぼ」クラウド上での動作と同じことがローカル環境で出来てしまうのですごいですよね。
やりたいこと
kubectl コマンドを使って、ローカルにリソースを作りたい。
helm コマンドを使って、ローカルにリソースを作りたい。
できるだけ、AWS EKS や GCP GKE と同じ手順を踏めるようにしたい。
minikube vs MicroK8s
Mac でk8s を動かすのであれば、単一ノードを簡単にセットアップできるツールが必要になります。
よく使われているものは minikube と MicroK8s でしょうか。
minikube
Win, Lin, Mac 対応
ARM 対応
VM, コンテナ、ベアメタルに対応
シングルノードのみサポート
GPU サポート
MicroK8s
Win, Lin, Mac 対応
ARM 対応
VM, コンテナ、ベアメタルに対応
マルチノードサポート(HA)
GPU サポート
ほとんど僅差で違いはないのですが、ドキュメントの読みやすさで 今回は minikube を利用しました。
minikube を Mac で使う上での注意点
docker ではなく VM で動作させる
MAC にインストール済みの docker-desktop を利用するほうが仮想マシンよりも速いです。
ただ、`docker images` コマンドを動作させるためには、仮想マシンを利用する方が楽でした。
そのため、今回は仮想マシンを MAC 上に作成し、仮想マシン上で k8s 環境を動かしていますhyperkit ではなく qemu でVMを動作
minikube をVMで動かす場合、まず hyperkit の利用ドキュメントがヒットします。
ARM 上で hyperkit は動かないため、今回はqemu でVM制御しています。
インストール
インストールは非常に簡単で、qemu -> socket_vmnet -> minikube の順番にbrew install していくだけです。
ここで minikube はデフォルトでは QEMU のnetworkに非対応なため、socket_vmnet をインストールします。
$ brew install qemu
$ brew install socket_vmnet
$ brew tap homebrew/services
$ HOMEBREW=$(which brew) && sudo ${HOMEBREW} services start socket_vmnet
$ brew install minikube
起動
初起動時は、driver, network を指定します。
また、VM にアサインするRAMもデフォルトは小さいため拡張して起動します。
さらに、MAC ターミナルで docker コマンドを打ち込んだときに、ローカルのdocker エンジンではなく、VM上のdocker を利用する指定を入れています。
# Qemu driver と socket_vmnet でMinikube 起動
# さらにRAM を増強
$ minikube start --driver qemu --network socket_vmnet --memory 8192
# 二度目以降は minikube start でOK
# minikube VM 上のdocker を使うように指定
$ eval $(minikube docker-env)
ちなみに、minikube VM 上の docker を使うように指定すると、接続先は以下のようになっていました。
$ docker context ls
NAME DESCRIPTION DOCKER ENDPOINT ERROR
default * Current DOCKER_HOST based configuration tcp://192.168.105.4:2376
desktop-linux Docker Desktop unix:///Users/user1/.docker/run/docker.sock
Warning: DOCKER_HOST environment variable overrides the active context. To use a context, either set the global --context flag, or unset DOCKER_HOST environment variable.
テスト - helm で wordpress
kubectl でも良いのですがひとっ飛びで helm を使ってみます。
まずは、helm をインストールします。
$ brew install helm
次に、bitnami/wordpress をインストールします。
必要な repo を追加 -> install -> 確認しています。
# Add bitnami repo
$ helm repo add bitnami https://charts.bitnami.com/bitnami
# Add bitnami/wordpress chart
$ helm install test-wordpress bitnami/wordpress
# pods 確認
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
test-wordpress-765f46d879-j6mlp 1/1 Running 0 2m57s
test-wordpress-mariadb-0 1/1 Running 0 2m57s
# service 確認
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 26d
test-wordpress LoadBalancer 10.102.88.72 <pending> 80:30650/TCP,443:32573/TCP 2m30s
test-wordpress-mariadb ClusterIP 10.108.201.85 <none> 3306/TCP 2m30s
ローカル MAC からブラウザで接続してみます。
minikube コマンドを利用し、出てきたURL にブラウザでアクセスが可能なことを確認します。
# LB への External-IP を外に見せる
$ minikube service test-wordpress --url
http://192.168.105.4:30650
http://192.168.105.4:32573
minikube を使うのは(EKSにはないので) ちょっと・・という場合、こちら。
kubectl port-forward を使ってポートをフォワードさせます
こちらも同様にブラウザでテスト接続ができました。
$ kubectl port-forward services/test-wordpress 33380:80
Forwarding from 127.0.0.1:33380 -> 8080
Forwarding from [::1]:33380 -> 8080
Handling connection for 33380
Handling connection for 33380
最後に bitnami/wordpress を削除しておきます。
$ helm delete test-wordpress
release "test-wordpress" uninstalled
minikube 停止
また、minikube VMも停止しておきます。
VM に貴重なRAMを取られ続けるのは大変ですので。
$ minikube stop
✋ Stopping node "minikube" ...
🛑 1 node stopped.
$ minikube status
minikube
type: Control Plane
host: Stopped
kubelet: Stopped
apiserver: Stopped
kubeconfig: Stopped
どうしてもクラウド版と異なるところ
一方で、クラウドリソースと連携しているところはどうしても読み替えが必要になります。
具体的には ingress (AWSだと ALB やNLBを使う部分)や storage class (AWS だと ECS-CSI driverを使う部分) 部分になります。
ここらあたりは「しゃあない」の精神で読み替えていくことにしました。
ファンシーなやり方を見つけたらまた共有するということで。
おまけ(もう必須) - autocompletion
なくても動きますが生産性バク上がりなツールとして、autocompletionはもう必須でした。
Linux command の autocompletion はサブコマンドを [TAB] キーで補完してくれるので、うろ覚えになりがちなものを簡単に補完してくれます。
$ kubectl <-- ここで TABキーを押すと、サブコマンドを出してくれる
-- completions --
annotate -- Update the annotations on a resource
api-resources -- Print the supported API resources on the server
api-versions -- Print the supported API versions on the server, in the form of "group/version"
apply -- Apply a configuration to a resource by file name or stdin
(snip)
さらにサブコマンドのような静的なものに限らず、pod名やservice名なども動的に補完してくれます。
同様に、pod 名など途中まで記述したものも補完してくれるので大助かりです。
$ kubectl describe -n kube-system pod <-- ここで TAB キーを押すと、起動中の pod を表示してくれる
-- completions --
coredns-6f6b679f8f-xcfd6 kube-apiserver-minikube kube-proxy-f7wcx storage-provisioner
etcd-minikube kube-controller-manager-minikube kube-scheduler-minikube
自分は以下のコマンドを ~/.zshrc ファイルに入れることで、minikube, kubectl, helm の補完を有効にしています。
Zshell 以外の場合は本家ドキュメントを参考にしてください。
# kubectl zsh autocompletion 1/2
autoload -Uz compinit
compinit
# minikube completion
source <(minikube completion zsh)
# kubectl zsh autocompletion 2/2
source <(kubectl completion zsh)
# helm autocompletion
source <(helm completion zsh)
まとめ
今回は、ローカル Mac (M1/M2) で k8s 環境を構築し、kubectl や helm が利用できるようにしました。
ローカル環境ならではの気軽さで試せると思います。
今回記事には含めませんでしたが、Istio のようなサービスメッシュもこの環境で動作します。
意外に深い使い方にも対応していますので、また面白い使い方が出ましたら共有していきたいと思います。