KubeEdge環境を構築してみた by AWS EC2

# TL;DR

KubeEdgeの公式手順に従ってKubeEdge環境をEC2インスタンス上に構築してみた
基本的には参考サイトに載っている手順に準じて構築している
構築までしかしていないので悪しからず！

## そもそもKubeEdgeとは？

CNCF(Cloud Native Computing Foundation)の配下で最近GAされたエッジコンピューティングフレイムワークのOSS
→ [詳しくはこちら](https://github.com/kubeedge/kubeedge)  
Kubernetes(以下、k8s)もCNCFによりGAされており、いわば本家お墨付きのようなエッジ用k8s
似たようなので、Rancherのk3sがある → [GitHub](https://github.com/rancher/k3s)

## はじめに

KubeEdge環境の構築には主に3通りの方法がある(詳しくはGHのUsage参照)

* 用意されたバイナリを実行し、k8s環境から全て自動構築する
* k8sの環境を自前で構築し、 リリースパッケージを使って構築する
* k8s環境を自前で構築し、ソースからビルドして構築する

今回は2つ目の方法で構築している、なぜか？
答え単純、1つ目の方法で上手くいかなかったからである！
※筆者は3回やって挫折
3度目に失敗してから「もう自分でやったほうが早いな」と思い至り2番目の方法で構築したらすんなりできた

## 環境

今回は構築方法までなのでエッジ側もAWSのEC2インスタンスでお手軽に構築してみた
本来ならエッジ側はラズパイなどのデバイスになるはずである
以下、環境情報

### バージョン

全て最新版を使用した(2019年8月時点)

* Docker: 19.03.1
* Kubernetes: 1.15.2
* kubeedge: 1.0.0

### マシンスペック

マスタを大きく設定したけど、こんなにいらなかった
これならローカルのVMでも動かせそうである

* master
  * OS: Ubuntu 18.04 LTS
  * CPU: 8
  * Memory: 32GB
  * Storage: 30GiB

稼働状況

```txt
Allocated resources:
  (Total limits may be over 100 percent, i.e., overcommitted.)
  Resource           Requests    Limits
  --------           --------    ------
  cpu                850m (21%)  100m (2%)
  memory             190Mi (1%)  390Mi (2%)
  ephemeral-storage  0 (0%)      0 (0%)
```

* worker
  * OS: Ubuntu 18.04 LTS
  * CPU: 2
  * Memory: 4GB
  * Storage: 15GiB

## 構築手順

本題である構築手順！
EC2インスタンスの立て方については書かないので悪しからず
公式に従い「kubeadm」でk8sクラスタを構築する

### 共通

まずは必須であるDockerとk8s関連のパッケージをそれぞれにインストールする

```bash
sudo apt update
sudo apt upgrade -y  # アップグレードは筆者の好み、正直しない方がいいかもしれない

# docker
sudo su -
apt-get update && apt-get install apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
add-apt-repository \
  "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) \
  stable"
apt-get update && apt-get install docker-ce

cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF
mkdir -p /etc/systemd/system/docker.service.d
systemctl daemon-reload
systemctl restart docker
systemctl status docker

# k8s関連
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

echo 'KUBELET_EXTRA_ARGS=--cgroup-driver=systemd' > /etc/default/kubelet

systemctl daemon-reload
systemctl restart kubelet
systemctl status kubelet  # まだkubeletは動かないが問題ない
```

### マスタ

共通の構築ができたらまずはマスタを構築する
今回はCNIにArmでも動く「flannel」を使う

```bash
sudo su -

# for flannel
kubeadm init --pod-network-cidr=10.244.0.0/16
sysctl -w net.bridge.bridge-nf-call-iptables=1

# KubeEdge用に編集する
vim /etc/kubernetes/manifests/kube-apiserver.yaml
- - --insecure-port=0
+ - --insecure-port=8080
+ - --insecure-bind-address=0.0.0.0

# flannelのPodをデプロイする
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
kubectl label nodes ip-172-31-38-225 type=master
kubectl get nodes -L type  # StatusがReadyになっているはず

# KubeEdgeで使うCRDをデプロイする
wget -L https://raw.githubusercontent.com/kubeedge/kubeedge/release-1.0/build/crds/devices/devices_v1alpha1_devicemodel.yaml
kubectl create -f devices_v1alpha1_devicemodel.yaml
wget -L https://raw.githubusercontent.com/kubeedge/kubeedge/release-1.0/build/crds/devices/devices_v1alpha1_device.yaml
kubectl create -f devices_v1alpha1_device.yaml

# KubeEdgeのリリースパッケージをダウンロード
curl -LO https://github.com/kubeedge/kubeedge/releases/download/v1.0.0/kubeedge-v1.0.0-linux-amd64.tar.gz
tar -xf kubeedge-v1.0.0-linux-amd64.tar.gz -C /etc
mv /etc/kubeedge-v1.0.0-linux-amd64 /etc/kubeedge

# KubeEdgeで使う証明書を発行
wget -L https://raw.githubusercontent.com/kubeedge/kubeedge/release-1.0/build/tools/certgen.sh
chmod +x certgen.sh
bash -x ./certgen.sh genCertAndKey edge

# マスタ側のKubeEdgeを起動する
cd /etc/kubeedge/cloud
nohup ./edgecontroller > edgecontroller.log 2>&1 &
tail edgecontroller.log

# エッジ側に同じものを送るためにコピーしておく
cp -r /etc/kubeedge /home/ubuntu
chown ubuntu:ubuntu /home/ubuntu/kubeedge -R
```

### ローカル

今回はマスタ側で発行した証明書などをエッジ側にも置くためにローカルからSCPでコピーして送った
※マスタとエッジが直接SSHできるならこれはいらない

```bash
scp -r -i ~/.ssh/aws/admin.pem ubuntu@<master-ip>:/home/ubuntu/kubeedge ~/
scp -r -i ~/.ssh/aws/admin.pem /home/ubuntu/kubeedge ubuntu@<edge-ip>:/home/ubuntu/
```

### エッジ

さて、マスタが構築できたらエッジを構築したk8sクラスタに参加させる
※「kubectl」をマスタ側で叩いているが、エッジでも叩けるようにすればどちらでも問題ない
→ [詳しくはこちら](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/#optional-controlling-your-cluster-from-machines-other-than-the-control-plane-node)

```bash
sudo su -

# 送っておいたファイルを適切な場所に置いておく
cp -r /home/ubuntu/kubeedge /etc
chown root:root /etc/kubeedge -R

# 構築したクラスタに参加させる ※適宜置き換える
kubeadm join 172.31.38.225:6443 --token <token> \
    --discovery-token-ca-cert-hash sha256:<ca-cert-hash>

# in master
# nodeの名前は適宜置き換える
kubectl get nodes  # 新しくnodeが追加されているはず
kubectl label node ip-172-31-39-8 type=worker
wget -L https://raw.githubusercontent.com/kubeedge/kubeedge/release-1.0/build/node.json
vim node.json
- name: "fb4ebb70-2783-42b8-b3ef-63e2fd6d242e",
+ name: "ip-172-31-39-8",
kubectl apply -f node.json

# エッジ側のKubeEdgeを起動する
cd /etc/kubeedge/edge
vim conf/edge.yaml  # nodeの名前を適切に修正する
- url: wss://172.31.38.225:10000/e632aba927ea4ac2b575ec1603d56f10/fb4ebb70-2783-42b8-b3ef-63e2fd6d242e/events
+ url: wss://172.31.38.225:10000/e632aba927ea4ac2b575ec1603d56f10/ip-172-31-39-8/events
- node-id: fb4ebb70-2783-42b8-b3ef-63e2fd6d242e
+ node-id: ip-172-31-39-8
- hostname-override: fb4ebb70-2783-42b8-b3ef-63e2fd6d242e
+ hostname-override: ip-172-31-39-8
nohup ./edge_core > edge_core.log 2>&1 &
tail edge_core.log
```

### テスト

最後にちゃんと動いてるか、簡単に確認する

```bash
kubectl apply -f https://raw.githubusercontent.com/kubeedge/kubeedge/release-1.0/build/deployment.yaml
kubectl get pods
kubectl get deploy
```

## おわりに

とりあえず動くものを構築してみた
最初の方にも書いたが、参考サイトに従って構築したので不明な点は参考サイトを参照してほしい
正直KubeEdge自体が正しく動いているか、確信が持ててない．．．
故に次は、KubeEdgeのExampleを試してみたいと思う
→ <https://github.com/kubeedge/examples/tree/master/led-raspberrypi>

# 参考

* docker
    * <https://kubernetes.io/docs/setup/production-environment/container-runtimes>
* kubeadm(+flannel)
  * <https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm>
  * <https://github.com/coreos/flannel> 
* KubeEdge
    * <https://github.com/kubeedge/kubeedge/blob/master/docs/getting-started/release_package.md>