Kubernetesクラスタを作ってみた with ラズベリーパイ〜上品なファブリックケーブルを添えて〜

一家に一台Kubernetesクラスタの時代が到来したとちらほらと聞こえ始めてきたので、いまさらながらRaspberry PIKubernetesクラスタを作ってみました。

Raspberry PIKubernetesクラスタであれば、EKSのようなクラウドベンダーが提供しているサービスではないので

  • マスターノードに制約がなく自由に設定ができる
  • サーバ費用をかけずに、複数ノード環境でaddonの検証ができる

というのが良いところか思います。

用意したもの

ラズパイとmicroSDカード、microUSBは千石電商、LANケーブルとケースはAmazon、その他はヨドバシAkibaで入手しました

揃えた中でちょっと微妙だったかもと思ったは以下の2つです。

  • LANケーブルは見た目にこだわった結果、長いものしかなく上記のものを選択しましたが短い方が配線は綺麗になるかと思います。
  • 充電機に使ったElecom MPA-ACD03BKは思ったより大きく、横にすると入らなくなったので、もう少し小さいものを購入した方が良さそうです。

環境の構成

SSHで接続するPC環境はSSHを使える環境、Raspbianイメージを作成するPC環境はイメージをSDカードにwriteできる環境であればどんな環境でも大丈夫です。 f:id:moritamorie:20190913015246p:plain

  • Raspberry PI k8s環境 (マスター, ワーカノード共通)
    • Raspbian Buster Lite (Version:July 2019, Release date:2019-07-10, Kernel version:4.19)

ラズパイクラスタをRaspbian stretch liteで作ったという記事を良くみかけますが、Raspbian Buster Liteに関してもそれらの記事の設定方法とまったく同じで手順で大丈夫でした。

完成したところ

ケーブルはよく見かける感じのものだと味気ないので、白黒のケーブルにしてみました。ケースもグレーにして大人っぽい上品な感じに仕上げてみました。

ビールかなんかと一緒に置くとより一層大人っぽい雰囲気を楽しめるかもしれません。 f:id:moritamorie:20190914114627j:plain

作り方

組み立て

組み立て方はつまるところがないと思うので省略します。

イメージの準備

以下のSDカードの準備イメージ内のファイル編集は、ラズパイ3台分 (SDカード3枚)行います。

SDカードの準備

Raspbianイメージを作成するPC環境(Windows 10環境を使いました)で、Raspbian Buster Lite (旧raspbian stretch lite)の最新版のイメージをダウンロードします。

イメージのSDカードへの書き込みは、Win32 Disk Imagerというツールを使いました。

イメージ内のファイルを編集

SDカード作成後、Windows OS上で以下のファイルを変更しました。

  • /bootディレクトリ直下にsshという名前のファイル(中身は空)を作成
    • デフォルトではSSHで接続できないので接続できるようにします。

f:id:moritamorie:20190913020631p:plain

  • /bootディレクトリ直下にある cmdline.txt を編集し、cgroup_enable=cpuset cgroup_enable=memoryを追加
    • cgroupsのcpusetとmemoryを有効化 f:id:moritamorie:20190910230143p:plain

Raspbian起動後の下準備

microSDカードをラズパイに挿入、充電器からmicroUSBケーブルを指して給電してラズパイを起動します。ラズパイ各環境でIPアドレス、ホスト名設定するまではHDMIケーブルで外部モニタ、USBキーボードを接続して操作しました。

下準備の設定内容は、マスターノード、ワーカーノードで共通です。

パッケージ更新、スワップオフ

デフォルトの

  • ユーザ: pi
  • パスワード: raspberry

でログイン。

aptパッケージを最新化します。

$ sudo apt-get -y update
$ sudo apt-get -y upgrade

Kubernetes 1.8以降スワップが有効のままだとkubeletが起動しなくなったので、スワップをオフにします。

$ sudo dphys-swapfile swapoff
$ sudo dphys-swapfile uninstall
$ sudo update-rc.d dphys-swapfile remove
ホスト名・Pアドレスを固定

次に /etc/hostname, /etc/hosts を編集しホスト名を変更、/etc/dhcpcd.confを編集しIPアドレスを固定します。

ホスト名、IPアドレスは3台それぞれ

  • k8s-master-01 (192.168.13.101)
  • k8s-worker-01 (192.168.13.102)
  • k8s-worker-02 (192.168.13.103)

をホスト名 (IPアドレス)にしてみました。

以下のようにマスターノードのホスト名の設定しました。

$ sudo vi /etc/hostname
- raspberrypi
+ k8s-master-01
$ sudo vi /etc/hosts
- 127.0.1.1  raspberrypi
+ 127.0.1.1  k8s-master-01

同様にマスターノードのIPアドレス設定を設定しました

$ sudo vi /etc/dhcpcd.conf
interface eth0
static ip_address=192.168.13.101/24
static routers=192.168.13.1
static domain_name_servers=192.168.13.1 8.8.8.8

PC環境からSSH接続できるように

SSH秘密鍵と公開鍵を作っておきます。鍵は同じものを使うようにしたため、実行は1回のみです。

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/username/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): <パスフレーズ>
Enter same passphrase again: <パスフレーズ>
Your identification has been saved in 【秘密鍵のファイル名】
Your public key has been saved in 【秘密鍵のファイル名】.pub.

作った公開鍵をラズパイ側の~/.ssh/authorized_keysにコピーします。以下はマスターノードの設定で実行したコマンドです。

$ ssh-copy-id -i 【秘密鍵のパス】 pi@192.168.13.101
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "秘密鍵のファイル名.pub"
The authenticity of host '192.168.13.101 (192.168.13.101)' can't be established.
ECDSA key fingerprint is SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
pi@192.168.13.101's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'pi@192.168.13.1021"
and check to make sure that only the key(s) you wanted were added.

SSH接続しやすいようにPC設定

.ssh/configに以下のように追加します。

Host k8s-master-01
    HostName 192.168.13.101
    User pi
    Port 22
    IdentityFile 【秘密鍵のパス】

ここまででSSH接続の設定は終わりです。以後の作業は、PC環境からSSHで各ラズパイ環境接続して作業を行っていきます。

Dockerをインストール

各ラズパイ環境にDockerをインストールしていきます。

$ curl -sSL https://get.docker.com/ | sh

kubelet kubeadm kubectl kubernetes-cni のインストール

https経由でaptを実行するために必要なパッケージをインストールします。

$ sudo apt-get install -y apt-transport-https

Google cloudの公式キー登録します。

$ curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -

ソースリストにkubernetesを追加します。

$ echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list

apt更新

$ sudo apt-get update

kubelet kubeadm kubectl kubernetes-cniをインストールします。

$ sudo apt-get install kubelet kubeadm kubectl kubernetes-cni

各ノード間でバージョンが異なると予期せぬ動きに繋がるので、バージョンが変わらないようにしておきます。

$ sudo apt-mark hold kubelet kubeadm kubectl kubernetes-cni

マスターノードのセットアップ

以下のコマンドを実行し、kubernetesクラスタのコントロールプレーンを初期化します。

$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16

後にネットワークaddonとしてインストールするflannelのドキュメントを読むとkubeadmの場合、pod-network-cidrに制約があるようなのでドキュメント通りにしています。

他の有名どころのネットワークaddonとして

  • Calicoは、AMD64プロセッサが動作要件にある。Raspbianは32bitなので候補から除外
  • Weaveに関しては、ARMをサポートしているが32bitに対応しているか明示されていないので候補から除外

消去法で残ったflannelを使うことにしています。

kubeadm initすると実行結果の一番最後の他のワーカーノードがジョインするためのコマンドが表示されるので控えておきます。

Your Kubernetes control-plane 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/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.13.101:6443 --token XXXXXXXXXXXXXXXXX \
    --discovery-token-ca-cert-hash sha256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

続いて、kubeadm initの実行結果に記載されているコマンドを実行します。

$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

現時点でどのPodが動いているか確認してみます。

$ kubectl get pods --all-namespaces

NAMESPACE     NAME                                    READY   STATUS    RESTARTS   AGE
kube-system   coredns-5c98db65d4-4bhgq                0/1     Pending   0          14m
kube-system   coredns-5c98db65d4-p5s4t                0/1     Pending   0          14m
kube-system   etcd-k8s-master-01                      1/1     Running   0          14m
kube-system   kube-apiserver-k8s-master-01            1/1     Running   0          13m
kube-system   kube-controller-manager-k8s-master-01   1/1     Running   0          14m
kube-system   kube-proxy-dz99s                        1/1     Running   0          14m
kube-system   kube-scheduler-k8s-master-01            1/1     Running   0  

Pod network addonがなく、corednsのpodがREADYの状態になっています。 Network addonとしてflannelを入れてみます。

# コマンドは https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#pod-network から取得
$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/62e44c867a2846fefb68bd5f178daf4da3095ccb/Documentation/kube-flannel.yml

数分待ってから再度Podの状態を確認してみると

$ kubectl get pods --all-namespaces

NAMESPACE     NAME                                    READY   STATUS    RESTARTS   AGE
kube-system   coredns-5c98db65d4-4bhgq                1/1     Running   0          37m
kube-system   coredns-5c98db65d4-p5s4t                1/1     Running   0          37m
kube-system   etcd-k8s-master-01                      1/1     Running   0          37m
kube-system   kube-apiserver-k8s-master-01            1/1     Running   0          36m
kube-system   kube-controller-manager-k8s-master-01   1/1     Running   1          37m
kube-system   kube-flannel-ds-arm-szj4t               1/1     Running   0          4m50s
kube-system   kube-proxy-dz99s                        1/1     Running   0          37m
kube-system   kube-scheduler-k8s-master-01            1/1     Running   1

全Pod Runningになっていることを確認できました。

ワーカーノードをKubernetesクラスに追加

残りのワーカーノードにSSHログインして、先程控えておいたクラスタ参加のためのコマンド実行するだけです。

$ sudo kubeadm join 192.168.13.101:6443 --token XXXXXXXXXXXXXXXXX \
    --discovery-token-ca-cert-hash sha256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

再度マスターノードにSSHログインして、以下のコマンドを実行すると

$ kubectl get nodes

NAME            STATUS   ROLES    AGE   VERSION
k8s-master-01   Ready    master   58m   v1.15.3
k8s-worker-01   Ready    <none>   17m   v1.15.3
k8s-worker-02   Ready    <none>   19s   v1.15.3

無事3台のノードでkubernetesクラスタができていることが確認できました。

参考資料