うさぎ好きエンジニアの備忘録

うさぎたちに日々癒されているエンジニアが業務で直面したもの & 個人的な学習メモを残していきます。

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

  • 構築してからしばらく利用してきたKubernetesクラスタが壊れてしまい、再起不能となったため作り直す
  • 今後のメモとして構築方法をまとめておく

今回作成するクラスタ

今回は、以下の環境のクラスタを構築する。

  • 3台構成 (Master1台、Worker2台)
  • Cent OS7
  • minikubeは使わない (kubeadmを使って構築)
  • 使用するkubectl / kubeadm / kubeletのバージョンは1.18.2

Masterの構築

各種パッケージのインストール

Masterを構築するサーバにログイン。

$ ssh k8s.master.kazono.co.jp

以下のコマンドを実行してkubernetes.repo/etc/yum.repos.dに配置。

$ sudo tee /etc/yum.repos.d/kubernetes.repo <<EOF
[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

SELinuxを一時的に無効化。

$ sudo setenforce 0
$ sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

dockerをインストールして、サービスをstartさせておく。

$ sudo yum install -y docker
$ sudo systemctl enable docker && sudo systemctl start docker
  • v1.6.0以降、KubernetesはデフォルトでCRI(Container Runtime Interface)の使用を有効にしており、kubeadmは既知のドメインソケットのリストをスキャンして、Linuxノード上のコンテナランタイムを自動的に検出しようするため。

  • 検出可能なランタイムとソケットパスは、以下のとおり。

ランタイム ドメインソケット
Docker /var/run/docker.sock
conteinerd /run/containerd/containerd.sock
CRI-O /var/run/crio/crio.sock
  • Dockerとcontainerdの両方が同時に検出された場合、Dockerが優先される。これはDocker 18.09にはcontainerdが同梱されており、両方が検出されてしまうため。他の2つ以上のランタイムが検出された場合、kubeadmはエラーを出力して終了する。

  • なお、もしコンテナランタイムとしてDockerを選択した場合、kebelet内に組み込まれたdockershim CRIが使用される。

dockerのインストールと起動が正常に完了したら、kubeletkubeadmkubectlをインストールして、kubelet自動起動を有効化。

$ sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
$ sudo systemctl enable --now kubelet

初期化と設定ファイルの準備

以下のコマンドでkubeadmの初期化を実施。

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

Your Kubernetes control-plane has initialized successfully! と表示されたらOK。kubeadm join ...は今後Slaveを登録する際に必要な情報のため、どこかにメモしておく。

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 <IP Addr>:6443 --token XXXXX \
    --discovery-token-ca-cert-hash YYYYYY

初期化が完了すると/etc/kubernetesディレクトリ配下に設定ファイルが生成されるので、適切なファイルをホームディレクトリにcpする。

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

コンテナ間通信の準備

続いて、コンテナ間の通信を行うための仮想ネットワークに関する設定を行う。今回はcalicoを使って設定を行なっていく。

  • flannelでもいいけど、開発が停滞している印象 (個人的主観)
  • flannelでも上層部分でcalicoのネットワークポリシーを使ってそう
$ kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml

正常に完了したら、以下のコマンドでcalicoがRunningになっていることを確認。

$ kubectl get pods -n kube-system

Masterの状態確認

ここまできたらkubectl get nodesクラスタにサービスインしているノードの情報が取れるはず。

$ kubectl get nodes
...
k8s.master.kazono.co.jp   Ready    master   13m   v1.18.2

Workerの追加

Masterが構築できたので、Workerをサービスインしていく。

各種パッケージのインストール

Masterを構築した時と同様にdockerkubeletなどをインストールしていく。

# repoファイルの準備
$ sudo tee /etc/yum.repos.d/kubernetes.repo <<EOF
[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

#SELinuxの停止
$ sudo setenforce 0
$ sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

# dockerのインストール
$ sudo yum install -y docker
$ sudo systemctl enable docker && sudo systemctl start docker

# kubelet, kubeadm, kubectlのインストール & kubeletの自動起動有効化
$ sudo yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
$ sudo systemctl enable --now kubelet

インストールが完了したらMaster構築時 (kubeadm initした時) に表示された kubeadm joinコマンドを実行。

Then you can join any number of worker nodes by running the following on each as root」と書いてあるように、rootで実行すること。

$ sudo kubeadm join <IP Addr>:6443 --token XXXXX \
    --discovery-token-ca-cert-hash YYYYYY

実行が正常に完了すると、「This node has joined the cluster」と表示されるので、Master側でkubectl get nodesを実行してみる。

$ kubectl get nodes
...
k8s.master.kazono.co.jp   Ready      master   27m     v1.18.2
k8s.worker01.kazono.co.jp   Ready      <none>   2m55s   v1.18.2
k8s.worker02.kazono.co.jp   NotReady   <none>   12s     v1.18.2

想定通り、3台のノードが表示されたのでOK。

ROLEの設定

kubeadmで追加したノードのROLEは基本的に設定されておらず<none>になっている。このままでもいいが、nodeSelectorなどで特定のノードにpodを起動したいという場面もあるかもしれないので、設定しておく。

コマンド自体は↓のような感じ。

# Node: k8s.worker01.kazono.co.jp に workerというROLEを付与
$ kubectl label node k8s.worker01.kazono.co.jp node-role.kubernetes.io/worker=k8s.worker01.kazono.co.jp

$ kubectl get nodes
...
k8s.master.kazono.co.jp   Ready    master   38m   v1.18.2
k8s.worker01.kazono.co.jp   Ready    worker   14m   v1.18.2
k8s.worker02.kazono.co.jp   Ready    <none>   11m   v1.18.2

ちなみにコマンドの構文としては以下のようになっている。

# 追加
$ kubectl label node <node name> node-role.kubernetes.io/<role name>=<key - (any name)>

# 削除
$ kubectl label node <node name> node-role.kubernetes.io/<role name>-

Kubernetes Dashboardのデプロイ

詳細は別記事で。今回はv2を使っていく。

ponteru.hatenablog.com

https://github.com/kubernetes/dashboard/tree/v2.0.0

yamlをダウンロードして、NodePortを使用するようにyamlを修正して、kubectl applyを実行。

$ wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0/aio/deploy/recommended.yaml
# NodePortを使うように修正
$ vi recommended.yaml
$ kubectl apply -f recommended.yaml

namespaceにkubenetes-dashboardを指定して、podが稼働していることを確認。

$ kubectl get service -n kubernetes-dashboard
NAME                        TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)         AGE
dashboard-metrics-scraper   ClusterIP   10.96.15.35      <none>        8000/TCP        6m42s
kubernetes-dashboard        NodePort    10.107.230.202   <none>        443:30843/TCP   6m43s

https://k8s.worker01.kazono.co.jp:30843/へアクセス。

サインインを求められる画面にリダイレクトされるので、認証用のサービスアカウントを作成して、認証情報を取得してサインイン。

$ tee ~/admin-user.yaml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: admin-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kubernetes-dashboard
EOF

$ kubectl apply -f admin-user.yaml
$ ADMIN=`kubectl get secret -n kubernetes-dashboard | grep admin | awk '{ print $1 }'`
$ kubectl describe secret $ADMIN -n kubernetes-dashboard | grep token: | awk '{ print $2 }'
# トークンが出力されるので、それをコピーしてサインイン