2017年5月7日日曜日

kubernetesをRaspberry pi 3にインストールする(その2)

前回に引き続きkubernetesをRaspberry pi 3にインストールします。

1. etcdのインストール

etcdの配布されているバイナリーにARM版がないため、ソースコードからビルドします。
今回はビルドして、そのバイナリを他のRasPiに配るようにします。

1.1 etcdのビルドとインストール (masterの1台)

# Go-langをインストール
$ wget https://storage.googleapis.com/golang/go1.8.1.linux-armv6l.tar.gz
$ tar zxf go1.8.1.linux-armv6l.tar.gz
$ sudo mv go /usr/local
$ echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.bashrc
# etcdをクローンしてビルド
$ export GOOS=linux
$ export GOARCH=arm
$ export GOARM=7
$ git clone --branch v3.1.7 https://github.com/coreos/etcd.git
$ cd etcd
$ ./build
# ビルドされたファイルは./bin/にできるので、インストール
$ sudo mv ./bin/* /usr/local/bin/
$ sudo chmod 755 /usr/local/bin/etcd
$ sudo chmod 755 /usr/local/bin/etcdctl
# 他のRasPiにファイルを転送
$ scp ./bin/etcd node02:/usr/local/bin/etcd
$ scp ./bin/etcd node02:/usr/local/bin/etcdctl
$ scp ./bin/etcd node03:/usr/local/bin/etcd
$ scp ./bin/etcd node03:/usr/local/bin/etcdctl
# etcdのデータ保存用のディレクトリを作成
$ sudo mkdir -p /var/lib/etcd
$ sudo chown -R root:$(whoami) /var/lib/etcd
$ sudo chmod -R a+rw /var/lib/etcd
# systemdファイルを作成
$ cat > /etc/systemd/system/etcd.service <<EOF
[Unit]
Description=etcd
Documentation=https://github.com/coreos/etcd
After=network.target
[Service]
Type=notify
Restart=always
RestartSec=5s
LimitNOFILE=40000
TimeoutStartSec=0
Environment="ETCD_UNSUPPORTED_ARCH=arm"
ExecStart=/usr/local/bin/etcd --name etcd-1 \\
    --data-dir /var/lib/etcd \\
    --discovery-srv k8s.h-tsk.com \\
    --initial-advertise-peer-urls http://node01.k8s.h-tsk.com:2380 \\
    --advertise-client-urls http://node01.k8s.h-tsk.com:2379 \\
    --listen-client-urls http://127.0.0.1:2379,http://node01.k8s.h-tsk.com:2379 \\
    --listen-peer-urls http://node01.k8s.h-tsk.com:2380 \\
    --initial-cluster-token my-etcd-token \\
    --initial-cluster-state new
[Install]
WantedBy=multi-user.target
EOF

1.2 etcdのインストール (残りmaster)

# ビルドされたファイルは転送してあるので、実行権限付与
$ sudo chmod 755 /usr/local/bin/etcd
$ sudo chmod 755 /usr/local/bin/etcdctl
# etcdのデータ保存用のディレクトリを作成
$ sudo mkdir -p /var/lib/etcd
$ sudo chown -R root:$(whoami) /var/lib/etcd
$ sudo chmod -R a+rw /var/lib/etcd
# systemdファイルを作成 (インストール先によってNODE_IDをかえる)
$ sudo su -
$$ export NODE_ID= 2 or 3
$$ cat > /etc/systemd/system/etcd.service <<EOF
[Unit]
Description=etcd
Documentation=https://github.com/coreos/etcd
After=network.target
[Service]
Type=notify
Restart=always
RestartSec=5s
LimitNOFILE=40000
TimeoutStartSec=0
Environment="ETCD_UNSUPPORTED_ARCH=arm"
ExecStart=/usr/local/bin/etcd --name etcd-${NODE_ID} \\
    --data-dir /var/lib/etcd \\
    --discovery-srv k8s.h-tsk.com \\
    --initial-advertise-peer-urls http://node0${NODE_ID}.k8s.h-tsk.com:2380 \\
    --advertise-client-urls http://node0${NODE_ID}.k8s.h-tsk.com:2379 \\
    --listen-client-urls http://127.0.0.1:2379,http://node0${NODE_ID}.k8s.h-tsk.com:2379 \\
    --listen-peer-urls http://node0${NODE_ID}.k8s.h-tsk.com:2380 \\
    --initial-cluster-token my-etcd-token \\
    --initial-cluster-state new
[Install]
WantedBy=multi-user.target
EOF

1.3 etcdの起動 (master)

etcdを2つ目のmasterを起動するまでは、1台目のstartコマンドは戻ってこないです。(2台でetcdクラスタが組めるまでは待機するらしい)
$ sudo systemctl start etcd
$ sudo systemctl enable etcd

2. flannelのインストール (master, node)


$ sudo apt-get install -y build-essential linux-libc-dev bridge-utils git curl ssh unzip
$ wget https://github.com/coreos/flannel/releases/download/v0.7.1/flannel-v0.7.1-linux-arm.tar.gz
$ tar zxf flannel-v0.7.1-linux-arm.tar.gz
$ sudo mkdir /opt/flanneld
$ sudo mv flanneld /usr/local/bin/flanneld
$ sudo mv mk-docker-opts.sh /opt/flanneld/mk-docker-opts.sh
$ sudo chmod 755 /usr/local/bin/flanneld
$ sudo chmod 755 /opt/flanneld/mk-docker-opts.sh
$ sudo su -
$$ mkdir -p /etc/flanneld
$$ export ADVERTISE_IP=192.168.13.1 # <- 設定する各masterのIPアドレス
$$ cat > /etc/flanneld/options.env << EOF
FLANNELD_IFACE=${ADVERTISE_IP}
FLANNELD_ETCD_ENDPOINTS=http://node01.k8s.h-tsk.com:2379,http://node02.k8s.h-tsk.com:2379,http://node02.k8s.h-tsk.com:2379
EOF
$$ cat > /etc/systemd/system/flanneld.service << EOF
[Unit]
Description=Network fabric for containers
Documentation=https://github.com/coreos/flannel
Requires=networking.service
Before=docker.service
After=networking.service
[Service]
Type=notify
Restart=always
RestartSec=5
EnvironmentFile=/etc/flanneld/options.env
LimitNOFILE=40000
LimitNPROC=1048576
ExecStartPre=/sbin/modprobe ip_tables
ExecStartPre=/bin/mkdir -p /run/flanneld
ExecStart=/usr/local/bin/flanneld --ip-masq=true
## Updating Docker options
ExecStartPost=/opt/flanneld/mk-docker-opts.sh -d /run/flanneld/docker_opts.env -i
[Install]
WantedBy=multi-user.target
EOF

3. flannelとdockerの連携設定 (master, node)

3.1 docker.serviceにflannelの設定をおこなう(master, node)

$ sudo cp /lib/systemd/system/docker.service /etc/systemd/system/docker.service
$ sudo sed -i "s/\[Service\]/\[Service\]\nEnvironmentFile=-\/run\/flanneld\/docker_opts.env/" /etc/systemd/system/docker.service
$ sudo sed -i "s/fd:\/\/$/fd:\/\/ \$DOCKER_OPTS \$DOCKER_OPT_BIP \$DOCKER_OPT_MTU \$DOCKER_OPT_IPMASQ/" /etc/systemd/system/docker.service

3.2 etcdにflannelの設定を入れる (masterの1台だけ)

$ etcdctl mk /coreos.com/network/config '{"Network":"172.17.0.0/16"}'

3.3 flannelとdockerを起動させる (master, node)

$ sudo systemctl daemon-reload
$ sudo systemctl start flanneld
$ sudo systemctl enable flanneld
$ sudo systemctl restart docker  
やっとkubernetesを動かす環境がセットアップできたので、次回はインストールをします。





kubernetesをRaspberry pi 3にインストールする(その1)

kubernetes 1.6がリリースされたので、出遅れ感もありながらRaspberry pi 3にインストールしてみる。

すでにhypriotkubeadmを組み合わせるとサクッとクラスタが作れるけど、勉強もかねて手動で全部入れることにします。

今回はRaspberry pi3を5台で、下記のような構成で設定します。


1. RaspberryPiにRaspbianのインストール (master, node共通)

インストール方法は有名なので省略。
注意点としては、最近のRaspbianはデフォルトでSSHが無効化されているので、boot領域に"ssh"の空ファイルをおいて、有効化させておくこと。

2. ネットワークの設定 (master, node共通)

今回のネットワークハブは5ポートでRasPiが5台だと、有線で外部接続ができないのでmasterにする1台をNATゲートウェイします。

2.1 RasPiに固定IPの設定 (master, node共通)

知らない間に固定IPの方法が "/etc/network/interfaces" から "/etc/dhcpcd.conf" 変わったらしい... 
"/etc/network/interfaces"にこんなコメント入ってた
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'

"/etc/dhcpcd.conf"にeth0の設定を入れますが、有線LANはeth0で認識するみたいなので確認せず入れちゃう。
$ cat <<EOF >> /etc/dhcpcd.confinterface eth0static ip_address=192.168.13.12/24   # <- ここはそれぞれの固定IPstatic routers=192.168.13.1                # <- NATゲートウェイにする1台だけは、設定しないのでコメントアウトstatic domain_name_servers=192.168.13.1 # <- DNSサーバを建てるところのIP(後述)EOF
※ここでOS再起動させると固定IPに変わるけど、DNSサーバを立ててないので外に繋がらなくなります....

2.2 NATゲートウェイの設定 (masterの1台だけ)

RasPiはNICが1つしかないので、USBのNICを追加(Wifiでも良いけど遅い気がするので...)して設定します。

RasPiについているNICは "eth0" で認識されていて、USB増設した方は "eth1" になっていてDHCPでIPアドレスが取れてます。
$ ip addr | grep -e "eth[0-9]"
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 192.168.1.41/24 brd 192.168.1.255 scope global eth0
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    inet 192.168.1.42/24 brd 192.168.1.255 scope global eth1
これを "eth0" (192.168.13.1 [固定IP]) <---> "eth1" (192.168.1.xx [DHCP])でNATゲートウェイに替えます。

あとは先人のUbuntu 14.04のルーター化に書かれているとおり黙々と設定します。
$ sudo vi /etc/sysctl.conf
#net.ipv4.ip_forward=1
↓ (コメントアウトを外す)
net.ipv4.ip_forward=1
 
$ sudo /sbin/iptables -t nat -A POSTROUTING -s 192.168.13.0/255.255.255.0 -j MASQUERADE
$ sudo /sbin/iptables-save -c > /etc/iptables.rules
$ cat <<EOF >> /etc/network/if-pre-up.d/iptables_start
#!/bin/sh
/sbin/iptables-restore < /etc/iptables.rules
exit 0
EOF
$ sudo chmod +x 
/etc/network/if-pre-up.d/iptables_start

3. OSの初期設定 (master, node共通)

ここは全部rootユーザに昇格してコマンド実行します。sudo打つのが面倒なので、、、
# piユーザーのパスワード変更
$ passwd pi
# cgroupを有効化
$ sed -ie 's/rootwait/cgroup_enable=cpuset cgroup_enable=memory rootwait/' /boot/cmdline.txt
# docker公式にしたがってインストール$ curl -sSL https://get.docker.com | sh$ gpasswd -a pi docker
# raspi-configでHostnameとかTimeZoneとか
$ raspi-config

4. 設定反映のために各RasPiを再起動すると、固定IPで接続できるはず。

5. DNSサーバの設定  (masterのNATゲートウェイの1台だけ)

dnsmasqをDNSサーバにして、RasPiのネットワークから外部DNSに問い合わせるためと、etcdのDNSディスカバリのために設定を入れます。

今回は "k8s.h-tsk.com" を内部ネットワーク用のサブドメインで使います。


$ sudo apt-get install -y dnsmasq dnsutils 
$ sudo /etc/dnsmasq.conf# 以下の項目をコメントアウトを外して修正domain-neededbogus-privstrict-orderlocal=/k8s.h-tsk.com/expand-hostsdomain=k8s.h-tsk.com
# 以下の項目をetcd公式にしたがって追加 (node01~03をetcdクラスタにします)srv-host=_etcd-server._tcp.k8s.h-tsk.com,node01.k8s.h-tsk.com,2380srv-host=_etcd-server._tcp.k8s.h-tsk.com,node02.k8s.h-tsk.com,2380srv-host=_etcd-server._tcp.k8s.h-tsk.com,node03.k8s.h-tsk.com,2380srv-host=_etcd-client._tcp.k8s.h-tsk.com,node01.k8s.h-tsk.com,2379srv-host=_etcd-client._tcp.k8s.h-tsk.com,node02.k8s.h-tsk.com,2379srv-host=_etcd-client._tcp.k8s.h-tsk.com,node03.k8s.h-tsk.com,2379 
# 各RasPiのIPアドレスをhosts$ cat <<EOF >> /etc/hosts192.168.13.1 k8s-node01 node01192.168.13.12 k8s-node02 node02192.168.13.13 k8s-node03 node03192.168.13.14 k8s-node04 node04192.168.13.15 k8s-node05 node05EOF 
$ systemctl start dnsmasq$ systemctl enable dnsmasq

6 DNSが動いているか確認  (masterのNATゲートウェイの1台だけ)

# 全部のRasPiのIPアドレスが取れるはず$ dig +noall +answer node01.k8s.h-tsk.com node02.k8s.h-tsk.com node03.k8s.h-tsk.com node04.k8s.h-tsk.com node05.k8s.h-tsk.comnode01.k8s.h-tsk.com. 0 IN A 192.168.13.1node02.k8s.h-tsk.com. 0 IN A 192.168.13.12node03.k8s.h-tsk.com. 0 IN A 192.168.13.13node04.k8s.h-tsk.com. 0 IN A 192.168.13.14node05.k8s.h-tsk.com. 0 IN A 192.168.13.15
# etcdクラスタに入れるmasterの3台分が取れるはず$ dig +noall +answer SRV _etcd-server._tcp.k8s.h-tsk.com_etcd-server._tcp.k8s.h-tsk.com. 0 IN SRV 0 0 2380 node03.k8s.h-tsk.com._etcd-server._tcp.k8s.h-tsk.com. 0 IN SRV 0 0 2380 node02.k8s.h-tsk.com._etcd-server._tcp.k8s.h-tsk.com. 0 IN SRV 0 0 2380 node01.k8s.h-tsk.com.$ dig +noall +answer SRV _etcd-client._tcp.k8s.h-tsk.com_etcd-client._tcp.k8s.h-tsk.com. 0 IN SRV 0 0 2379 node03.k8s.h-tsk.com._etcd-client._tcp.k8s.h-tsk.com. 0 IN SRV 0 0 2379 node02.k8s.h-tsk.com._etcd-client._tcp.k8s.h-tsk.com. 0 IN SRV 0 0 2379 node01.k8s.h-tsk.com.

長くなったので、etcdとflannelのインストールとkubernetesのインストールは分けます。




参考:
  1. dnsmasqで始めるプライベートDNSサーバ
  2. Providing SRV and TXT records for Kerberos and LDAP with dnsmasq
  3. raspberry pi 3でSSH接続できない?
  4. Installing Kubernetes on ARM with kubeadm