ラズパイクラスタにKubernetesをインストール(成功編)
「ラズパイクラスタにKubernetesをインストール(失敗編)」でCentOSを選んだためDockerのインストールに失敗したので、今度はUbuntuで試してみる。
今回の作業内容
全体の作業概要
- 物理的な配線(ラズパイでKubernetesクラスタを構築する(物理編))
- ラズパイにOSをインストール(本記事の範囲)
- Kubernetesのインストール(本記事の範囲)
- Dockerをインストール
- cgroupでmemoryサブシステムを有効にする
- Kubernetesのインストール
Dockerをインストールしようとすると依存関係のエラーが出て、その解決方法を調べるのに時間がとられた。
OSイメージをMicroSDに焼く
UbuntuのwikiからOSイメージをダウンロードする。
公式イメージはPi2用しか配布されていないのでPi3にインストールするためには一手間が必要になる。一応Unofficialとして個人が公開しているPi3用のイメージへのリンクがwikiに貼られている。
いろいろ面倒そうなので公式イメージを使うことにした。
ubuntu-18.04.1-preinstalled-server-armhf+raspi2.img.xzをMacにダウンロードしてxzコマンドで解凍する。
$ xz -d ubuntu-18.04.1-preinstalled-server-armhf+raspi2.img.xz $ ls ubuntu-18.04.1-preinstalled-server-armhf+raspi2.img
MicroSDカードをUnMountしてからSDカードへ書き込む。1枚書き込むのにだいたい30分かかる。
$ diskutil unmountDisk /dev/disk2 Unmount of all volumes on disk2 was successful $ sudo dd bs=1m if=./ubuntu-18.04.1-preinstalled-server-armhf+raspi2.img of=/dev/disk2 2252+0 records in 2252+0 records out 2361393152 bytes transferred in 1949.493602 secs (1211285 bytes/sec)
このOSイメージはPi2用なので、Pi3用で動かすためには
- dbtファイルの置き換え
- config.txtの書き換え
が必要。
また、Pi3 B+で動かすためにはさらにbootloader用にbootcode.bin, fixup.dat and start.elfを置き換える必要がある。
dbtファイルを含めて必要なファイルはGithubのraspberrypi/firmwareリポジトリで公開されている。
wgetでダウンロードする。
$ wget https://github.com/raspberrypi/firmware/raw/master/boot/bcm2710-rpi-3-b-plus.dtb $ wget https://github.com/raspberrypi/firmware/raw/master/boot/bootcode.bin $ wget https://github.com/raspberrypi/firmware/raw/master/boot/fixup.dat $ wget https://github.com/raspberrypi/firmware/raw/master/boot/start.elf
MicroSDカードが/Volume/system-boot
にマウントされているとして、ダウンロードしたファイルをコピーする
$ cp bcm2710-rpi-3-b-plus.dtb /Volumes/system-boot/ $ cp start.elf /Volumes/system-boot/ $ cp bootcode.bin /Volumes/system-boot/ $ cp fixup.dat /Volumes/system-boot/
次に、/Vomue/system-boot/config.txt
の中身を以下のように変更する。
# For more options and information see # http://www.raspberrypi.org/documentation/configuration/config-txt.md # Some settings may impact device functionality. See link above for details # コメントアウト #kernel=uboot.bin #device_tree_address=0x02000000 # 追記 kernel=vmlinuz initramfs initrd.img followkernel
終わったらSDカードを取り出す。
$ diskutil eject /dev/disk2 Disk /dev/disk2 ejected
OSをインストールする
MicroSDカードを刺した状態で電源をいれるとOSのインストールが始まる。
ログインプロンプトが表示されたら
アカウント名:ubuntu
パスワード: ubuntu
でログインしてすぐにパスワードの初期化を求められるので実施する。
- ホスト名の設定: hostname XXX
続いて、ネットワークの設定をしてパッケージを更新する。
- eth0にアドレスを割り当てる
eth0へのネットワークの割り当てはsudo dhclient eth0
でできる。
続いて、パッケージを更新する。
sudo apt update
sudo apt upgrade -y
- 途中、
keyboad-configuration
の設定を聞かれる.
- 途中、
上記を3台に実施する。
ホスト名とIPアドレス、それぞれの役割は以下の通り。
ホスト名 | IPアドレス | 役割 |
---|---|---|
compute-0-0 | 192.168.10.109 | KubernetesのMaster |
compute-0-1 | 192.168.10.108 | KubernetesのNode1 |
compute-0-2 | 192.168.10.107 | KubernetesのNode2 |
このままだとネットワークの名前解決ができないので、各ホストの/etc/hosts
に以下の内容を追記する。
192.168.10.109 compute-0-0 192.168.10.108 compute-0-1 192.168.10.107 compute-0-2
Dockerのインストール
インストールしたUbuntuはarmhf(32bit版)として動作している。docker-ceの推奨は64bitだがUbuntuであればarmhfをサポートしているので問題ない。
$ sudo apt-get update $ sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ software-properties-common $ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - # armv7lなのでarmhfアーキ用を実行 $ sudo add-apt-repository \ "deb [arch=armhf] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable" $ sudo apt-get update $ sudo apt-get install docker-ce $ docker --version Docker version 18.09.0, build 4d60db4
ubuntuユーザがdockerコマンドを実行するたびにsudoが必要である。
sudoがなくてもdockerコマンドを実行できるようにubuntuユーザをdockerグループに追加しておく。
$ sudo gpasswd -a ubuntu docker Adding user ubuntu to group docker $ sudo systemctl restart docker
なお、依存関係のエラーでdocker-ceのインストールに失敗することがあった。
その場合はapt-utilの依存関係を修復する。
$ sudo apt-get install docker-ce Reading package lists... Done Building dependency tree Reading state information... Done You might want to run 'apt --fix-broken install' to correct these. The following packages have unmet dependencies: apt-utils : Depends: apt (= 1.6.3) but 1.6.6 is to be installed docker-ce : Depends: docker-ce-cli but it is not going to be installed Depends: containerd.io but it is not going to be installed Recommends: aufs-tools but it is not going to be installed Recommends: cgroupfs-mount but it is not going to be installed or cgroup-lite but it is not going to be installed Recommends: pigz but it is not going to be installed Recommends: libltdl7 but it is not going to be installed E: Unmet dependencies. Try 'apt --fix-broken install' with no packages (or specify a solution). $ sudo apt --fix-broken install Reading package lists... Done Building dependency tree Reading state information... Done Correcting dependencies... Done The following additional packages will be installed: apt-utils The following packages will be upgraded: apt-utils 1 upgraded, 0 newly installed, 0 to remove and 89 not upgraded. 16 not fully installed or removed. Need to get 0 B/192 kB of archives. After this operation, 0 B of additional disk space will be used. Do you want to continue? [Y/n] Y ...
修復が完了したらもう一度docker-ceをインストールする。
$ sudo apt-get install docker-ce Reading package lists... Done Building dependency tree Reading state information... Done The following additional packages will be installed: aufs-tools cgroupfs-mount containerd.io docker-ce-cli libltdl7 pigz The following NEW packages will be installed: aufs-tools cgroupfs-mount containerd.io docker-ce docker-ce-cli libltdl7 pigz 0 upgraded, 7 newly installed, 0 to remove and 89 not upgraded. 1 not fully installed or removed. Need to get 29.7 MB of archives. After this operation, 149 MB of additional disk space will be used. Do you want to continue? [Y/n] Y ...
Kubernetesをインストールする
Kubernetesは1.8からSwapが有効になっているとkubeletが起動しなくなっている。 今回の環境はSwap領域は存在しないので気にしてくていいが、もしSwapが有効になっていれば無効化が必要。
# swap領域が0になっている $ free -h total used free shared buff/cache available Mem: 923M 138M 84M 4.4M 701M 764M Swap: 0B 0B 0B # 念のためSwapの有無を確認 $ swapon -s
続いて、公式ドキュメントに従って全ホストでkubeadm, kubelet, kubectlをインストールする。
# rootになる sudo su - apt-get update && apt-get install -y apt-transport-https curl curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - cat <<EOF >/etc/apt/sources.list.d/kubernetes.list deb https://apt.kubernetes.io/ kubernetes-xenial main EOF apt-get update apt-get install -y kubelet kubeadm kubectl apt-mark hold kubelet kubeadm kubectl
インストールしたパッケージのバージョンを確認する。
# dpkg -l |grep kube ii kubeadm 1.13.1-00 armhf Kubernetes Cluster Bootstrapping Tool ii kubectl 1.13.1-00 armhf Kubernetes Command Line Tool ii kubelet 1.13.1-00 armhf Kubernetes Node Agent ii kubernetes-cni 0.6.0-00 armhf Kubernetes CNI
続いて、Kubernetesクラスタのネットワークを設計する。
Kubernetesはoerlay networkを構築する必要がある。そのためのツールとして有名なところではflannnel, weave, Calicoなどがある。
今回はARMプロセッサの上で動くUbuntu 18.04の32bit版で動作することが要件になる。
Calicoの要件はAMD64プロセッサであること。Ubuntuの32bitで動作するか不安なので見送る。
WeaveはARMをサポートしたバイナリをリリースしているものの、32bitに対応しているか明記されていなかったこととWeaveをラズパイ3B+で動かしたときにカーネルに起因するバグがあるissueを見つけたので見送る。
そこで、今回はflannelを採用することにした。
先ほど書いたようにホストは192.168.10.0/24で設定されている。
flannelが環境構築のために公開しているマニフェストは初期値が10.2544.0.0/16になっている。Pod IPのCIDRは10.244.0.0/16を割り当てることにした。違うCIDRを割り当てたい場合は、後述するflannelの環境構築時にgithub上のマニフェストを指定するのではなく、ローカルにダウンロードしたマニフェストを編集して利用すればいい。
KubernetesのMasterを起動するため、compute-0-0でkubeadm init
を実行する。
$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16 [init] Using Kubernetes version: v1.13.1 [preflight] Running pre-flight checks [preflight] The system verification failed. Printing the output from the verification: KERNEL_VERSION: 4.15.0-1017-raspi2 CONFIG_NAMESPACES: enabled CONFIG_NET_NS: enabled CONFIG_PID_NS: enabled CONFIG_IPC_NS: enabled CONFIG_UTS_NS: enabled CONFIG_CGROUPS: enabled CONFIG_CGROUP_CPUACCT: enabled CONFIG_CGROUP_DEVICE: enabled CONFIG_CGROUP_FREEZER: enabled CONFIG_CGROUP_SCHED: enabled CONFIG_CPUSETS: enabled CONFIG_MEMCG: enabled CONFIG_INET: enabled CONFIG_EXT4_FS: enabled CONFIG_PROC_FS: enabled CONFIG_NETFILTER_XT_TARGET_REDIRECT: enabled (as module) CONFIG_NETFILTER_XT_MATCH_COMMENT: enabled (as module) CONFIG_OVERLAY_FS: enabled (as module) CONFIG_AUFS_FS: enabled (as module) CONFIG_BLK_DEV_DM: enabled DOCKER_VERSION: 18.09.0 OS: Linux CGROUPS_CPU: enabled CGROUPS_CPUACCT: enabled CGROUPS_CPUSET: enabled CGROUPS_DEVICES: enabled CGROUPS_FREEZER: enabled CGROUPS_MEMORY: missing [WARNING SystemVerification]: this Docker version is not on the list of validated versions: 18.09.0. Latest validated version: 18.06 error execution phase preflight: [preflight] Some fatal errors occurred: [ERROR SystemVerification]: missing cgroups: memory [preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`
cgroupのmemoryが無効化されているらしい。/proc/cgroups
を確認するとたしかにmemoryのenabledが0(無効)になっている。
$ cat /proc/cgroups #subsys_name hierarchy num_cgroups enabled cpuset 10 2 1 cpu 6 60 1 cpuacct 6 60 1 blkio 7 60 1 memory 0 68 0 devices 4 60 1 freezer 2 2 1 net_cls 3 2 1 perf_event 5 2 1 net_prio 3 2 1 pids 8 66 1 rdma 9 1 1
boot時の設定を変更してcgroupfsのmemoryを有効にする。
/boot/firmware/cmdline.txt
にcgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory
を追記して再起動する。追記が終わったあとのファイルは以下の通り。
$ cat /boot/firmware/cmdline.txt net.ifnames=0 dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory # reboot
再起動したあとはeth0に割り当てられたIPが消えているのでsudo dhclient eth0
を実行する。
memoryサブシステムが有効になっているのがわかる。
$ cat /proc/cgroups #subsys_name hierarchy num_cgroups enabled cpuset 2 1 1 cpu 5 34 1 cpuacct 5 34 1 blkio 4 34 1 memory 7 68 1 devices 11 34 1 freezer 9 1 1 net_cls 3 1 1 perf_event 8 1 1 net_prio 3 1 1 pids 6 39 1 rdma 10 1 1
再度Kubernetesをインストールしなおす.
$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16 [init] Using Kubernetes version: v1.13.1 [preflight] Running pre-flight checks [WARNING SystemVerification]: this Docker version is not on the list of validated versions: 18.09.0. Latest validated version: 18.06 [preflight] Pulling images required for setting up a Kubernetes cluster [preflight] This might take a minute or two, depending on the speed of your internet connection [preflight] You can also perform this action in beforehand using 'kubeadm config images pull' [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Activating the kubelet service [certs] Using certificateDir folder "/etc/kubernetes/pki" [certs] Generating "ca" certificate and key [certs] Generating "apiserver" certificate and key [certs] apiserver serving cert is signed for DNS names [ubuntu kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.10.109] [certs] Generating "apiserver-kubelet-client" certificate and key [certs] Generating "etcd/ca" certificate and key [certs] Generating "etcd/peer" certificate and key [certs] etcd/peer serving cert is signed for DNS names [ubuntu localhost] and IPs [192.168.10.109 127.0.0.1 ::1] [certs] Generating "etcd/server" certificate and key [certs] etcd/server serving cert is signed for DNS names [ubuntu localhost] and IPs [192.168.10.109 127.0.0.1 ::1] [certs] Generating "etcd/healthcheck-client" certificate and key [certs] Generating "apiserver-etcd-client" certificate and key [certs] Generating "front-proxy-ca" certificate and key [certs] Generating "front-proxy-client" certificate and key [certs] Generating "sa" key and public key [kubeconfig] Using kubeconfig folder "/etc/kubernetes" [kubeconfig] Writing "admin.conf" kubeconfig file [kubeconfig] Writing "kubelet.conf" kubeconfig file [kubeconfig] Writing "controller-manager.conf" kubeconfig file [kubeconfig] Writing "scheduler.conf" kubeconfig file [control-plane] Using manifest folder "/etc/kubernetes/manifests" [control-plane] Creating static Pod manifest for "kube-apiserver" [control-plane] Creating static Pod manifest for "kube-controller-manager" [control-plane] Creating static Pod manifest for "kube-scheduler" [etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests" [wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s [kubelet-check] Initial timeout of 40s passed. [apiclient] All control plane components are healthy after 85.513804 seconds [uploadconfig] storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [kubelet] Creating a ConfigMap "kubelet-config-1.13" in namespace kube-system with the configuration for the kubelets in the cluster [patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "ubuntu" as an annotation [mark-control-plane] Marking the node ubuntu as control-plane by adding the label "node-role.kubernetes.io/master=''" [mark-control-plane] Marking the node ubuntu as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule] [bootstrap-token] Using token: ntvqxo.ghxfq7gvi8rc79aw [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles [bootstraptoken] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials [bootstraptoken] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token [bootstraptoken] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster [bootstraptoken] creating the "cluster-info" ConfigMap in the "kube-public" namespace [addons] Applied essential addon: CoreDNS [addons] Applied essential addon: kube-proxy Your Kubernetes master has initialized successfully! To start using your cluster, you need to run the following as a regular user: mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config You should now deploy a pod network to the cluster. Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/ You can now join any number of machines by running the following on each node as root: kubeadm join 192.168.10.109:6443 --token ntvqxo.ghxfq7gvi8rc79aw --discovery-token-ca-cert-hash sha256:709766a97f016e2a0fd5113b12ce5afa1cebc740ecfa6596f8bbe9f30cb5897f
kubectlに認証設定を読み込ませるために指定されたコマンドを実行する。
$ mkdir -p $HOME/.kube $ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config $ sudo chown $(id -u):$(id -g) $HOME/.kube/config
動作していることが確認できる。
$ kubectl get node NAME STATUS ROLES AGE VERSION compute-0-0 NotReady master 23m v1.13.1
STATUSがNodeReadyなのはOveray Networkが設定されていないから。flannelをインストールする。
$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml clusterrole.rbac.authorization.k8s.io/flannel created clusterrolebinding.rbac.authorization.k8s.io/flannel created serviceaccount/flannel created configmap/kube-flannel-cfg created daemonset.extensions/kube-flannel-ds-amd64 created daemonset.extensions/kube-flannel-ds-arm64 created daemonset.extensions/kube-flannel-ds-arm created daemonset.extensions/kube-flannel-ds-ppc64le created daemonset.extensions/kube-flannel-ds-s390x created # STATUSがReadyになった $ kubectl get node NAME STATUS ROLES AGE VERSION compute-0-0 Ready master 34m v1.13.1
Nodeになるcompute-0-1とcompute-0-2で以下を実行する。
$ sudo kubeadm join 192.168.10.109:6443 --token ntvqxo.ghxfq7gvi8rc79aw --discovery-token-ca-cert-hash sha256:709766a97f016e2a0fd5113b12ce5afa1cebc740ecfa6596f8bbe9f30cb5897f [preflight] Running pre-flight checks [WARNING SystemVerification]: this Docker version is not on the list of validated versions: 18.09.0. Latest validated version: 18.06 [discovery] Trying to connect to API Server "192.168.10.109:6443" [discovery] Created cluster-info discovery client, requesting info from "https://192.168.10.109:6443" [discovery] Requesting info from "https://192.168.10.109:6443" again to validate TLS against the pinned public key [discovery] Cluster info signature and contents are valid and TLS certificate validates against pinned roots, will use API Server "192.168.10.109:6443" [discovery] Successfully established connection with API Server "192.168.10.109:6443" [join] Reading configuration from the cluster... [join] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml' [kubelet] Downloading configuration for the kubelet from the "kubelet-config-1.13" ConfigMap in the kube-system namespace [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Activating the kubelet service [tlsbootstrap] Waiting for the kubelet to perform the TLS Bootstrap... [patchnode] Uploading the CRI Socket information "/var/run/dockershim.sock" to the Node API object "compute-0-1" as an annotation This node has joined the cluster: * Certificate signing request was sent to apiserver and a response was received. * The Kubelet was informed of the new secure connection details. Run 'kubectl get nodes' on the master to see this node join the cluster.
compute-0-0からkubectl get node
を実行するとNodeがクラスタとして認識されていることを確認できる。
$ kubectl get node NAME STATUS ROLES AGE VERSION compute-0-2 Ready <none> 73s v1.13.1 compute-0-1 Ready <none> 75s v1.13.1 compute-0-0 Ready master 39m v1.13.1
以上でKubernetesクラスタの構築ができました。
CentOSのコンテナを作ってみる。
$ kubectl run tmp-centos --rm -it --image centos -- bash kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead. If you don't see a command prompt, try pressing enter. [root@tmp-centos-cc49649b6-kpfvg /]#
Deploymentが動くことも確認できた。
まとめ
Kubernetesクラスタのインストールは何度もやったことがあったので、初のラズパイといってもまぁすぐに終わるだろうと思っていたら、実家のネットワーク設定によるものやSDカードの不具合によるもの、OSの選定、OSインストール後の謎の個体差などなどでかなり時間がかかってしまった。
他にも実はここに書ききれない細かなトライ&エラーを繰り返している。Ubuntu 18系を使うのは初めてだったので、原因がOSのバージョン、カーネルのバージョン、ラズパイのどれに起因するものなのかの切り分けが大変だった。
トラブルの原因を調べて解決することを繰り返すことで知識がつくので、これはこれで新年からいい経験ができたと思う。