Raspberry PI と kubeadm で自宅 Kubernetes クラスタを構築する

# はじめに

こんにちは､ @hatotaka と申します｡この記事は､ [Z Lab Advent Calendar 2017](https://qiita.com/advent-calendar/2017/zlab) 16日目の記事です｡

今回は､Kubernetes初心者向けに､Raspberry PIとkubeadmを利用して自宅Kuberneetesクラスタを構築する方法を紹介したいと思います｡私も11月から本格的に業務でもKubernetesを利用するようになりました｡その勉強として自宅でKubernetesを構築したので､その方法を共有したいと思います｡

# 準備

まずは､必要なものを準備します｡

今回､私が準備したものは以下の通りです｡これらはすべて Yahoo! ショッピングやAmazonで購入することができます｡

- Raspberry Pi 3 Model B * 3
- Transcend microSDHCカード 32GB Class10 UHS-I対応 * 3
- Anker PowerPort 6 (60W 6ポート USB急速充電器)
- LAN ケーブル * 3
- マイクロ USB ケーブル * 3

これらは、弊社親会社のヤフー株式会社が10月から開始したMy Polaris[^my_polaris]の技術活動費用補助を利用して購入しました。この制度は技術力向上のための費用を月1万円まで補助してくれる制度です。Z Labでは、My Porarisをはじめ、ヤフーの様々な制度[^y_welfare][^y_familycare][^y_vacation]を利用することができます。

[^my_polaris]: https://about.yahoo.co.jp/pr/release/2017/10/02a/
[^y_welfare]: https://about.yahoo.co.jp/hr/workplace/welfare.html
[^y_familycare]: https://about.yahoo.co.jp/hr/workplace/familycare.html
[^y_vacation]: https://about.yahoo.co.jp/hr/workplace/vacation.html

また､すでに自宅にある以下のものを利用しました。

- スイッチングハブ
- AirMac Express

私の自宅では､有線LANを作業場まで引っ張ってくることが難しかったので､AirMac Expressを自宅のWiFi アクセスポイントに接続し､そこからスイッチングハブ､スイッチングハブからRaspberry PIに接続しました｡

<img width="400" alt="wifi.png" src="https://qiita-image-store.s3.amazonaws.com/0/100305/5c0ebccb-3fac-0e06-6560-b5f356a830d9.png">

# Kubernetes クラスタの構築

今回構築するKubernetes クラスタは以下のとおりです｡

- Raspberry pi
  - モデル: Raspberry Pi 3 Model B
  - OS: Raspbian stretch lite (2017-11-29)  
- Kubernetes
  - kubeadm: v1.8.4
  - Pod Network: Flannel

また､今回の方法はmacOS High Sierraで行っています｡WindowsやLinux、macOSのほかのバージョンでは異なる場合があるので注意してください｡

## OS のインストール

まずは､Raspberry PIにOSをインストールします｡今回のOSはRaspbianを利用します｡OSのインストールはマイクロSDカードにイメージを書き込みます。これらの作業はmacOS上で行います。

以下のURLからRaspbian stretch liteをダウンロードします｡

- https://www.raspberrypi.org/downloads/raspbian/

ダウンロードしたzipファイルを解凍して､マイクロSDカードに書き込みます｡
ディスクのパスは環境ごとに違うので注意が必要です｡

```console
// zipファイルを解凍する
$ cd ~/Download
$ unzip 2017-09-07-raspbian-stretch-lite.zip
Archive:  2017-09-07-raspbian-stretch-lite.zip
  inflating: 2017-09-07-raspbian-stretch-lite.img 

// SD card のパスを確認
$ diskutil list

// SD card をアンマウントする
$ sudo diskutil umount /dev/disk2s1

// dd コマンドでイメージを書き込む
$ sudo dd bs=1M if=/path/to/image/2017-09-07-raspbian-stretch-lite.img of=/dev/rdisk2
```

詳細は https://www.raspberrypi.org/documentation/installation/installing-images/README.md を参照してください｡

OSイメージをSDカードに書き込めたら､いくつか設定を行います｡これらの作業もmacOS上で行います｡

### ssh の有効化

sshを有効にするための設定をします｡bootディレクトリ以下にsshという名前のファイルを作成します｡

```console
$ cd /Volumes/boot
$ touch ssh
```

この作業を行うことにより､Raspbianの起動後にsshdが起動して､リモートからセットアップを続けることができます｡詳細は https://www.raspberrypi.org/blog/a-security-update-for-raspbian-pixel/ を参照してください｡

### cgroups の有効化

次にcgroupsのcpusetとmemoryを有効化するために､以下の設定を行います｡

```console
$ cd /Volumes/boot
$ vi cmdline.txt
```

`cgroup_enable=cpuset cgroup_enable=memory`を追加します｡

```diff
- dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=af816d3b-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait
+ dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=af816d3b-02 rootfstype=ext4 cgroup_enable=cpuset cgroup_enable=memory elevator=deadline fsck.repair=yes rootwait
```

最新のkernelバージョンでは､ 設定方法が `cgroup_memory=1` に変わっているようです｡

https://archlinuxarm.org/forum/viewtopic.php?f=15&t=12086#p57035

以上の作業をセットアップするRaspberry PIの台数分行います｡

## Bootと初期設定

上記の手順で作成したSDカードを､Raspberry PIに挿入し､電源をいれます｡

起動後､同一ネットワークに `raspberrypi` の名前のインスタンスがなければ､ `raspberrypi.local`の名前でアクセスすることができます｡

```console
$ slogin pi@raspberrypi.local
//  初期パスワードは raspberry
```

ログインができたら､次にホスト名を変更します｡`/etc/hostname`ファイルを修正して、好きなホスト名に変更します。今回私は`raspi[001-003]`の名前を付けました。

また、必要に応じて、ユーザの追加、デフォルトユーザ `pi` の無効化等も実施します。

```console
$ sudo vi /etc/hostname
// ホスト名を変更

// 必要に応じて、ユーザの追加等を行う

$ sudo reboot
```

reboot後は､ `<設定したホスト名>.local`の名前でアクセスすることができます｡

## Docker のインストール

次にDockerのインストールを行います｡

```console
$ slogin <設定したホスト名>.local

// 必要なパッケージのインストール
$ sudo apt-get install apt-transport-https ca-certificates curl software-properties-common

// リポジトリの追加
$ curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | sudo apt-key add -
$ echo "deb [arch=armhf] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
     $(lsb_release -cs) stable" | \
    sudo tee /etc/apt/sources.list.d/docker.list

// インストール
$ sudo apt-get update
$ sudo apt-get install docker-ce
```

詳細は､ https://docs.docker.com/engine/installation/linux/docker-ce/debian/ を参照してください｡

## kubeadmのインストール

次に､kubeadmとkubelet、kubectlをインストールします｡

ます､スワップを無効にします。これはKubernetes 1.8からスワップが有効だとkubeletが起動しない[^kubelet_swapoff]ためです｡

[^kubelet_swapoff]: https://qiita.com/tkusumi/items/0962220a0700cb1f6eb3#ノードの-swap-が有効な場合kubelet-が起動しないようになった

```console
$ sudo dphys-swapfile swapoff
$ sudo dphys-swapfile uninstall
$ sudo update-rc.d dphys-swapfile remove
```

リポジトリを追加してパッケージをインストールします｡

```console
$ slogin <設定したホスト名>.local

// リポジトリの追加
$ curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg|sudo apt-key add -
$ echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kube.list

// インストール
$ sudo apt-get update
$ sudo apt-get install kubelet kubeadm kubectl
```

詳細は､ https://kubernetes.io/docs/setup/independent/install-kubeadm/ を参照してください｡

## Master のセットアップ

masterにするインスタンスで以下のコマンドを実行します｡ `--pod-network-cidr=10.244.0.0/16` のオプションはflannelを利用するために必要なオプションです。

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

....

Your Kubernetes master has initialized successfully!

To start using your cluster, you need to run (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:
  http://kubernetes.io/docs/admin/addons/

You can now join any number of machines by running the following on each node
as root:

  kubeadm join --token xxxxxx.xxxxxxxx 10.0.1.22:6443 --discovery-token-ca-cert-hash sha256:xxxxxxxxx
```

無事成功すると､上記のようなメッセージが表示されます｡

メッセージ通り､pod networkをデプロイします｡今回はFlannelを利用します｡

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

kubectlが正しく実行できるかどうか､確認します｡

```console
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"8", GitVersion:"v1.8.5", GitCommit:"cce11c6a185279d037023e02ac5249e14daa22bf", GitTreeState:"clean", BuildDate:"2017-12-07T16:16:03Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"linux/arm"}
Server Version: version.Info{Major:"1", Minor:"8", GitVersion:"v1.8.5", GitCommit:"cce11c6a185279d037023e02ac5249e14daa22bf", GitTreeState:"clean", BuildDate:"2017-12-07T16:05:18Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"linux/arm"}
```

以下のコマンドでflannelをデプロイします｡

```console
$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/bc79dd1505b0c8681ece4de4c0d86c5cd2643275/Documentation/kube-flannel.yml
```

これで､masterのセットアップが完了しました｡

## Node のセットアップ

nodeとして追加するインスタンスで以下のコマンドを実行します｡このコマンドはmasterのkubeadm init実行時に表示されたものです｡

```console
$ kubeadm join --token xxxxxx.xxxxxxxx 10.0.1.22:6443 --discovery-token-ca-cert-hash sha256:xxxxxxxxx
```

`kubeadm join`を実行後、`kubectl get node`を実行すると、ノードが追加され、ステータスも Ready になります。

```console
$ kubectl get node
NAME       STATUS    ROLES     AGE       VERSION
raspi001   Ready     master    27m       v1.8.5
raspi002   Ready     <none>    1m        v1.8.5
raspi003   Ready     <none>    1m        v1.8.5
```

以上でセットアップ完了です｡

# おわりに

以上の手順でkubeadmを利用することで簡単にRaspberry PIにKubernetesクラスタを構築することができます。みなさんもぜひ自宅にRaspberry PIでKubernetesクラスタを構築してみてください。