【Kubernetes】VirtualBox上のVM(CentOS 7)にkubeadmで1Master+2Node環境作ってみた

(出遅れ感が否めないですが)最近流行のKubernetesをkubeadmで一から構築してみようと思い、
色々と躓いて何とか形になったので、メモを残しておきたいと思います(大事)。

#本記事の構成
ホストPC上に仮想化ソフトウェアを使って仮想マシンを3台構築し、
「1Master + 2Node」の構成のKubernetes環境を作る。以下、仮想マシンの情報です。

|仮想マシン名|OS|ネットワーク①|ネットワーク②|役割|vCPU|vMEM|
|:--|:--|:--|:--|:--|:--|:--|
|k8s-master|CentOS 7|10.0.2.21/24|192.168.56.101/24|Master|2|2,048MB|
|k8s-node-1|CentOS 7|10.0.2.22/24|192.168.56.102/24|Node-1|1|2,048MB|
|k8s-node-2|CentOS 7|10.0.2.23/24|192.168.56.103/24|Node-2|1|2,048MB|
※1：ネットワーク①は後述の「NATネットワーク」で、GWを「10.0.2.1」としてます
※2：ネットワーク②は後述の「ホストオンリーアダプター」

# ホスト環境
|ホストPCのOS|Windows 10 home|
|:--|:--|
|仮想化ソフトウェア|VirtualBox ver 6.0.6 r130049 (Qt5.6.2)|

#構築手順
以下の順序で説明していきます
　(1) 仮想マシンの作成とOS設定
　　　└VirtualBoxでの仮想マシン作成周りと、インフラ観点などのOS設定について
　(2) Kubernetes初期設定
　　　└Kubernetesで利用するノードとしての最低限の設定について
　(3) Kubernetes上の役割ごとの設定
　　　└Masterへの設定、Nodeの参加方法について

<b>※ある程度まで「k8s-master」を作成し、VirutualBoxの機能で複製して「k8s-node-1」「k8s-node-2」を作成するほうが楽に構築できます。<b>

## (1) 仮想マシンの初期設定
###(1-1) VirtualBox上の仮想マシンの設定

|項目|設定値|
|:--|:--|
|タイプ|Linux|
|バージョン|Red Hat(64-bit)|
|メモリーサイズ|2,048MB|
|ハードディスク|仮想ハードディスクを作成する|
|ハードディスクのファイルタイプ|VDI(VirutalBox Disk Image)|
|物理ハードディスクにあるストレージ|可変サイズ|
|ファイルの場所|(VirtualBox VMsのPath)\VirtualBox VMs\k8s-master|
|サイズ|16.00GB<br>★8GBとかにすると容量不足で途中でエラーになる|

###(1-2) OSインストール設定
1. 起動ディスクとして「CentOS-7-x86_64-DVD-1810.iso」を指定
  * DL先URL：[Index of /pub/linux/centos/7/isos/x86_64](http://ftp.iij.ad.jp/pub/linux/centos/7/isos/x86_64/)
- ディスク読み込み後の画面で「Install CentOS7」を選択してEnter
- 「WELCOME TO CENTOS 7.」の画面で「日本語」を選択して「続行」をクリック
  * 検索バーで「j」って入れればすぐに「日本語」が出てきます 
- 「インストールの概要」画面で以下操作が完了したら、「インストールの開始」をクリック
  - 「ソフトウェア」において以下項目が「ソフトウェア...をチェック中...」から変更されるまで待つ
     - インストールソース：ローカルメディア
     - ソフトウェアの選択：最小限のインストール
  - 「ソフトウェアの選択」をクリックして画面遷移し、以下項目を指定して「完了」をクリック
     - ベース環境：GNOME Desktop
     - 選択した環境のアドオン：GNOMEアプリケーション、開発ツール
  - 「インストール先」が"赤字"で「自動パーティシ...択されました」になっていればクリックする
     - 「インストール先」画面に遷移するが、何も変更せず「完了」をクリック
        - 「インストール概要」画面で「インストール先」が"黒字"で「自動パーティシ...択されました」になることを確認する
- 「インストールの開始」をクリックするとインストールが始まるので、完了するまで以下対応をする
  - インストール中の「設定」画面にて警告マークがついている以下２項目への対処をする
     - 「ROOTパスワード」：当該項目をクリックして任意のパスワードを設定して「完了」をクリック、設定画面の警告マークが消える
     - 「ユーザの作成」：ユーザ作成の必要があればクリックして任意の情報を入力し、「完了」をクリック(任意なのでやらなくてもいい)
  - 終わるまで待ち(目安で1時間ほどかかります)、終わった後は「再起動」をクリック
- 再起動後、「初期セットアップ」画面で「ライセンスに同意しない」と表示されている「LICESING INFORMATION」をクリック
  - 「ライセンス契約に同意します」にチェックを入れて、「完了」をクリック
- 「ネットワークとホスト名」は特に触らず、「設定の完了」をクリックし、GUIログイン画面が表示されることを確認する

###(1-3)OS初期起動時の設定
1. rootユーザでログインするため、ログイン画面で「アカウントが見つかりませんか？」をクリック
- ユーザー名に「root」を入力し、Enter
- パスワードに「(rootのパスワード)」を入力し、Enter
- rootユーザーでのGUIログインが完了
- 初回ログイン設定として以下項目を設定
  - 「言語」で「日本語」を選択し「次へ」
  - 「入力」で「日本語(無印)」を選択し「次へ」
  - 「プライバシー」で「位置情報サービス」を「オフ」にして「次へ」
  - 「オンラインアカウント」は特に設定しないで「スキップ」
  - 「準備完了」となるので「CentOS Linuxを使い始める」をクリックして初期設定完了
- ネットワーク設定をするため、一度仮想マシンの電源OFF
  - 右上の電源マークから電源オフが可能

###(1-4)仮想マシンへのネットワーク設定
1. 事前設定(NATネットワークの作成)
  - VirtualBoXの左上「ファイル」
    - 「環境設定」
      - 「ネットワーク」
        - NATネットワーク画面が出るので、右端の作成マーク(＋のやつ)をクリック
          - 画面に作成したネットワークが出てきたことを確認して「OK」をクリック
- VirutalBoxで仮想マシンを選択し、「設定」をクリック
- 「ネットワーク」メニューをクリックして、以下設定をして「OK」をクリック
  - アダプター1：「enp0s3：10.0.2.X」
     - 「ネットワークアダプターを有効化」にチェックが入っていることを確認
     - 「割り当て」を「NAT」から「NATネットワーク」に変更
        - 事前に作成した「NATネットワーク名」が選択されていることを確認して「OK」
  - アダプター2：「有線接続\ 1(enp0s8)：192.168.56.X」
     -  「ネットワークアダプターを有効化」にチェックを入れる(初期状態ではチェックされてない)
     - 「割り当て」を「ホストオンリーアダプター」に変更して「OK」
- 仮想マシンを起動
- 起動後、rootユーザでログインし、端末を開いて「# ip a」等で
  上記で設定したNICごとにアドレスが取得できているか確認する
  - 次の手順で固定IPアドレスを指定するので、アドレスの値については気にしない
- ここまでの手順が実施できたら一度VirtualBoxでスナップショットを取得し、
  3台の構成(1Master+2Node)になるように仮想マシンを作成する
  - <b>※仮想マシンはMasterは「2CPU以上」とすること(しないと以降の処理でCPU不足でダウンします)<b>

###(1-5) 仮想マシンのインフラ設定
3台の仮想マシンにログインし、以下コマンドを実行して「NIC設定」「ホストネーム設定」を行う(実施後、再起動すること)

```markdown:k8s-masterのインフラ設定
# hostnamectl set-hostname k8s-master.local
# hostname -f
# nmcli connection modify enp0s3 ipv4.method manual ipv4.addresses "10.0.2.21/24" ipv4.gateway "10.0.2.1" ipv4.dns "8.8.8.8" autoconnect yes
# nmcli connection modify 有線接続\ 1 ipv4.method manual ipv4.addresses "192.168.56.101/24"
# vi /etc/hosts
```

```markdown:k8s-node-1のインフラ設定
# hostnamectl set-hostname k8s-node-1.local
# hostname -f
# nmcli connection modify enp0s3 ipv4.method manual ipv4.addresses "10.0.2.22/24" ipv4.gateway "10.0.2.1" ipv4.dns "8.8.8.8" autoconnect yes
# nmcli connection modify 有線接続\ 1 ipv4.method manual ipv4.addresses "192.168.56.102/24"
# vi /etc/hosts
```

```markdown:k8s-node-2のインフラ設定
# hostnamectl set-hostname k8s-node-2.local
# hostname -f
# nmcli connection modify enp0s3 ipv4.method manual ipv4.addresses "10.0.2.23/24" ipv4.gateway "10.0.2.1" ipv4.dns "8.8.8.8" autoconnect yes
# nmcli connection modify 有線接続\ 1 ipv4.method manual ipv4.addresses "192.168.56.103/24"
# vi /etc/hosts
```
「/etc/hosts」の設定については、3台ともに以下記載としてください。

```markdown:/etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
#::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
10.0.2.21       k8s-master k8s-master.local
10.0.2.22       k8s-node-1 k8s-node-1.local
10.0.2.23       k8s-node-2 k8s-node-2.local
```

## (2) Kubernetes初期設定
※以下操作は「k8s-master」「k8s-node-1」「k8s-node-2」すべてに実施ください
　└どれか1台設定し、スナップショットで代用しても大丈夫です

以下、「k8s-node-1」を例として記載します。

###(2-1) SELinux無効化

```
[root@k8s-node-1 ~]# getenforce
Enforcing
[root@k8s-node-1 ~]# setenforce 0
[root@k8s-node-1 ~]# getenforce
Permissive
[root@k8s-node-1 ~]# sed -i 's/^SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config
[root@k8s-node-1 ~]# cat /etc/selinux/config

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of three values:
#     targeted - Targeted processes are protected,
#     minimum - Modification of targeted policy. Only selected processes are protected. 
#     mls - Multi Level Security protection.
SELINUXTYPE=targeted 
```

###(2-2) firewalld無効化
```
[root@k8s-node-1 ~]# systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
   Active: active (running) since 月 2019-06-17 22:42:16 JST; 1min 55s ago
     Docs: man:firewalld(1)
 Main PID: 2850 (firewalld)
    Tasks: 2
   CGroup: /system.slice/firewalld.service
           mq2850 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid

 6月 17 22:42:15 k8s-node-1.local systemd[1]: Starting firewalld - dynamic firewall daemon...
 6月 17 22:42:16 k8s-node-1.local systemd[1]: Started firewalld - dynamic firewall daemon.
[root@k8s-node-1 ~]# systemctl stop firewalld
[root@k8s-node-1 ~]# systemctl disable firewalld
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
[root@k8s-node-1 ~]# systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
   Active: inactive (dead)
     Docs: man:firewalld(1)

 6月 17 22:42:15 k8s-node-1.local systemd[1]: Starting firewalld - dynamic firewall daemon...
 6月 17 22:42:16 k8s-node-1.local systemd[1]: Started firewalld - dynamic firewall daemon.
 6月 17 22:44:17 k8s-node-1.local systemd[1]: Stopping firewalld - dynamic firewall daemon...
 6月 17 22:44:18 k8s-node-1.local systemd[1]: Stopped firewalld - dynamic firewall daemon.
```
###(2-3) ipv6無効化

```
[root@k8s-node-1 ~]# echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf
[root@k8s-node-1 ~]# echo "net.ipv6.conf.default.disable_ipv6 = 1" >> /etc/sysctl.conf
[root@k8s-node-1 ~]# sysctl -p /etc/sysctl.conf
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
```

###(2-4) dockerインストール&起動設定

```
[root@k8s-node-1 ~]# yum -y install docker

　・・・(略)・・・

インストール:
  docker.x86_64 2:1.13.1-96.gitb2f74b2.el7.centos                                                                    

依存性関連をインストールしました:
  atomic-registries.x86_64 1:1.22.1-26.gitb507039.el7.centos                                                         
  container-selinux.noarch 2:2.95-2.el7_6                                                                            
  container-storage-setup.noarch 0:0.11.0-2.git5eaf76c.el7                                                           
  containers-common.x86_64 1:0.1.35-2.git404c5bd.el7.centos                                                          
  docker-client.x86_64 2:1.13.1-96.gitb2f74b2.el7.centos                                                             
  docker-common.x86_64 2:1.13.1-96.gitb2f74b2.el7.centos                                                             
  oci-register-machine.x86_64 1:0-6.git2b44233.el7                                                                   
  oci-systemd-hook.x86_64 1:0.1.18-3.git8787307.el7_6                                                                
  oci-umount.x86_64 2:2.3.4-2.git87f9237.el7                                                                         
  python-pytoml.noarch 0:0.1.14-1.git7dea353.el7                                                                     
  subscription-manager-rhsm-certificates.x86_64 0:1.21.10-3.el7.centos                                               

完了しました!
[root@k8s-node-1 ~]# systemctl start docker
[root@k8s-node-1 ~]# systemctl enable docker
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.
[root@k8s-node-1 ~]# systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
   Active: active (running) since 月 2019-06-17 22:45:41 JST; 16s ago
     Docs: http://docs.docker.com
 Main PID: 4630 (dockerd-current)
   CGroup: /system.slice/docker.service
           tq4630 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --def...
           mq4635 /usr/bin/docker-containerd-current -l unix:///var/run/docker/libcontainerd/docker-containerd.soc...

 6月 17 22:45:39 k8s-node-1.local dockerd-current[4630]: time="2019-06-17T22:45:39.031495202+09:00" level=info...35"
 6月 17 22:45:40 k8s-node-1.local dockerd-current[4630]: time="2019-06-17T22:45:40.223662171+09:00" level=info...ds"
 6月 17 22:45:40 k8s-node-1.local dockerd-current[4630]: time="2019-06-17T22:45:40.225259438+09:00" level=info...t."
 6月 17 22:45:40 k8s-node-1.local dockerd-current[4630]: time="2019-06-17T22:45:40.308837736+09:00" level=info...se"
 6月 17 22:45:40 k8s-node-1.local dockerd-current[4630]: time="2019-06-17T22:45:40.526785857+09:00" level=info...ss"
 6月 17 22:45:40 k8s-node-1.local dockerd-current[4630]: time="2019-06-17T22:45:40.716252979+09:00" level=info...e."
 6月 17 22:45:41 k8s-node-1.local dockerd-current[4630]: time="2019-06-17T22:45:41.582194680+09:00" level=info...on"
 6月 17 22:45:41 k8s-node-1.local dockerd-current[4630]: time="2019-06-17T22:45:41.582497198+09:00" level=info...3.1
 6月 17 22:45:41 k8s-node-1.local systemd[1]: Started Docker Application Container Engine.
 6月 17 22:45:41 k8s-node-1.local dockerd-current[4630]: time="2019-06-17T22:45:41.591493834+09:00" level=info...ck"
Hint: Some lines were ellipsized, use -l to show in full.
```

###(2-5) Kubernetes用のnet.bridge設定

```
[root@k8s-node-1 ~]# emacs /etc/sysctl.d/k8s.conf
[root@k8s-node-1 ~]# cat /etc/sysctl.d/k8s.conf 
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
[root@k8s-node-1 ~]# sysctl --system
~~~(略)~~~
* Applying /etc/sysctl.d/k8s.conf ...
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
~~~(略)~~~
```

###(2-6) Kubernetes用のリポジトリ登録&インストール
```
[root@k8s-node-1 ~]# emacs /etc/yum.repos.d/kubernetes.repo
[root@k8s-node-1 ~]# cat /etc/yum.repos.d/kubernetes.repo 
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kube*
[root@k8s-node-1 ~]# yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

　・・・(略)・・・

インストール:
  kubeadm.x86_64 0:1.14.3-0             kubectl.x86_64 0:1.14.3-0             kubelet.x86_64 0:1.14.3-0            

依存性関連をインストールしました:
  conntrack-tools.x86_64 0:1.4.4-4.el7                      cri-tools.x86_64 0:1.12.0-0                             
  kubernetes-cni.x86_64 0:0.7.5-0                           libnetfilter_cthelper.x86_64 0:1.0.0-9.el7              
  libnetfilter_cttimeout.x86_64 0:1.0.0-6.el7               libnetfilter_queue.x86_64 0:1.0.2-2.el7_2               
  socat.x86_64 0:1.7.3.2-2.el7                             

完了しました!
[root@k8s-node-1 ~]# systemctl enable --now kubelet
Created symlink from /etc/systemd/system/multi-user.target.wants/kubelet.service to /usr/lib/systemd/system/kubelet.service.
[root@k8s-node-1 ~]# systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
   Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; vendor preset: disabled)
  Drop-In: /usr/lib/systemd/system/kubelet.service.d
           mq10-kubeadm.conf
   Active: activating (auto-restart) (Result: exit-code) since 月 2019-06-17 22:48:21 JST; 6s ago
     Docs: https://kubernetes.io/docs/
  Process: 4986 ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS (code=exited, status=255)
 Main PID: 4986 (code=exited, status=255)

 6月 17 22:48:21 k8s-node-1.local systemd[1]: kubelet.service: main process exited, code=exited, status=255/n/a
 6月 17 22:48:21 k8s-node-1.local systemd[1]: Unit kubelet.service entered failed state.
 6月 17 22:48:21 k8s-node-1.local systemd[1]: kubelet.service failed.
```
###(2-7) swapオフ
```
[root@k8s-node-1 ~]# swapoff -a
[root@k8s-node-1 ~]# emacs /etc/fstab 
[root@k8s-node-1 ~]# cat /etc/fstab

#
# /etc/fstab
# Created by anaconda on Mon Jun 17 21:10:10 2019
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root /                       xfs     defaults        0 0
UUID=2416ec32-31fa-4c20-934c-71b79e9d8b87 /boot                   xfs     defaults        0 0
#/dev/mapper/centos-swap swap                    swap    defaults        0 0
```

###(2-8) ipv4のフォワード設定
```
[root@k8s-node-1 ~]# echo 1 > /proc/sys/net/ipv4/ip_forward
[root@k8s-node-1 ~]# echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
[root@k8s-node-1 ~]# sysctl -p /etc/sysctl.conf
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv4.ip_forward = 1
```

## (3) Kubernetes上の役割ごとの設定
###(3-1) Masterの設定
「k8s-master」に以下設定する

```
[root@k8s-master ~]#  kubeadm init --apiserver-advertise-address=192.168.56.101 --pod-network-cidr=10.100.0.0/16
[init] Using Kubernetes version: v1.14.3
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Activating the kubelet service
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "etcd/ca" certificate and key
[certs] Generating "apiserver-etcd-client" certificate and key
[certs] Generating "etcd/peer" certificate and key
[certs] etcd/peer serving cert is signed for DNS names [k8s-master.local localhost] and IPs [192.168.56.101 127.0.0.1 ::1]
[certs] Generating "etcd/healthcheck-client" certificate and key
[certs] Generating "etcd/server" certificate and key
[certs] etcd/server serving cert is signed for DNS names [k8s-master.local localhost] and IPs [192.168.56.101 127.0.0.1 ::1]
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver-kubelet-client" certificate and key
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [k8s-master.local kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.56.101]
[certs] Generating "front-proxy-ca" certificate and key
[certs] Generating "front-proxy-client" certificate and key
[certs] Generating "sa" key and public key
[kubeconfig] Using kubeconfig folder "/etc/kubernetes"
[kubeconfig] Writing "admin.conf" kubeconfig file
[kubeconfig] Writing "kubelet.conf" kubeconfig file
[kubeconfig] Writing "controller-manager.conf" kubeconfig file
[kubeconfig] Writing "scheduler.conf" kubeconfig file
[control-plane] Using manifest folder "/etc/kubernetes/manifests"
[control-plane] Creating static Pod manifest for "kube-apiserver"
[control-plane] Creating static Pod manifest for "kube-controller-manager"
[control-plane] Creating static Pod manifest for "kube-scheduler"
[etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests"
[wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s
[apiclient] All control plane components are healthy after 19.010243 seconds
[upload-config] storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace
[kubelet] Creating a ConfigMap "kubelet-config-1.14" in namespace kube-system with the configuration for the kubelets in the cluster
[upload-certs] Skipping phase. Please see --experimental-upload-certs
[mark-control-plane] Marking the node k8s-master.local as control-plane by adding the label "node-role.kubernetes.io/master=''"
[mark-control-plane] Marking the node k8s-master.local as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
[bootstrap-token] Using token: 24dwfw.bguduge4oh9j8x0w
[bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles
[bootstrap-token] configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials
[bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token
[bootstrap-token] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstrap-token] creating the "cluster-info" ConfigMap in the "kube-public" namespace
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy

Your Kubernetes control-plane 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/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.56.101:6443 --token <生成されたランダム文字列> \
    --discovery-token-ca-cert-hash <生成されたランダム文字列> 
```
上記の「kubeadm join」のコマンドはNode参加に必要なため控えておく

###(3-1-1) kubectlのコンフィグと入力補完設定
個人環境なので、admin.confを直接参照しています。

```
[root@k8s-master ~]# export KUBECONFIG=/etc/kubernetes/admin.conf
```
以下を実行することで、kubectlのタブ補完が使えるようになります。

```
[root@k8s-master ~]# source <(kubectl completion bash)
```
「.bashrc」に設定を記載してしまうと今後が楽になります。

```
[root@k8s-master ~]# echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bashrc
[root@k8s-master ~]# echo "source <(kubectl completion bash)" >> ~/.bashrc
```
###(3-1-2) コンテナ間通信設定(Calico)
コンテナ間の通信のためにCalicoの設定を行います

```
[root@k8s-master ~]# kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml
clusterrole.rbac.authorization.k8s.io/calico-node created
clusterrolebinding.rbac.authorization.k8s.io/calico-node created
[root@k8s-master ~]# kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml
configmap/calico-config created
service/calico-typha created
deployment.apps/calico-typha created
poddisruptionbudget.policy/calico-typha created
daemonset.extensions/calico-node created
serviceaccount/calico-node created
customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created
```

###(3-2) Node設定
(3-1)で取得したNode参加コマンドを、「k8s-node-1」「k8s-node-2」に対して実行する

```
[root@k8s-node-1 ~]#  kubeadm join 192.168.56.101:6443 --token <生成されたランダム文字列> \
>     --discovery-token-ca-cert-hash <生成されたランダム文字列>
[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -oyaml'
[kubelet-start] Downloading configuration for the kubelet from the "kubelet-config-1.14" ConfigMap in the kube-system namespace
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Activating the kubelet service
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.
```

###(3-3) 構成確認
上記(3-1)(3-2)が正常に終了すると、MasterからNodeが確認できるようになります。

```
[root@k8s-master ~]# kubectl get nodes 
NAME               STATUS   ROLES    AGE     VERSION
k8s-master.local   Ready    master   5m35s   v1.14.3
k8s-node-1.local   Ready    <none>   67s     v1.14.3
k8s-node-2.local   Ready    <none>   40s     v1.14.3
```

#まとめ
Minikubeなどで簡単に用意しても良かったのですが、せっかくなので苦労してみようということで
今更ながらKubernetes環境をkubeadmで構築してみました。

色々な記事等を参考にしながらやってみて思いましたが、Kubernetesはバージョンアップ速度が速いので、この記事に記載されている内容にも不足事項が出るかもしれません。そういった意味では常にリリース情報をチェックするような姿勢が必要だと思いました。

# 参考
もともと本記事の環境は以下を参照して構築しており、自身の理解を深めるためのアウトプットとして記事化しています。
・[【2019年版】Kubernetes 1.13 の簡単インストール手順（その１）](https://k8sinfo.com/2019/02/13/create-k8s-environment-manual-1/)
・[【2019年版】Kubernetes 1.13 の簡単インストール手順（その２）](https://k8sinfo.com/2019/02/14/create-k8s-environment-manual-2/#toc_id_1_3)