こんにちは、SREチームの西脇(@yasuhiro1711)です。今回は特別番組ということで、33時間クッキング、【Kubernetesのラズベリーパイ包み ウエパ風】をお送りしたいと思います。見逃しそうな方はぜひ録画予約をお願いします。

サイバーの美味しそうなパイ包みを見て、ウエパでも物理的にパイ包みを作ってみることにしました。ローカルマシンやクラウドでもクラスターを組んで利用することは可能ですが、このクッキングを通じてKubernetesのそもそもの理解を深めることを目的としてやりました。

※ なおこちらの記事は、至る所をサイバーエージェントを非常〜〜にオマージュしおります。この記事を了承頂きまして、本当にありがとうございます! オマージュ記事は最後にリンクがございます。

一家に一台、Kubernetesの時代に

この10年でスマホが爆発的に普及したように、Kubernetesが一家に一台の時代がやってきます。本日作るラズベリーパイ包みはそんな時代にもってこい。家庭でお子様からおじいちゃんまで幅広く愛されるであろう、手のひらサイズのKubernetesです。

完成品

完成品はこちらとなります。ジャーン!
Image from iOS (9) 2

材料 (1クラスタ分)

では、まずは材料のご紹介です。

材料名 個数
Raspberry Pi 3 Model B 3 個
ヒートシンク 3 セット
microSD カード (16 GB) 3 枚
4 段積層式 Raspberry Pi 3 ケース 1 個
6 ポート 50W USB 充電器 1 個
2.4A microUSB ケーブル 5 本
コンパクト無線親機 (WMR-433W-BK) 1 個
microUSB 給電 スイッチングハブ (LAN-SW05PSBE) 1 個
0.3m LAN ケーブル 3 本
0.15m LAN ケーブル 1 本
3M 強力両面テープ 少々
結束テープ 少々
六角スペーサー 適量
ウエパ のステッカー プライスレス

これだけの材料を集めるとこんな感じになりました。

s_Image from iOS

そのままでも美味しそうなラズベリーパイが6個もありますね。

作り方

ネタの下準備

1, ラズパイの開封

まずは、ラズベリーパイを開封します。

s_Image from iOS (1)

傷つけないよう気をつけましょう。

2, ヒートシンク設置

続いてヒートシンクをつけます。両面テープを剥がすのが意外に辛かったです。魚の鱗取りのようでした。

s_Image from iOS (2)

3, 4 段積層式のケースの 下 3 段に Raspberry Pi を取り付け

アクリル板の保護シールを剥がします。剥がしづらいと聞いていましたが今回購入のものは、爪を使えば意外と簡単でした。

s_Image from iOS (3)

剥がしたらアクリル板にラズパイを取り付けます。このようにできればOKです。わくわくわく!

s_Image from iOS (4)

その後,2段目、3段目と作ってまいります。おーいい感じ。

s_Image from iOS (5)

4, 最上段に USB 充電器を取り付け

写真のようなかたちでUSB充電器をとりつけます。両面テープでがっちりとめましょう。ちなみに今回の充電器はギリギリの大きさでしたので、購入時に大きさはしっかり見ておいた方がよかったです。

設置後、天板まで設置ができました。

s_Image from iOS (6)

5, 最上段にスイッチングハブとコンパクト無線親機を取り付け

それぞれ両面テープで固定します。向きはあなたの感性で。ケーブルの長さには注意しましょう。

s_Image from iOS (7)

6, 最後にケーブリングを丁寧に実施

ここがエンジニアそれぞれの個性を出すところです。私はこんな感じで決めました! 

s_Image from iOS (8)

7, ネットワークの設定

一番上に設置している、無線LANルーターに接続します。その管理画面にて、別wifiに接続することでインターネットへの疎通もとれます。

OS のインストール

ここからの部分は、いくつかの方法を試して理解を深めましたが、ここではパッケージを用いた分かりやすい構築手順を記載して進めていきます。まずは、Raspberry PIにOSをインストールします。今回はRaspbianを利用します。

マイクロSDカードにOSイメージ作成

これより、マイクロSDカードにイメージを書き込みする作業をmacOS上で行います。

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

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

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// 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 umountDisk /dev/disk2
// dd コマンドでイメージを書き込む
$ sudo dd bs=1m if=2018-04-18-raspbian-stretch-lite.img of=/dev/rdisk2 conv=sync
1Mと説明しているサイトが多いが、小文字ですんなりいけた。なんやねん。
// 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 umountDisk /dev/disk2 // dd コマンドでイメージを書き込む $ sudo dd bs=1m if=2018-04-18-raspbian-stretch-lite.img of=/dev/rdisk2 conv=sync 1Mと説明しているサイトが多いが、小文字ですんなりいけた。なんやねん。
// 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 umountDisk /dev/disk2


// dd コマンドでイメージを書き込む
$ sudo dd bs=1m if=2018-04-18-raspbian-stretch-lite.img of=/dev/rdisk2 conv=sync

1Mと説明しているサイトが多いが、小文字ですんなりいけた。なんやねん。

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

ssh の有効化

sshを有効にするための設定をしますにsshという名前のファイルを作成します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$ cd /Volumes/boot
$ touch ssh
$ cd /Volumes/boot $ touch ssh
$ cd /Volumes/boot
$ touch ssh

この作業を行うことにより、Raspbianの起動後にsshdが起動し、リモートログインが可能になります。

# cgroups の有効化

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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$ cd /Volumes/boot
$ vi cmdline.txt
$ cd /Volumes/boot $ vi cmdline.txt
$ cd /Volumes/boot
$ vi cmdline.txt

cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1を追加します。

Bootと初期設定

作成したSDカードを、Raspberry PIに挿入し、電源をいれます。

起動後はデフォルトでraspberrypi.localの名前でアクセスすることができます。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
slogin pi@raspberrypi.local
(初期パスワードは raspberry)
slogin pi@raspberrypi.local (初期パスワードは raspberry)
slogin pi@raspberrypi.local

(初期パスワードは raspberry)

その後、各OSのホスト名の設定、hostsの設定を行います。3台は、k8s01(master)、k8s02(node)、k8s03(node) としました。

スワップ削除

k8s 1.8からスワップが有効だとkubeletが起動しないので実施する。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
sudo dphys-swapfile swapoff
sudo dphys-swapfile uninstall
sudo update-rc.d dphys-swapfile remove
sudo dphys-swapfile swapoff sudo dphys-swapfile uninstall sudo update-rc.d dphys-swapfile remove
sudo dphys-swapfile swapoff
sudo dphys-swapfile uninstall
sudo update-rc.d dphys-swapfile remove

DockerとKubernetesコンポーネントのインストール

Docker インストール

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
curl -sSL https://get.docker.com/ | sh
curl -sSL https://get.docker.com/ | sh
curl -sSL https://get.docker.com/ | sh

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

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

apt-transport-httpsをインストール

自分の環境では既にインストール済みでした。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
apt-get install -y apt-transport-https
apt-get install -y apt-transport-https
apt-get install -y apt-transport-https

鍵登録

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -

aptのソースリストにkubernetesを追加

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list

aptを更新します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
sudo apt-get update
sudo apt-get update
sudo apt-get update

kubernetesの各モジュールをインストールします。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
apt-get install kubelet kubeadm kubectl kubernetes-cni
apt-get install kubelet kubeadm kubectl kubernetes-cni
apt-get install kubelet kubeadm kubectl kubernetes-cni

※ インストールに成功すると自動的にkubeletが起動します。

masterのセットアップ(k8s01でのみ実施)

master のセットアップを行います。

以下を実行

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
sudo kubeadm init --pod-network-cidr=10.244.0.0/16

もしinitに失敗していたら、kubeadm reset で戻せます。成功すると以下のようなメッセージが流れます。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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 6391e6.b4b1bb96a7bdea7c 192.168.13.11:6443 --discovery-token-ca-cert-hash sha256:90be9b3dd4d44c1225d5c3e52af49db25d5c3e5226a5a708fe0af36dadb
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 6391e6.b4b1bb96a7bdea7c 192.168.13.11:6443 --discovery-token-ca-cert-hash sha256:90be9b3dd4d44c1225d5c3e52af49db25d5c3e5226a5a708fe0af36dadb
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 6391e6.b4b1bb96a7bdea7c 192.168.13.11:6443 --discovery-token-ca-cert-hash sha256:90be9b3dd4d44c1225d5c3e52af49db25d5c3e5226a5a708fe0af36dadb

kubeadm init で表示されたメッセージに従って、以下のコマンドも実行。

rootから一般ユーザになって実行します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

kubectl が正しく実行できるか確認。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$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.13", GitCommit:"290fb182489a396dce5d136451388f9b12f29c94", GitTreeState:"clean", BuildDate:"2018-05-15T18:08:47Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"linux/arm"}
$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.13", GitCommit:"290fb182489a396dce5d136451388f9b12f29c94", GitTreeState:"clean", BuildDate:"2018-05-15T18:08:47Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"linux/arm"}
$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.13", GitCommit:"290fb182489a396dce5d136451388f9b12f29c94", GitTreeState:"clean", BuildDate:"2018-05-15T18:08:47Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"linux/arm"}

kubectl get nodes

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s01 NotReady master 5m v1.8.5
kubectl get nodes NAME STATUS ROLES AGE VERSION k8s01 NotReady master 5m v1.8.5
kubectl get nodes
NAME      STATUS     ROLES     AGE       VERSION
k8s01     NotReady   master    5m        v1.8.5

kubectl get pods –all-namespaces -o wide

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
kubectl get pods --all-namespaces -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE
kube-system etcd-k8s01 1/1 Running 0 6m 192.168.13.11 k8s01
kube-system kube-apiserver-k8s01 1/1 Running 0 6m 192.168.13.11 k8s01
kube-system kube-controller-manager-k8s01 1/1 Running 0 6m 192.168.13.11 k8s01
kube-system kube-dns-66ffd5c588-fns2f 0/3 Pending 0 6m <none> <none>
kube-system kube-proxy-tfwl8 1/1 Running 0 6m 192.168.13.11 k8s01
kube-system kube-scheduler-k8s01 1/1 Running 0 6m 192.168.13.11 k8s01
kubectl get pods --all-namespaces -o wide NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE kube-system etcd-k8s01 1/1 Running 0 6m 192.168.13.11 k8s01 kube-system kube-apiserver-k8s01 1/1 Running 0 6m 192.168.13.11 k8s01 kube-system kube-controller-manager-k8s01 1/1 Running 0 6m 192.168.13.11 k8s01 kube-system kube-dns-66ffd5c588-fns2f 0/3 Pending 0 6m <none> <none> kube-system kube-proxy-tfwl8 1/1 Running 0 6m 192.168.13.11 k8s01 kube-system kube-scheduler-k8s01 1/1 Running 0 6m 192.168.13.11 k8s01
kubectl get pods --all-namespaces -o wide
NAMESPACE     NAME                            READY     STATUS    RESTARTS   AGE       IP              NODE
kube-system   etcd-k8s01                      1/1       Running   0          6m        192.168.13.11   k8s01
kube-system   kube-apiserver-k8s01            1/1       Running   0          6m        192.168.13.11   k8s01
kube-system   kube-controller-manager-k8s01   1/1       Running   0          6m        192.168.13.11   k8s01
kube-system   kube-dns-66ffd5c588-fns2f       0/3       Pending   0          6m        <none>          <none>
kube-system   kube-proxy-tfwl8                1/1       Running   0          6m        192.168.13.11   k8s01
kube-system   kube-scheduler-k8s01            1/1       Running   0          6m        192.168.13.11   k8s01

おや、 kube-system kube-dns-66ffd5c588-fns2f 0/3となっており、dnsがうまくうごいていないことがわかります。

falnnel のデプロイ

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
kubectl apply -f <(curl -s https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml |sed 's/amd64/arm/g')
kubectl apply -f <(curl -s https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml |sed 's/amd64/arm/g')
kubectl apply -f <(curl -s https://raw.githubusercontent.com/coreos/flannel/v0.9.1/Documentation/kube-flannel.yml |sed 's/amd64/arm/g')

マスター(k8s01)に、node2台をjoin(k8s02,k8s03)

masterで、init が成功した時に、トークンも含めたjoinのコマンドが流れました。これでnodeを登録をします。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
kubeadm join --token 6391e6.b4b1bb96a7bdea7c 192.168.13.11:6443 --discovery-token-ca-cert-hash sha256:90be9b3dd4d44c1225d5c3e52af49dbf611baf1a611d926a5a708fe0af36dadb
kubeadm join --token 6391e6.b4b1bb96a7bdea7c 192.168.13.11:6443 --discovery-token-ca-cert-hash sha256:90be9b3dd4d44c1225d5c3e52af49dbf611baf1a611d926a5a708fe0af36dadb
kubeadm join --token 6391e6.b4b1bb96a7bdea7c 192.168.13.11:6443 --discovery-token-ca-cert-hash sha256:90be9b3dd4d44c1225d5c3e52af49dbf611baf1a611d926a5a708fe0af36dadb

登録後

まだNotReadyですが、、

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
pi@k8s01:~ # kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s01 Ready master 15m v1.8.5
k8s02 NotReady <none> 35s v1.8.5
k8s03 NotReady <none> 34s v1.8.5
pi@k8s01:~ # kubectl get nodes NAME STATUS ROLES AGE VERSION k8s01 Ready master 15m v1.8.5 k8s02 NotReady <none> 35s v1.8.5 k8s03 NotReady <none> 34s v1.8.5
pi@k8s01:~ # kubectl get nodes
NAME      STATUS     ROLES     AGE       VERSION
k8s01     Ready      master    15m       v1.8.5
k8s02     NotReady   <none>    35s       v1.8.5
k8s03     NotReady   <none>    34s       v1.8.5

Readyに変わります。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
pi@k8s01:~ # kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s01 Ready master 16m v1.8.5
k8s02 Ready <none> 1m v1.8.5
k8s03 Ready <none> 1m v1.8.5
pi@k8s01:~ # kubectl get nodes NAME STATUS ROLES AGE VERSION k8s01 Ready master 16m v1.8.5 k8s02 Ready <none> 1m v1.8.5 k8s03 Ready <none> 1m v1.8.5
pi@k8s01:~ # kubectl get nodes
NAME      STATUS    ROLES     AGE       VERSION
k8s01     Ready     master    16m       v1.8.5
k8s02     Ready     <none>    1m        v1.8.5
k8s03     Ready     <none>    1m        v1.8.5

できましたね。これでクラスターが組めましたのでこの上にpodを作成してアプリケーションを乗せて検証できるようになりました。

まとめ

【Kubernetesのラズベリーパイ包み〜ウエパ風〜】を作って見ました。 物理的であるので実際に自らkubernetesの動きを理解していくのには、非常によいものとなりました。また、いくつかのパターンでの構築や、dashbordやmetallbのテストなどにも踏み込んでいけたので、研修としてGoodです。 オライリーの入門Kubernetesにも似た例が載っているので参考にしてみてください。

エンジニア大募集中

Wedding Parkでは一緒に技術のウエディングパークを創っていくエンジニアを募集しています。
興味のある方はぜひ一度気軽にオフィスに遊びにいらして頂ければと思います。

ブライダル業界のデジタルシフトを加速させるリードエンジニア候補募集!

オマージュ記事

お世話になりました。ありがとうございます。

3日間クッキング【Kubernetes のラズペリーパイ包み “サイバーエージェント風”】
https://developers.cyberagent.co.jp/blog/archives/14721/

Join Us !

ウエディングパークでは、一緒に働く仲間を募集しています!
ご興味ある方は、お気軽にお問合せください(カジュアル面談から可)

採用情報を見る