KubernetesをVirtualboxにVagrantとKubeadmでインストールしてみよう #kubernetes #kubeadm #vagrant #virtualbox
この記事は1年以上前に投稿されました。情報が古い可能性がありますので、ご注意ください。
「Kubernetesの勉強のためにインストールから始めてみよう! ……と思ったけれど、設定すべきIPアドレスがたくさん出てきてよくわからない……。Kubernetesを勉強したいからインストールするのに、インストールする際に知っておかないといけないKubernetesの知識が多すぎる……」と、いきなり手詰まりになってしまう方も多いかと思います。
ローカルで手軽にKubernetesを構築できるminikubeやkindなどのツールが存在するので、まずはそちらでKubernetesの勉強をするのもよいでしょう。
本稿では、kubeadmとVagrantを使ってVirtualbox上にKubernetesをインストールする際に気をつけるべき点をまとめてみたいと思います。
前提条件
ホストマシンにVagrantとVirtualboxがインストール済みであり、IPアドレスは 192.168.24.201 であるとします。IPアドレスは必要に応じて適宜読み替えてください。
デフォルトで利用されるIPアドレス範囲
まず、Vagrant + Virtualbox + Kubernetesのデフォルトで利用されるIPアドレス範囲を見ておきます。
- 10.0.2.15/32
- 172.17.0.0/16
- 10.96.0.0/12
- 192.168.0.0/16 (注:Calicoの場合、詳細後述)
これらがホストマシンのIPアドレスにかぶっていると理解の妨げになる上に、何か動作がおかしくなった場合の原因特定が大変になるため、可能な限り変更したいところです。前提条件の通り、本稿におけるホストマシンのIPアドレスは 192.168.24.201 で 192.168.0.0/16 とかぶっているので、その他のものも含めて、以降で各IPアドレス範囲の詳細と変更方法を見ていきましょう。
10.0.2.15/32
10.0.2.15/32 は、Vagrant + Virtualbox でゲストOSのプライマリネットワークインターフェイス(例えばeth0)に付与される、内部ネットワーク用のIPアドレスです。末尾の 15 は変えられないようですが、ネットワーク部 10.0.2.0/24 は変更できます: Configuring the Address of a NAT Network Interface, VBoxManage Customizations
例えば 10.0.3.15/32 に変更するには Vagrantfile で次のようにします。
Vagrant.configure(2) do |config| # 省略 config.vm.provider "virtualbox" do |v| v.customize ["modifyvm", :id, "--natnet1", "10.0.3/24"] end # 省略 end
なお、この内部ネットワーク用のIPアドレスはプライマリネットワークインターフェイスに必ず付与されます。そのため、プライマリネットワークインターフェイスを自動検知して利用するソフトウェアは動作不良を起こすので、利用するネットワークインターフェイスを手動設定する必要があります。具体例は後述します。
172.17.0.0/16
172.17.0.0/16 はDockerのデフォルトブリッジネットワークで使われるIPアドレス範囲です。もう少し具体的に言うと、ネットワークインターフェイスdocker0のIPアドレス(例えば 172.17.0.1/16)は、このIPアドレス範囲から割り当てられます。
$ ip a show docker0 4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:04:c5:cf:b8 brd ff:ff:ff:ff:ff:ff inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0 valid_lft forever preferred_lft forever
docker0のIPアドレスを変更するには、 /etc/docker/daemon.json にて bip キーでIPアドレスを指定し、Dockerを再起動します: Configure the default bridge network
例えば 172.20.0.1/16 に変更するには /etc/docker/daemon.json で次のようにします。
{ "bip": "172.20.0.1/16" }
$ ip a show docker0 4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link/ether 02:42:04:c5:cf:b8 brd ff:ff:ff:ff:ff:ff inet 172.20.0.1/16 brd 172.20.255.255 scope global docker0 valid_lft forever preferred_lft forever
余談ですが、bip キーで変更できるのはデフォルトブリッジネットワーク(docker0)のみで、追加ブリッジネットワークは依然として 172.17.0.0/16 から割り当てられることに注意が必要です。
$ for i in $(seq 1 1 5); do docker network create network-$i; done $ for i in $(docker network ls --filter driver=bridge -q); do docker network inspect --format '{{.Name}} : {{range .IPAM.Config}}{{.Subnet}}{{end}}' $i; done bridge : 172.20.0.0/16 network-1 : 172.17.0.0/16 network-2 : 172.18.0.0/16 network-3 : 172.19.0.0/16 network-4 : 172.21.0.0/16 network-5 : 172.22.0.0/16
これを避けるには bip キーの代わりに default-address-pools キーを使います。base はブリッジネットワークに割り当てられるIPアドレス範囲で、size は base から切り出されるサブネットマスクになります。例えば、
{ "default-address-pools": [ { "base": "172.20.0.0/16", "size": 24 } ] }
とすると、172.20.0.0/16 すなわち 172.20.0.1 〜 172.20.255.254 がブリッジネットワークに割り当てられるIPアドレス範囲で、
- 172.20.0.0/24
- 172.20.1.0/24
- 172.20.2.0/24
- (中略)
- 172.20.253.0/24
- 172.20.254.0/24
- 172.20.255.0/24
が各ブリッジネットワーク(最初の 172.20.0.0/24 はdocker0)に割り当てられることになります。
$ for i in $(seq 1 1 5); do docker network create network-$i; done $ for i in $(docker network ls --filter driver=bridge -q); do docker network inspect --format '{{.Name}} : {{range .IPAM.Config}}{{.Subnet}}{{end}}' $i; done bridge : 172.20.0.0/24 network-1 : 172.20.1.0/24 network-2 : 172.20.2.0/24 network-3 : 172.20.3.0/24 network-4 : 172.20.4.0/24 network-5 : 172.20.5.0/24
参考: default-address-pools, docker0
10.96.0.0/12
10.96.0.0/12は、kubeadmのデフォルト設定でKubernetesをインストールした場合にServiceという仕組みに用いられるIPアドレス範囲です。
Vagrant + Virtualbox でゲストOSのプライマリネットワークインターフェイス(例えばeth0)に付与される 10.0.2.15/32 と若干まぎらわしいため、変更しておくと理解しやすくなると思います。
Serviceに用いるIPアドレス範囲を変更するには kubeadm initの --service-cidr オプションを使用します。
$ kubeadm init --service-cidr 203.0.113.0/24
192.168.0.0/16
192.168.0.0/16は、 Pod間の通信 に Calico を用いる場合にデフォルトで使用されるIPアドレス範囲です。
前述の通り、本稿のホストマシンのIPアドレスである 192.168.24.201 を含んでいるため変更しましょう。
Calicoが使用するIPアドレス範囲を変更するには kubeadm initの --pod-network-cidr オプションを使用し、
$ kubeadm init --pod-network-cidr 198.51.100.0/24
さらにCalicoのインストールに利用するYAMLファイルを変更します。これは後述します。
実際のインストール
以上を踏まえて、実際にKubernetesのインストールを行ってみます。
ゲストOSの準備
次のVagrantfileで、ゲストOSのプライマリネットワークインターフェイスのIPアドレスを 10.0.3.15/32 に設定しています(デフォルトは 10.0.2.15/32)。
また、ゲストOSのIPアドレス範囲は、ホストマシンのIPアドレス 192.168.24.201 とややまぎらわしいですが大きな問題となることは少ないため、192.168.123.0/24 としておきます。
Vagrant.configure("2") do |config| config.vm.box = "ubuntu/bionic64" config.vm.box_check_update = false config.vm.define "master" do |cf| cf.vm.hostname = "master" cf.vm.network "private_network", ip: "192.168.123.101" cf.vm.provider "virtualbox" do |vb| vb.memory = 4096 vb.customize ["modifyvm", :id, "--natnet1", "10.0.3/24"] end end config.vm.define "worker" do |cf| cf.vm.hostname = "worker" cf.vm.network "private_network", ip: "192.168.123.102" cf.vm.provider "virtualbox" do |vb| vb.memory = 4096 vb.customize ["modifyvm", :id, "--natnet1", "10.0.3/24"] end end end
master と worker の両ゲストOSの /etc/hosts で、両ホストのIPアドレスが 127.0.2.1 となっているところを Vagrantfile で設定したそれぞれのIPアドレスに変更し、お互いに名前解決できるように追記もしておきます(※一部抜粋)。
192.168.123.101 master 192.168.123.102 worker
Dockerのインストールと設定
CRIのインストールに従い、Dockerをインストールします。
/etc/docker/daemon.json の設定には default-address-pools キーの設定を追加し、docker0のIPアドレスを 172.20.0.0/16 に変更します(デフォルトは 172.17.0.0/16)。
{ "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m" }, "storage-driver": "overlay2", "default-address-pools": [ { "base": "172.20.0.0/16", "size": 24 } ] }
kubeadmによるKubernetesのインストール
kubeadmを使ってクラスターを構築するに従い、kubeadmでKubernetesをインストールします。
まずはkubeadmのインストールに従い、masterゲストとworkerゲストの両方に kubelet, kubeadm, kubectl をインストールします。
次にkubeadmを使用したクラスターの作成に従い、masterゲストで kubadm init を実行しますが、これには前述の通りオプションが必要になります。
Serviceに用いるIPアドレス範囲は203.0.113.0/24(デフォルトは10.96.0.0/12)とし、Pod間通信のために用いるIPアドレス範囲は198.51.100.0/24(デフォルトは192.168.0.0/16)とします。また、プライマリネットワークインターフェイスを自動検知しないよう --apiserver-advertise-address オプションでmasterゲストのIPアドレス 192.168.123.101 を指定します。
$ sudo kubeadm init --service-cidr 203.0.113.0/24 --pod-network-cidr 198.51.100.0/24 --apiserver-advertise-address 192.168.123.101
正常に完了すれば、次のコマンド群が表示されるので、これをコピー&ペーストしてmasterゲストで実行します。
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
さらにこのコマンド群の後に kubeadm join というコマンドが表示されるので、これをコピー&ペーストしてworkerゲストで実行します。次は本稿での例で、細かい文字列は異なります。
$ sudo kubeadm join 192.168.123.101:6443 --token wq7k60.igq3l1qr7ehxw7yi \ --discovery-token-ca-cert-hash sha256:ce72112c0048e7e00a9b2a7857fba65ce3a3aeeaf746e364ed1c8fa01aa449cd
さらに kubelet がプライマリネットワークインターフェイスを自動検知しないよう手動で設定します。具体的には /etc/default/kubelet ファイルを作成し、master であれば次を、
KUBELET_EXTRA_ARGS=--node-ip=192.168.123.101
worker であれば次を、
KUBELET_EXTRA_ARGS=--node-ip=192.168.123.102
それぞれ記載し、
$ sudo systemctl daemon-reload $ sudo systemctl restart kubelet
を実行して kubelet を再起動して設定を読み込ませます。psコマンドでkubeletプロセスを確認し、 --node-ip=192.168.123.10X オプションが付与されていれば成功です。
masterゲストで kubelet get nodes コマンドを実行し、次のようになっていればひとまず kubeadm による Kubernetes のインストールは一段落です。
$ kubectl get nodes NAME STATUS ROLES AGE VERSION master NotReady control-plane,master 12m v1.22.0 worker NotReady 7m2s v1.22.0
Calicoのインストール
Install Calicoに従い、Pod間通信のためのCalicoをインストールします。すべてmasterゲストで実施します。
まず1つ目のYAMLファイルはそのまま適用します。
$ kubectl create -f https://docs.projectcalico.org/manifests/tigera-operator.yaml
2つ目のYAMLには、変更すべきIPアドレス範囲の記載があるため、そのまま適用してはいけません。YAMLファイルをダウンロードし、デフォルトのIPアドレス範囲192.168.0.0/16を198.51.100.0/24に変更します。
$ wget https://docs.projectcalico.org/manifests/custom-resources.yaml $ cp custom-resources.yaml custom-resources.yaml.orig $ vi custom-resources.yaml $ diff -u custom-resources.yaml.orig custom-resources.yaml --- custom-resources.yaml.orig 2021-08-10 07:22:52.987585977 +0000 +++ custom-resources.yaml 2021-08-10 07:23:44.471585977 +0000 @@ -10,7 +10,7 @@ # Note: The ipPools section cannot be modified post-install. ipPools: - blockSize: 26 - cidr: 192.168.0.0/16 + cidr: 198.51.100.0/24 encapsulation: VXLANCrossSubnet natOutgoing: Enabled nodeSelector: all()
変更したYAMLファイルを適用します。
$ kubectl create -f custom-resources.yaml
少し待ち、次のようにSTATUSがすべてRunningになれば成功です。
$ kubectl get pods -n calico-system NAME READY STATUS RESTARTS AGE calico-kube-controllers-585ff4589d-tvtnw 1/1 Running 0 15m calico-node-g6jxs 1/1 Running 0 15m calico-node-vtqwg 1/1 Running 0 15m calico-typha-57d65ff8f5-4rbnm 1/1 Running 0 15m calico-typha-57d65ff8f5-k75r8 1/1 Running 0 15m
またこちらのSTATUSもすべてReadyとなっていることも確認しましょう。
$ kubectl get nodes NAME STATUS ROLES AGE VERSION master Ready control-plane,master 45m v1.22.0 worker Ready 39m v1.22.0
動作テスト
masterゲスト上でもワークロードを実行できるように次を実行します。
$ kubectl taint nodes --all node-role.kubernetes.io/master- node/master untainted error: taint "node-role.kubernetes.io/master" not found
エラーのように見えますが、1行目に「node/master untainted」と出ていれば問題ありません。
デモアプリケーションとしてSock Shopをデプロイします。
$ kubectl create -f https://raw.githubusercontent.com/microservices-demo/microservices-demo/master/deploy/kubernetes/complete-demo.yaml
しばらく待ち、次を実行してSTATUSがすべてRunningになっていたら成功です。
$ kubectl -n sock-shop get pods NAME READY STATUS RESTARTS AGE carts-b4d4ffb5c-7h2hq 1/1 Running 0 20m carts-db-6c6c68b747-27bjb 1/1 Running 0 20m catalogue-759cc6b86-gq9rc 1/1 Running 0 20m catalogue-db-96f6f6b4c-qd7df 1/1 Running 0 20m front-end-5c89db9f57-pf5mn 1/1 Running 0 20m orders-7664c64d75-hqwxk 1/1 Running 0 20m orders-db-659949975f-bckt8 1/1 Running 0 20m payment-7bcdbf45c9-d2g8j 1/1 Running 0 20m queue-master-5f6d6d4796-7frwb 1/1 Running 0 20m rabbitmq-5bcbb547d7-52s6p 2/2 Running 0 20m session-db-7cf97f8d4f-xfvzh 1/1 Running 0 20m shipping-7f7999ffb7-2xqh8 1/1 Running 0 20m user-68df64db9c-tcj28 1/1 Running 0 20m user-db-6df7444fc-gtrz5 1/1 Running 0 20m
ブラウザで http://192.168.123.101:30001 あるいは http://192.168.123.102:30001 にアクセスし、Sock ShopのUIが表示されれば正常に動作しています。
IPアドレス範囲の確認
--pod-network-cidr 198.51.100.0/24 が有効だったかどうかは次で確認できます。
$ kubectl -n sock-shop get pods -o jsonpath='{range .items[*]}{.status.podIP}{"\n"}' 198.51.100.215 198.51.100.207 198.51.100.8 198.51.100.209 198.51.100.9 198.51.100.210 198.51.100.14 198.51.100.212 198.51.100.11 198.51.100.216 198.51.100.13 198.51.100.10 198.51.100.206 198.51.100.12
--service-cidr 203.0.113.0/24 が有効だったかどうかは次で確認できます。
$ kubectl -n sock-shop get svc -o jsonpath='{range .items[*]}{.spec.clusterIP}{"\n"}' 203.0.113.190 203.0.113.234 203.0.113.36 203.0.113.141 203.0.113.12 203.0.113.171 203.0.113.235 203.0.113.53 203.0.113.73 203.0.113.61 203.0.113.254 203.0.113.77 203.0.113.21 203.0.113.227
片付け
次のコマンドでSock Shopを停止・削除します。
$ kubectl delete ns sock-shop namespace "sock-shop" deleted
まとめ
本稿ではVagrant + VirtualboxでKubernetesをインストールする際に問題となるプライマリネットワークインターフェイスと、Kubernetesで使われるさまざまなIPアドレス範囲とその変更方法、そして実際のkubeadmによるKubernetesのインストールとデモアプリケーションのデプロイについて見てみました。
IPアドレス範囲について把握しておけばKubernetesの学習中に遭遇する疑問やトラブルなどに対処しやすくなり、またVagrant + VirtualboxでKubernetesをインストールできていればクラウド料金等をかけずに手軽に実験することも可能です。
皆様のKubernetesの学習に本稿が役立てば幸いです。