Kubernetes・Rancherハンズオン on さくらのクラウドv19.01

# 概要

[Kubernetes](https://kubernetes.io/) でコンテナのオーケストレーション概念を把握するために、kubernetes 構築方法の理解と基本的なコマンド操作を行います。

- Rancher で Kubernetes の動作環境を構築する

![archi01.png](https://qiita-image-store.s3.amazonaws.com/0/13002/4ee44b01-c39f-83e5-7c82-81a67ea48a52.png)


- Kubernetes クラスタを kubectl / kubeadm で構築する

![arch02.png](https://qiita-image-store.s3.amazonaws.com/0/13002/53c3cd37-78df-c651-4bb7-f30fcfbc29e8.png)


以上の作業を[さくらのクラウド](https://cloud.sakura.ad.jp/)上の[VPCルータ](https://manual.sakura.ad.jp/cloud/network/vpc-router/index.html)配下のネットワーク上で構築します。

- Rancher 選定の理由…クラスタ状態やサービス等の状況を把握するためには、kubernetes の [Dashoboard UI](https://github.com/kubernetes/dashboard)よりも初期設定やユーザ権限に関する設定が簡単であり、学習に最適なため。
- VPCルータ on さくらのクラウド選定の理由…ローカル・ネットワーク上にKubernetesクラスタを構築したり、ネットワーク上のサービスをインターネット側へ公開するために、VPCルータのネットワーク・モデルが一般的な学内・社内・家庭内と共通する汎用性があり、Kubernetes学習のためのオーバーヘッドを減らすため。

# A. Rancher 環境構築編

## A1. スタートアップスクリプトで Rancher を起動

### A1-1. さくらのクラウドにログイン

[コントロールパネル](https://secure.sakura.ad.jp/cloud/) https://secure.sakura.ad.jp/cloud/ にアクセスします。
画面右側 `さくらのクラウドユーザとしてログイン` へ配布済みのユーザ情報でログインします。

### A1-2. API キーの作成

1.「ホーム」から左メニュー `APIキー` を選び、アカウント名をクリックした後、 `追加` をクリック。
2.`名前` に rancher など何らかの文字列を入れて `作成` をクリック。

### A1-3. Rancher ホストの起動

1.「ホーム」から `さくらのクラウド(IaaS)` をクリック
2.`サーバ`から`追加`をクリック
3.`シンプルモード`のチェックを外す
4.`2コア`/`4GB`を選択
5.「アーカイブ選択」で`CentOS 7.5`を選び`OK`
6.「管理ユーザのパスワード」（任意）を入力
7.「ホスト名」は `rancher` とする
8.「スタートアップスクリプト」は`shell`を選び、`Rancher2セットアップ`にする
9.`Rancher管理ユーザのパスワード`（admin)を入力し、`APIキー`を選択
10.サーバの情報 `rancher`
11.最後に`作成`をクリック

### A1-4. Rancher 確認・さくらのクラウドに kubernetes をデプロイ

`https://<ip>/` にアクセスすると、管理画面が出ます。

ノードは「Add Cluster」で「さくらのクラウド」を追加できます。

note:

```
yum install kubernetes-client
kubectl get nodes
```

# B. Kubernetes 環境構築編

## B1. VPCルータと仮想サーバの作成

### B1-1. 「VPCルータ」を作成

「VPCルータ」機能を使い、クラウド上に外から直接接続できないローカル・ネットワークを構築します。

1. メニューから `VPCルータ`->`追加` をクリック 
2. 「名前」は `myvpc`
3. `作成` をクリック


作成後「有効状態」が「コピー中」から「利用可能」になるまで待ちます。

メニューから `マップ` をクリックすると、画面上にどのように表示されていますか。

### B1-2. 「スイッチ」を作成

VPCルータのネットワークは以下に複数の仮想サーバを置きます。

1. メニューから `ネットワーク`->`スイッチ`をクリック
2. `追加`をクリック
3. 「名前」に `192.168.0.0/24` を入力
4. `作成` をクリック

メニューから `マップ` をクリックすると、画面上にどのように表示されていますか。

### B1-3. VPCルータにスイッチを接続して起動

1. メニューから `アプライアンス` -> `VPCルータ`
2. 「VPCルータ一覧」で `myvpc` をダブルクリック（コピー中の表示の場合は、再読み込みボタンをクリック）
3. `インターフェース` タブをクリックし、「グローバル」にある「IPアドレス」をメモ（後で SSH やブラウザでの表示に使います）
4. 「プライベート１」にある `鉛筆アイコン` をクリックします
5. `既存スイッチを接続`： 「接続先スイッチ」を ``192.168.0.0/24`
6. 「IPアドレス」を `192.168.0.1`
7. 「プリフィックス」を `/24`
7. `更新` をクリック 
8. `反映` をクリック
9. `電源操作` -> `起動` を選び、VPC ルータを起動

メニューから `マップ` をクリックすると、画面上にどのように表示されていますか。

### B1-4. Kubernetes クラスタ用サーバの作成

ここでは3台の仮想マシンを作成します。いずれのサーバのeth0インターフェースを VPC ルータ配下の `192.168.0.0/24` スイッチに対して接続します。

- Kubernetes 用の仮想マシン3台 (192.168.0.21～23）

1. メニューから `サーバ` -> `追加` をクリック
2. 「シンプルモード」を有効化し（チェックボックスが入った状態）で、 `CoreOS Container Linux` を選択し、 `4 GB / 2 仮想コア` を選択
3. 「接続先のネットワーク」を `スイッチ` にし、 `192.168.0.0/24` を選択
4. 「サーバの設定」で「IPアドレスの設定」を `固定IPアドレスの利用` を選択
5. 「IPアドレス」は `192.168.0.21`
6. 「ネットマスク」は `24`（デフォルト）
7. 「ゲートウェイ」は `192.168.0.1`（VPCルータ側）を入力
8. 「管理ユーザのパスワード」（英数字・記号混在が望ましい）を入力
9. 「ホスト名」は `kube1` と入力
10. `作成` をクリック
11. 「確認画面」で `作成` をクリックし `閉じる` をクリック
12. 手順5～11 を繰り返し、worker を作成する。以下のIPアドレス・ホスト名で繰り返す。

- 192.168.0.21 - kube1 (Kubernetes Masterとして利用・作成済み) 
- 192.168.0.22 - kube2 (worker)
- 192.168.0.23 - kube3 (worker)

メニューから `マップ` をクリックすると、画面上にどのように表示されていますか。

## B2. Kubernetes セットアップ

「192.168.0.21」を作業用サーバとして使います。VPC ルータ以下のネットワークには直接ログインできません。リモートアクセス（PPTPまたはL2TP/IPsec）用のアカウントを作成するか、インターネット側から SSH 用のポートを NAT します。それから Rancher を動かすために Docker をセットアップします。

### B2-1. 作業用サーバに SSH ログイン

1. メニュー `アプライアンス` -> `VPCルータ` から `NAT` タブをクリックし、`追加` をクリック
2. プロトコル `TCP` 、「グローバル側ポート番号」`10022`、「プライベート側IPアドレス」`192.168.0.21`、「プライベート側IPアドレス」`22`を入力し、`追加`
3. `反映` をクリック
4. `ssh -l core <VPCルータのIP> -p 10022` を入力して kube1(192.168.0.21) にログイン

`traceroute www.sakura.ad.jp` や `ip route` コマンドを実行して、何か気づきますか？

補足情報：Container Linux のバージョンアップを手動で行う場合は ` update_engine_client -check_for_update` を実行し、`update_engine_client -status` で状況確認の後、 `sudo reboot` で再起動。

### B2-2. Docker の確認

1.`docker version` を実行し、`Server:` 行が表示されるのを確認します。

```
$ docker version
Client:
 Version:           18.06.1-ce
 API version:       1.38
 Go version:        go1.10.4
 Git commit:        e68fc7a
 Built:             Tue Aug 21 17:16:31 2018
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.06.1-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.4
  Git commit:       e68fc7a
  Built:            Tue Aug 21 17:16:31 2018
  OS/Arch:          linux/amd64
  Experimental:     false
```

## B3. Kubernetes セットアップとクラスタ構築

kube1(192.168.0.21)を経由して、kuberntesサーバにログインし、kubeletやkubeadmなど関連パッケージをセットアップします。

### B3-1. 初期セットアップ

Kubernetes の CNI (Container Network Interface) は [Calico](https://www.projectcalico.org/) を使います。

1.kube1(192.168.0.21)を起点に、kube2(192.168.0.22)、kube3(192.168.0.23)、の各サーバに SSH でログインします。このとき `ssh-keygen` と `ssh-copy-id` コマンドで SSH 認証鍵の作成とコピーをしておくと便利です。

2.ログイン後は環境を確認します。

* `docker version`
* `free`

3.それから各サーバで`sudo su -` を実行

4.ディレクトリ作成 `mkdir -p /opt/cni/bin`

5.以下の手順で、kubeadm と kubelet などのセットアップ用コマンドの実行

CNIプラグインのセットアップ：

```
CNI_VERSION="v0.7.4"
mkdir -p /opt/cni/bin
curl -L "https://github.com/containernetworking/plugins/releases/download/${CNI_VERSION}/cni-plugins-amd64-${CNI_VERSION}.tgz" | tar -C /opt/cni/bin -xz
```

kubeadm を動かすために必要な crictl (Kubelet container Runtime interface) をインストール：

```
CRICTL_VERSION="v1.13.0"
mkdir -p /opt/bin
curl -L "https://github.com/kubernetes-incubator/cri-tools/releases/download/${CRICTL_VERSION}/crictl-${CRICTL_VERSION}-linux-amd64.tar.gz" | tar -C /opt/bin -xz
```

`crictl` のバージョン確認：

```
$ crictl -v
```

それから「kubeadm」「kubelet」「kubectl」「kubelet」をsystemd に入れる：

```
RELEASE="$(curl -sSL https://dl.k8s.io/release/stable.txt)"

mkdir -p /opt/bin
cd /opt/bin
curl -L --remote-name-all https://storage.googleapis.com/kubernetes-release/release/${RELEASE}/bin/linux/amd64/{kubeadm,kubelet,kubectl}
chmod +x {kubeadm,kubelet,kubectl}
```

systemd 用の設定ファイル設置と kubelet の起動：

```
curl -sSL "https://raw.githubusercontent.com/kubernetes/kubernetes/${RELEASE}/build/debs/kubelet.service" | sed "s:/usr/bin:/opt/bin:g" > /etc/systemd/system/kubelet.service
mkdir -p /etc/systemd/system/kubelet.service.d
curl -sSL "https://raw.githubusercontent.com/kubernetes/kubernetes/${RELEASE}/build/debs/10-kubeadm.conf" | sed "s:/usr/bin:/opt/bin:g" > /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
systemctl enable kubelet && systemctl start kubelet
```

※この時点で kubelet は正常起動できませんが、問題ありません（起動に必要なファイルがないため、起動と停止を繰り返します）。


6.kube1 のみクラスタ初期化コマンドを実行します。

```
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 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 at:
  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 192.168.0.21:6443 --token n5f3gr.c3enfuqrftc6tvqw --discovery-token-ca-cert-hash sha256:e0fff6e419121483a453a3cb886882dd9b9fb64ec3ac16a38b32c8c11704271b
```

最後の「kubeadm join」行の文字列をエディタ等に控えておきます（あとで kube2 と kube3 をクラスタに追加するときに使います）。

7.一般ユーザに戻り、kubectl 用の設定ファイルをコピーします。

```
exit
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown core:core $HOME/.kube/config
```

8.`kubectl version` を実行します。

```
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"12", GitVersion:"v1.12.3", GitCommit:"435f92c719f279a3a67808c80521ea17d5715c66", GitTreeState:"clean", BuildDate:"2018-11-26T12:57:14Z", GoVersion:"go1.10.4", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"12", GitVersion:"v1.12.3", GitCommit:"435f92c719f279a3a67808c80521ea17d5715c66", GitTreeState:"clean", BuildDate:"2018-11-26T12:46:57Z", GoVersion:"go1.10.4", Compiler:"gc", Platform:"linux/amd64"}
```

9.ノード一覧を表示します。

```
$ kubectl get nodes
NAME    STATUS     ROLES    AGE     VERSION
kube1   NotReady   master   4m51s   v1.12.3
```

10.CoreDNS の Pod が起動していないのを確認します。どのような状態ですか？


```
# kubectl get pods --all-namespaces
NAMESPACE     NAME                            READY     STATUS    RESTARTS   AGE
kube-system   coredns-78fcdf6894-drjc4        0/1       Pending   0          4m
kube-system   coredns-78fcdf6894-xs7tm        0/1       Pending   0          4m
kube-system   etcd-kube1                      1/1       Running   0          3m
kube-system   kube-apiserver-kube1            1/1       Running   0          3m
kube-system   kube-controller-manager-kube1   1/1       Running   0          3m
kube-system   kube-proxy-mnqzt                1/1       Running   0          4m
kube-system   kube-scheduler-kube1            1/1       Running   0          3m
```

11.CNI の Calico をセットアップ（デプロイ）します。

```
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml
```

それから

```
kubectl get pods --all-namespaces
watch -n 1 !!
```

を実行して様子を見ます。どのような変化がありますか？(正常であれば、calico-node → coredns の順番でポッドが起動します)

### B3-2. workerノードの追加（クラスタ形成）

1.kube1(192.168.0.21)ではノード一覧を表示し続けます。

```
kubectl get nodes
watch -n 1 !!
```

2.kube2(192.168.0.22)、kube3(192.168.0.23)でノード追加用コマンドを実行します。

※先ほどkubeadm initコマンド実行時に表示された`kubeadm join`コマンドです。以下の通り実行してもトークンが違うため、正常にクラスタに対してノードが追加できません。

```
kubeadm join 192.168.0.21:6443 --token n5f3gr.c3enfuqrftc6tvqw --discovery-token-ca-cert-hash sha256:e0fff6e419121483a453a3cb886882dd9b9fb64ec3ac16a38b32c8c11704271b
```

この時、kube1 側の出力はどのようになっていますか？

* `STATUS` が「NorReady」から「Ready」になります。 `ROLE` は `<none>` のままです。

以上で Kubernetes のセットアップは完了しました。

## B4. サンプルアプリケーションの実行

- Example: Deploying PHP Guestbook application with Redis - Kubernetes
  - https://kubernetes.io/docs/tutorials/stateless-application/guestbook/

次のコマンドを実行して、Guestbook を起動します。


```
kubectl apply -f https://k8s.io/examples/application/guestbook/redis-master-deployment.yaml
kubectl get pods
kubectl logs -f redis-master-<id>
kubectl apply -f https://k8s.io/examples/application/guestbook/redis-master-service.yaml
kubectl get service
kubectl apply -f https://k8s.io/examples/application/guestbook/redis-slave-deployment.yaml
kubectl apply -f https://k8s.io/examples/application/guestbook/redis-slave-service.yaml
kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-deployment.yaml
kubectl get pods -l app=guestbook -l tier=frontend
kubectl apply -f https://k8s.io/examples/application/guestbook/frontend-service.yaml
kubectl get services 
```

このままでは VPC の中からしかアクセスできません。
インターネットからゲストブックをブラウザで開くにはどうしたらよろしいでしょうか。

# C. アプリケーション実行編

## C1. RancherUIからWordPress を立ち上げる

1. `Global` -> `Default`
2. `Catalog Apps`
3. `Launch` -> `wordpress`
4. ユーザ名とパスワードの設定を必ずする
5. `Launch`

起動後はインターネットから接続するには？
スケールできますか？

ヒント：２つあるポートは http と https です

## C2. Kubernetes チュートリアルで学ぶ

- Tutorials - Kubernetes
  - https://kubernetes.io/docs/tutorials/