kubernetes 1.12をAWS EC2でクラスタ化

# はじめに
　Dockerのオーケストレーションである[kubenetes]を使用してDockerのクラスタ化を行います。過去バージョンのものはいくつかあったのですが新バージョンはなかった気がするので備忘録で上げておきます。



## 環境
AWSで以下の構成を作ります

|VPC|Subnet|ホスト名|役割|インスタンスタイプ|AMI|AMI|
|:--------|:--------:|:--------|:--------|:--------|:--------|:--------|
|10.2.0.0/16|10.2.1.0/24|k8b-mster|マスター|t2.middle|centos 7.0|work-sg|
|10.2.0.0/16|10.2.1.0/24|k8b-node01|ノード1号機|t2.middle|centos 7.0|work-sg|
|10.2.0.0/16|10.2.1.0/24|k8b-node02|ノード2号機|t2.middle|centos 7.0|work-sg|

■[work-sg]内容
※非推奨（全開放しています）

Inbound　：　0-65536　0.0.0.0
Outbound　：　すべて　0.0.0.0

## 準備

### root ssh パスワード認証
別にやらなくても構いませんが筆者は鍵認証よりパスワード認証でsudo -s で切り替えるのが面倒だったためにこの設定を入れました

```
対象：全台
<$：centos>
sudo -s
passwd root
※以降root
sed -ri "s/#PermitRootLogin yes/PermitRootLogin yes/g" /etc/ssh/sshd_config
sed -ri "s/PasswordAuthentication no/PasswordAuthentication yes/g" /etc/ssh/sshd_config
systemctl restart sshd

```


### ssh パスワード認証なし
これは必須ではありません。何となくおまじないでやっています

```
<<#:Master>>
ssh-keygen -t rsa
（途中入力するプロンプトはすべてEnter）
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
vi ~/.ssh/authorized_keys
<<#:node01,node02>>
ssh-keygen -t rsa
cat ~/.ssh/id_rsa.pub
(master側の｢authorized_keys｣に内容をコピペ)
<<#:Master>>
cat .ssh/authorized_keys
<<#:node01,node02>>
vi ~/.ssh/authorized_keys
(マスター側の[authorized_keys]の内容をすべてコピペ)
```

```
(known_hostsの作成)
for ip in 10.2.1.62 10.2.1.141 10.2.1.21; do ssh $ip uname -a; done
for ip in k8b-master k8b-node01 k8b-node02; do ssh $ip uname -a; done
```

### EC2hostname変更とhosts設定
これは必須です。クラスタ間の通信の際に使ってると思います

```ruby:hostname変更
<<#:master>>
hostnamectl set-hostname 'k8b-master'
<<#:node01>>
hostnamectl set-hostname 'k8b-node01'
<<#:node02>>
hostnamectl set-hostname 'k8b-node02'
```

```ruby:hosts設定
vi /etc/hosts
10.2.1.62 k8b-master
10.2.1.141 k8b-node01
10.2.1.21 k8b-node02

scp /etc/hosts root@k8b-master:/etc/hosts
scp /etc/hosts root@k8b-node01:/etc/hosts
scp /etc/hosts root@k8b-node02:/etc/hosts
```

### selinux　停止
クラスタの際のエラーを回避するために停止させます

```
<<#:master>>
for host in k8b-master k8b-node01 k8b-node02 ;do ssh $host sed -ri "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config && cat /etc/selinux/config | grep SELINUX; done
for i in k8b-master k8b-node01 k8b-node02; do ssh $i sed -i 's/^SELINUX=permissive$/SELINUX=disabled/' /etc/selinux/config;done

<<#:master,node01,node02>>
reboot

<<#:master>>
for i in k8b-master k8b-node01 k8b-node02; do ssh $i sestatus;done
```

##　Docker install
　これから[kubenetes]のインストール作業に入ります。まずは前提となる[Docker]をインストールします
下記コマンドを実行するとすべてのサーバに[1.13.1]が導入されます

```
<<#:master>>
# Dockerリポジトリの追加
for i in k8b-master k8b-node01 k8b-node02; do ssh $i yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo && ls -l /etc/yum.repos.d/; done
# yumの更新
for i in k8b-master k8b-node01 k8b-node02; do ssh $i yum update all; done
# Docker install
for i in k8b-master k8b-node01 k8b-node02; do ssh $i yum install -y docker; done
# Docker install check
for i in k8b-master k8b-node01 k8b-node02; do ssh $i echo $hostname && echo "------" && docker -v && echo "-----"; done

<<#:master,node01,node02>>
# Docker サービス設定
systemctl enable docker && systemctl start docker && systemctl status docker
```

## kubernetesのリポジトリ追加

```
<<#:master>>
cat <<EOF > /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
EOF
scp /etc/yum.repos.d/kubernetes.repo root@k8b-node01:/etc/yum.repos.d/
scp /etc/yum.repos.d/kubernetes.repo root@k8b-node02:/etc/yum.repos.d/
for i in k8b-master k8b-node01 k8b-node02; do ssh $i ls -l /etc/yum.repos.d/; done
```

## kubenetes　インストール
　for文使って各サーバに対して一気に実行することも可能だと思いますが、ここは確認しながら進めたかったので
個別に実行しています

```
<<#:master,node01,node02>>
yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
```

## kubenetes マスター初期化
　｢kubenetes｣のマスターを初期化しています。

## サービス設定

```
systemctl enable kubelet && systemctl start kubelet
※この時点ではサービスは起動していない
```

##　net.bridge.bridge-nf-call-iptablesの確認
1であればよい

```
sysctl -n net.bridge.bridge-nf-call-iptables
```

## cgroup　確認
Dockerの設定と[10-kubeadm.conf]の[cgroupdriver]が一致しているか確認する
｢systemd｣になっていない場合変更する
（Centosの場合は基本的に[systemd]）

※現バージョンにはそもそも入っていないのでスルーで可。以下は一応確認した結果

```
docker info | grep -i cgroup
cat /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
```

```ruby:Result
[root@k8b-master ~]# docker info | grep -i cgroup
  WARNING: You're not using the default seccomp profile
Cgroup Driver: systemd
[root@k8b-master ~]# cat /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
# Note: This dropin only works with kubeadm and kubelet v1.11+
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
# This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
# This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use
# the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file.
EnvironmentFile=-/etc/sysconfig/kubelet
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS
[root@k8b-master ~]#
```

## kubenetes マスター初期化
　｢kubenetes｣のマスターを初期化します。実行結果の最後に出てくるメッセージはメモ帳等に保存してください。ノード追加の時に使用します

```
<<#:master>>
kubeadm init --pod-network-cidr=10.244.0.0/16
※IPは使ってなければいいだけのようです。
```

```ruby:Result
[root@k8b-master ~]# kubeadm init --pod-network-cidr=10.244.0.0/16
[init] using Kubernetes version: v1.12.3
[preflight] running pre-flight checks
<中略>
[addons] Applied essential addon: kube-proxy

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 10.2.1.9:6443 --token 4mlbar.6g75q47pg3vodb8t --discovery-token-ca-cert-hash sha256:5d62c6cc1061fb5aac0c17e21d744e164eef734611146693ca45959d9ac857c5
```

## admin.confのパス設定
　rootで行う場合は以下のコマンドでパスを通します

```
<<#：master>>
export KUBECONFIG=/etc/kubernetes/admin.conf
```

## n/w　設定
[calico]を使用してPodのネットワーク設定を行います

```
<<#：master>>
kubectl apply -f https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml

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

```

## ノード追加
　マスター以外に作った2台のサーバをクラスタに追加させる

```
<<#:k8b-node01,k8b-node02>>
※（Masterで[kubeadm init]を実行した際の最後に表示されたコマンドをそのまま実行する

kubeadm join 10.2.1.9:6443 --token 4mlbar.6g75q47pg3vodb8t --discovery-token-ca-cert-hash sha256:5d62c6cc1061fb5aac0c17e21d744e164eef734611146693ca45959d9ac857c5

```

## 稼働確認

```
kubectl get nodes
```

## ノード追加
　先ほどinitを実行したときのコマンドを使用してマスターにノードを追加します。やり方は保存済みのJoinコマンドをノードで実行するだけです

```
<<#:node01,node02>>
kubeadm join 10.2.1.9:6443 --token 4mlbar.6g75q47pg3vodb8t --discovery-token-ca-cert-hash sha256:5d62c6cc1061fb5aac0c17e21d744e164eef734611146693ca45959d9ac857c5
<<#:master>>
kubectl get nodes
```

```ruby:result
[root@k8b-master ~]# kubectl get nodes
NAME         STATUS   ROLES    AGE    VERSION
k8b-master   Ready    master   16m    v1.12.3
k8b-node01   Ready    <none>   2m5s   v1.12.3
k8b-node02   Ready    <none>   2m1s   v1.12.3
[root@k8b-master ~]#
```

## コンテナ作成
ここでは[apache]と[nginx]を起動させて本当にクラスタになっているかを確認します。作成するフォルダは任意となります。今回は[~/kubeimg]の下に作成していきます。

```ruby:apache
mkdir ~/kubeimg
vi ~/kubeimg/apache.yaml
vi ~/kubeimg/apache-svc.yaml
```
```ruby:apache.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: apache
spec:
  selector:
    matchLabels:
      app: apache
  replicas: 2
  template:
    metadata:
      labels:
        app: apache
    spec:
     containers:
     - name: apache
       image: httpd:2.4
       ports:
       - containerPort: 80
```

```ruby:apache-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: apache
spec:
  type: NodePort
  selector:
    app: apache
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
```

```ruby:apache
mkdir ~/kubeimg
vi ~/kubeimg/nginx.yaml
vi ~/kubeimg/nginx-svc.yaml
```

```ruby:nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
     containers:
     - name: nginx
       image: nginx:1.12.1
       ports:
       - containerPort: 80
```

```ruby:nginx-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
```

## apacheとnginxの起動

```ruby:起動
cd ~/kubeimg
kubectl apply -f nginx.yaml
kubectl apply -f nginx-svc.yaml
kubectl apply -f apache.yaml
kubectl apply -f apache-svc.yaml
kubectl get deployment,replicasets,pods
kubectl get svc
```

```ruby:Result1
[root@k8b-master kubeimg]# kubectl get deployment,replicasets,pods
NAME                           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/apache   2         2         2            2           37m
deployment.extensions/nginx    2         2         2            2           14m

NAME                                      DESIRED   CURRENT   READY   AGE
replicaset.extensions/apache-5954cc7465   2         2         2       37m
replicaset.extensions/nginx-7f97d5f456    2         2         2       8m6s

NAME                          READY   STATUS    RESTARTS   AGE
pod/apache-5954cc7465-bdrpg   1/1     Running   0          37m
pod/apache-5954cc7465-dhwpd   1/1     Running   0          37m
pod/nginx-7f97d5f456-442l5    1/1     Running   0          8m6s
pod/nginx-7f97d5f456-bcm2j    1/1     Running   0          8m5s
[root@k8b-master kubeimg]#
```

```ruby:Result2
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
apache       NodePort    10.103.43.210    <none>        80:32130/TCP   38m
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        132m
nginx        NodePort    10.100.254.122   <none>        80:32240/TCP   9m30s
[root@k8b-master kubeimg]#
※Portsに指定された番号にアクセスすることになります
（コンテナポート：リモートポート）
```


## web起動

AWSなのでPublicIPにバインディングしたポートを指定し
ブラウザアクセス。node1IP:<port>,node2IP:<port>で同じ画面が見えていることが正解です

■apache
AWSでやっているのでパブリックIPを使用してアクセス

TeraTermでポートフォワーディングしているのでURLはすべてlocalhostになります

```ruby:設定内容
Local "localhost" port 80 to remote "node01のプライベートIP" port 32130

Local "localhost" port 80 to remote "node02のプライベートIP" port 32130
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/150678/57b79e81-44d0-268a-a6e0-f8151c024cc0.png)



■nginx

```ruby:設定内容
Local "localhost" port 80 to remote "node01のプライベートIP" port 32240

Local "localhost" port 80 to remote "node02のプライベートIP" port 32240
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/150678/4a0dd01c-91ce-b3dd-5be2-d94988f29d9a.png)


補足）

podが使用しているIPを知りたい場合

```
[root@appmaster apache]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
apache       NodePort    10.98.130.184   <none>        80:32455/TCP   4h54m
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        5h6m
nginx        NodePort    10.99.201.47    <none>        80:30587/TCP   4h54m
[root@appmaster apache]#
```

namespeceの情報を取得する

```
[root@appmaster apache]# kubectl get pod --all-namespaces
NAMESPACE     NAME                                    READY   STATUS             RESTARTS   AGE
default       apache-5954cc7465-cztk9                 1/1     Running            0          4h55m
default       apache-5954cc7465-ntsk7                 1/1     Running            0          4h55m
default       nginx-7f97d5f456-57dl2                  1/1     Running            0          4h55m
default       nginx-7f97d5f456-hxw2n                  1/1     Running
[root@appmaster apache]#

```

究極の手段リセット

```
[root@appmaster apache]# kubeadm reset
[reset] WARNING: changes made to this host by 'kubeadm init' or 'kubeadm join' will be reverted.
[reset] are you sure you want to proceed? [y/N]: y
[preflight] running pre-flight checks
[reset] stopping the kubelet service
[reset] unmounting mounted directories in "/var/lib/kubelet"
[reset] deleting contents of stateful directories: [/var/lib/kubelet /etc/cni/net.d /var/lib/dockershim /var/run/kubernetes /var/lib/etcd]
[reset] deleting contents of config directories: [/etc/kubernetes/manifests /etc/kubernetes/pki]
[reset] deleting files: [/etc/kubernetes/admin.conf /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf]
[root@appmaster apache]#
```

# 終わりに
　ここまでやるのに結構苦労しました。今現在は[dashbord]を頑張っています。次に各種コマンドを一通りやってみて最終的に[kubernetes]の備忘録にするつもりです。それにしてもDocker関連は面白いですね。