Ubuntu 18.04 LTS にKubernetes環境をインストールする [Master / Worker]

この記事は、「[オンプレミス、Kubernetesで、マイクロサービスを意識したWebアプリをデプロイするまでの軌跡](https://qiita.com/soumi/items/2ef65b0d6e3fb562451e)」の一部です。

## はじめに

Kubernetesをインストールする方法は色々あるようで、最近では比較的簡単にインストールできる環境も整ってきているようです。
フルスクラッチで必要なデーモンを一つ一つ手動でインストールしていくという方法もあるようですが、かなり道のりが遠そうだったので、今回は```kubeadm```という公式でも紹介されているツールを使う事にしました。
ですので、一つ一つのサービスの詳細までは僕は分かっていません。とりあえずこの手順でインストールしたら動いた、というものをまとめようと思います。

### 今回目指す構成

この記事では

**Master + Workerノード1つ**

という構成を目指しますが、Masterだけでもとりあえず動作させる事ができるので、そちらも併せて紹介しようと思います。
(といってもコマンド一つなのですが)

### 表記の注意

Masterノード端末とWorkerノード端末両方で作業する必要があり、タイトルの表記で

- Masterノードでする作業を **[M]**
- Workerノードでする作業を **[W]**  

と表記する事で区別しています。

### 環境

MasterもWorkerも、

Ubuntu 18.04 LTS
(仮想環境上で動作)

上に構築していきます。

## [M/W] Dockerをインストール

KubernetesはDockerをはじめとしたコンテナのオーケストレーションツールなので、まずはDockerをインストールします。
Dockerの導入記事は[以前書いた](https://qiita.com/soumi/items/5b01d88c187b678c0474)ので参照しながら導入していってください。docker-composeは使わないので省いて構いません。

### インストールしたDockerのバージョンが合わない場合

次項で説明する ```kubeadam init``` を実行した際、「バージョンが違うのでインストールできない」という旨のエラーが出る事があります。ワーニングで済む場合もありますが、それで正しく動くとは限らないので注意が必要です。

僕が構築した時はここで引っかかったのですが、最新のDockerバージョンにKubernetesが対応していない事があります。
その時はDockerのバージョンを対応しているものに変えてインストールして下さい。

```shell
$ sudo service docker stop
$ sudo apt install docker-ce=18.06.0~ce~3-0~ubuntu
```

また、

> detected "cgroupfs" as the Docker cgroup driver

のようなワーニングが出たら、以下のサイトを参照してみて下さい。

https://kubernetes.io/docs/setup/production-environment/container-runtimes/

## [M/W] Kubernetesをインストール

今回は```kubeadm```を使用してインストールするので、まずは```kubeadm```をインストールする必要があります。

デフォルトのリポジトリに```kubeadm```が無いので、まずkubernetes のキーとリポジトリを登録して

```shell
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
$ sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main"
```

その後、```kubeadm```をインストールします。

```shell
$ sudo apt update
$ sudo apt install kubeadm
```

Kubernetes1.8から```swap```をオフにしないとちゃんと必要な機能が起動しないようになったそうなので、 ```swap```をオフにします。 

```shell
$ sudo swapoff -a
```

ちゃんと理解していないですが、以前はこの設定をしなくても動作していたものの、```swap```が起動しているとそれが原因で動作が遅くなる事があるそうで、Kubernetesの仕様として```swap```がオフでないと```kubelet```という必須サービスが起動しないようになったそうです。

ちなみに、↑のコマンドで```swap```をオフにした場合、ホストのOS再起動後に再び有効になりますのでご注意を。

# [M] Kubernetesをセットアップ

いよいよkubernetesをインストールします！
…といっても```kubeadm```を使うので、数手でインストール完了してしまいます。

flannel 用にオプション付きで init します。

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

インストールの最後に完了メッセージとともに、次のステップについても説明が表示されます。
この中にはWorkerのノードを追加するために必要な情報も含まれています。

```shell
## 略
 Your Kubernetes master 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 
   https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of machines by running the following on each node
as root:
kubeadm join 10.114.51.231:6443 --token xxxxxx.xxxxxxxxxxxxx --discovery-token-ca-cert-hash sha256:xxxxxxx
```

ちゃんと言われたとおりに実行します。
(僕は最初これを読み飛ばして色々と苦労しました…)

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

これでKubernetesから言われたことは全て実行したので、一度ノードの様子を見てみます。

```shell
$ kubectl get nodes

NAME     STATUS     ROLES    AGE   VERSION
master   NotReady   master   50s   v1.12.2

```

この時点ではNotReadyですが、きちんとノードが存在しています。

flannelのためにiptablesを編集します。
これをしないと、後で作られる```core-dns```というPodが永遠にCrashLoopBackOff状態になって起動しません。
(ここでハマりました…)

```shell
sudo sysctl net.bridge.bridge-nf-call-iptables=1
```

設定後、満を持してflannel を入れます。

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

しばらくすると、nodeの状態がReadyに変わります。

```shell
$ kubectl get nodes

NAME     STATUS   ROLES    AGE     VERSION
master   Ready    master   2m36s   v1.12.2

```

マスターの基本的な設定はこれで終わりです。

### Masterノードにもデプロイしたい場合は

デフォルト状態ではMasterノードにデプロイする事が出来ません。
以下のコマンドを実行する事で、Masterノードにもデプロイすることが出来ます。

```shell
$ kubectl taint nodes <名前空間> node-role.kubernetes.io/master:NoSchedule-
```

Workerノードを追加せずにMasterノードのみで運用する場合はこれで完了です。
お疲れ様でした。

## [W] Masterノードにjoinする

Masterノードをセットアップした時に表示された情報を元に、以下のコマンドを実行します。

```shell
$ sudo kubeadm join 10.114.51.231:6443 --token xxxxxx.xxxxxxxxxxxxx --discovery-token-ca-cert-hash sha256:xxxxxxx
```

```--token``` と ```--discovery-token-ca-cert-hash``` は、Kubernetesセットアップが完了した時に表示されていたものを使います。
…というよりセットアップ完了時、Workerノードで実行するべきコマンドが表示されるので、そのままコピペでOKです。

しかし、あまり時間が経過し過ぎるとトークンが無効になってしまいます。
その場合は以下のコマンドで再度取得できます。

**--discovery-token-ca-cert-hash**

```shell
$ openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
```

**--token**

```shell
$ kubeadm token create
```

## [M] Workerノードの参加を確認

Workerで参加のコマンドを実行して、成功したらMasterに戻ってきましょう。
上手くいっていれば、ノードを取得した際に今追加したWorkerノードが見えてきます。

```shell
$ kubectl get nodes

NAME     STATUS   ROLES    AGE   VERSION
master   Ready    master   23m   v1.12.2
node1    Ready    <none>   21m   v1.12.2
```

基本的な準備はこれで完了です。
お疲れさまでした！

## [M] Dashboardをインストール(おまけ)

Kubernetesは基本的に```kubectl```というコマンドを実行して操作するのですが、Web画面上で現在の設定や動作状況を確認したり、簡単なコマンドを実行できるソフトウェアがあります。これもKubernetes上で動作するので、以下で導入方法を紹介します。

まずyamlをDLしてきます。

```shell
$ wget https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/alternative/kubernetes-dashboard.yaml
```

DLしてきたファイルを一部編集します。

```yaml
# ------------------- Dashboard Service ------------------- #

kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kube-system
spec:
  type: NodePort     <------ ここを追加
  ports:
  - port: 80
    targetPort: 9090
    nodePort: 32002     <------ ここを追加
  selector:
    k8s-app: kubernetes-dashboard
```

編集したyamlをkubectlコマンドでデプロイ。

```shell
$ kubectl create -f kubernetes-dashboard.yaml 
```

これでダッシュボードがデプロイされましたが、デフォルトではアクセス制限があるため、ダッシュボードの全機能にアクセスできません。

以下のようなyamlを作成して、サービスアカウントの準備をします。

***service-account.yaml***

```yaml
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: kubernetes-dashboard
  labels:
    k8s-app: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: kubernetes-dashboard
  namespace: kube-system
```

そしてサービスアカウント作成。

```shell
$ kubectl apply -f service-account.yaml
```

この状態で以下のアドレスにアクセスすると、ダッシュボードが見えます。

```shell
サーバーip:32002
```


![dashboard.png](https://qiita-image-store.s3.amazonaws.com/0/321330/2511affb-3bd1-2d58-7611-e89a5f7274d6.png)


この設定だと、アクセスした人が全員ダッシュボードのフル機能にアクセスできるっぽいので、適切に権限を設定するか、不要な時はダッシュボードを削除するかする必要がありそうです。
前者は僕には難しそうなので、後者にで運用する事になりそうです…

## 参考記事

### Docker

[以前の記事](https://qiita.com/soumi/items/5b01d88c187b678c0474)

### Kubernetes

[Ubuntu 18.04 に kubernetes をインストールする](https://qiita.com/ysaito8015@github/items/26a208f9c482b2d2d24a)
[kubeadmを使ってオンプレミスのプロキシ環境下にKubernetesクラスタをデプロイする(CentOS 7.3)](https://qiita.com/k-srkw/items/7a4c6be6c3e3fbf3c23c)
[Creating a single master cluster with kubeadm](https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/)
[Kubernetes v1.8: Before Upgrading](https://qiita.com/tkusumi/items/0962220a0700cb1f6eb3)

### Dashboard

[Kubernetes 1.10 Dashboard設定](https://qiita.com/sugimount/items/689b7cd172c7eaf1235f)
[Kubernetes Dashboardにcluster-admin権限でSign inする](https://qiita.com/h-sakano/items/79bb15f7a0661e141c75)