余ったPC1台を使ってオンプレKubernetesクラスタを構築してみる

2020-01-31Docker, Kubernetes

はじめに

仕事ではGoogle Kubernetes Engine (GKE)を使ってのKubernetesクラスタ構築をしています。

仕事以外の時間でもKubernetesクラスタをゴリゴリ触ってみたいと思いました。
そこで、家の使っていない古いPCを使ってKubernetesクラスタをいちから作成してみることにしました。

(2020-01-26 追記)

当エントリでまとめたセットアップ手順をシンプルなシェルスクリプトにまとめ、公開しました。

クラスタを構成する「マスタサーバ」と「ノード」の2つの役割はどうするの?

Kubernetesクラスタには、マスターサーバノードと言われるサーバが必要になります。

ざっくりいうと、 マスターサーバは管理者からの要求に答えてノード(後述)にコンテナを立ち上げたり、ノードに存在するコンテナの状況を監視します。
ノードはコンテナそのものを動かすサーバです。

「Hadoop HDFS」におけるマスタノードスレーブノードに似ていますね。

したがって、できる限りマスターサーバは余裕のある状況が望ましいです。

ただし今回は検証環境である、またお金をかけたくないなどの理由から、
「マスタサーバ」x1台と「ノード」x1台を物理サーバx1台に共存させたいと思います。

セットアップ

Kubernetesクラスタを構築していきます。

OSのディストリビューション・バージョンを確認

さて、今回余っていた古いPCには Ubuntu18.04 がインストールされていたため、その環境をそのまま利用します。

$ uname -v
40~18.04.1-Ubuntu SMP Thu Nov 14 12:06:39 UTC 2019

Docker のインストール

セットアップ後は以下のコマンドを実行し、OSリブート時にもサービスが自動起動するようにしておきます。

$ sudo apt-get update -y
$ sudo apt-get install -y docker.io
$ sudo systemctl enable docker.service

# 現在ログインしているユーザが `docker` コマンドを実行できるようにしておく
$ sudo gpasswd -a "${USER}" docker

# 上記で設定したdockerグループへの所属は、一度ログインしないと反映されない
$ exit

正常にセットアップされたか配下のコマンドを実行すれば確認できます。

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

**※まずここで詰まると先に進めないので、確実に docker ps が正しく動作しているかを確認しましょう。

kubeadm のインストール

※CentOSの場合についても試すことができたので掲載しておきます。

Ubuntuの場合

aptのリポジトリにKubernetesの設定を追加します。

$ sudo apt-get install -y gnupg gnupg2
$ curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg|sudo apt-key add -
$ echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kube.list

準備ができたのでインストールしてみます。

$ sudo apt-get update -y

$ sudo apt-get install -y kubeadm kubelet kubectl

正常にインストールできたか確認してみます。

# バージョン情報が表示されればOK
$ kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.2", GitCommit:"59603c6e503c87169aea6106f57b9f242f64df89", GitTreeState:"clean", BuildDate:"2020-01-18T23:27:49Z", GoVersion:"go1.13.5", Compiler:"gc", Platform:"linux/amd64"}

CentOSの場合

CentOSの場合はyumでインストールできるようにリポジトリを追加します。

$ 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

# Set SELinux in permissive mode (effectively disabling it)
$ setenforce 0
$ sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

インストールしていきます。

$ yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes

$ systemctl enable --now kubelet

正常にインストールできたか確認してみます。

# バージョン情報が表示されればOK
$ kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.2", GitCommit:"59603c6e503c87169aea6106f57b9f242f64df89", GitTreeState:"clean", BuildDate:"2020-01-18T23:27:49Z", GoVersion:"go1.13.5", Compiler:"gc", Platform:"linux/amd64"}

マスターサーバの初期化

kubeadmコマンドを使って、マスターサーバを初期化します。

  1. Swapが有効になっていると初期化できないようなので、無効にしておきます。
  2. --pod-network-cidr=10.244.0.0/16 のオプションはflannel(後述)というKubernetes上の仮想ネットワークを構成するための設定となります。

多少時間がかかるため、気長に待ちましょう。

# SwapをOFF
$ sudo swapoff -a

# 初期化
$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16
...

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.0.201:6443 --token *********************** \
    --discovery-token-ca-cert-hash sha256:****************************************************************

マスターサーバと通信するための設定と動作確認

マスターサーバの初期化が終了しました。

先程のログにかかれていますが、現在のログインユーザでKubernetesクラスタと通信するための設定を行います。

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

kubectl version でバージョンが表示されるかを確認します。

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.1", GitCommit:"d224476cd0730baca2b6e357d144171ed74192d6", GitTreeState:"clean", BuildDate:"2020-01-16T11:36:03Z", GoVersion:"go1.13.6", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.2", GitCommit:"59603c6e503c87169aea6106f57b9f242f64df89", GitTreeState:"clean", BuildDate:"2020-01-18T23:22:30Z", GoVersion:"go1.13.5", Compiler:"gc", Platform:"linux/amd64"}

flannelをデプロイ

Kubernetes上の仮想ネットワークを構成するためのコンポーネントをインストールします。

  • ネット上に掲載されているflannelのインストールコマンドは現在では古い場合が多いことに注意!
    • これは当ブログにも言えることです!!
  • 2020-01-20現在は、以下のmasterブランチの構成情報ファイルが利用できました。
$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

マスタノードにポッドをスケジュールできるようにする

kubeadm で初期化したマスターサーバは、デフォルトの状態では「ノード」の役割を持ちません。
通常は「マスタサーバ」は余裕のある状況が望ましいですのですが、何度も言いますが今回は検証環境であるため、「ノード」の役割を兼任させてしまいます。

$ kubectl taint nodes --all node-role.kubernetes.io/master-

kubelet サービスを有効化

「ノード」の役割を担当する kubelet というサービスを、OS起動時にも自動的に立ち上がるようにしておきます。

$ sudo systemctl enable kubelet.service

ここまで行けばクラスタの構築は完了です。

Apacheサーバを立ち上げてみる

Kubernetesクラスタを使って、Apacheサーバを立ち上げてみます。

細かい説明は省略しますが以下のコマンドを実行してみます。

# Apacehサーバを立ち上げる
$ kubectl run --port 80 --image=httpd httpd
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/httpd created

# Apacheサーバが立ち上がっているかを確認する
$ kubectl get pod
NAME                       READY   STATUS    RESTARTS   AGE
httpd-785b97775d-nkbx7     1/1     Running   0          18s

# このままではサーバにはクラスタ外からはアクセスできないので、ポートフォワードして8080でアクセスできるようにする
$ kubectl port-forward httpd-785b97775d-nkbx7 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Handling connection for 8080

ブラウザあるいはcurlコマンドで http://localhost:8080 にアクセスしてみます。

$ curl localhost:8080
<html><body><h1>It works!</h1></body></html>

無事Webページが見れるはずです。

ひとこと

1台のKubernetesクラスタはどこまで死なずに稼働できるでしょうね。
試してみます。

2020-01-31Docker, Kubernetes