Edited at

ClusterHATを使って世界最小Kubernetesクラスタを構築する - インストール編その1

More than 1 year has passed since last update.


はじめに

まずはClusterHATを接続してRaspberry Pi Zero3枚を含んだ豆腐クラスタを構築したサーバー構築編、そしてKelsey HightowerさんのKubernetes The Hard Way豆腐クラスタ上に構築する第一弾(TLS証明書編)に続き、いよいよ今回は各種サーバーコンポーネントをインストールする。

前回同様に原則Kelsay Hightowerさんのチュートリアルを順を追って進めていくが、本家がGCP上に6つのVMを用意して構築する手順となっている為、その手順と差が出る箇所は特に重点的に記載していく。前回は第6章まで終わったので、今回は第7章から始める。


環境

前回の投稿に記載。

最終的に各種バイナリならびに設定ファイルはコントローラーの以下に配置される:

Folder
File

/etc/etcd
ca.pem

kubernetes-key.pem

kubernetes.pem

/etc/systemd/system
etcd.service

kube-apiserver.service

kube-controller-manager.service

kube-sccheduler.service

/usr/local/bin
etcd

etcdctl

kube-apiserver

kube-controller-manager

kube-schedule

kubectl

/var/lib/kubernetes
ca-key.pem

ca.pem

encryption-config.yaml

kubernetes-key.pem

kubernetes.pem


7. Bootstrapping the etcd Cluster

まずはクラスタの各種状態を保存するetcdをインストールする。チュートリアルでは3つのコントローラーぞれぞれにetcdをインストールしクラスタ化しているが、豆腐クラスタでは母艦であるPi3 Bのみをコントローラーとしており、今回はこのコントローラーのみにインストールする。(ノードにもインストールしてクラスタ化しても一向に問題ない。)

ここがさらに大事。Raspberry 3BのCPUは64ビットだがRaspbian自体は32ビットである。チュートリアルでは64ビット版のバイナリをインストール手順となっているのでここを32ビットに変更する必要がある。そして残念ながらetcdはGoの32ビットに関する問題の為サポートしないとあるので自分でビルドする必要がある。

etcdのソースからのインストールについてはkubernetesをRaspberry pi 3にインストールする(その2)に大変お世話になった。感謝。


Controller

#Goのインストール

$ wget https://storage.googleapis.com/golang/go1.10.1.linux-armv6l.tar.gz
$ tar zxf go1.10.1.linux-armv6l.tar.gz
$ sudo mv go /usr/local
$ echo "export PATH=$PATH:/usr/local/go/bin" >> ~/.bashrc
# Gitのインストール
$ sudo apt-get install git
# etcdのインストール
$ export GOOS=linux
$ export GOARCH=arm
$ export GOARM=7
$ git clone --branch v3.3.4 https://github.com/coreos/etcd.git
$ cd etcd
$ ./build
$ sudo mv bin/* /usr/local/bin
$ sudo mkdir -p /etc/etcd /var/lib/etcd
# 第5章で生成した証明書とキーをコピーしたフォルダに移動してから実行
$ sudo cp ca.pem kubernetes-key.pem kubernetes.pem /etc/etcd/

次にetcd用の.serviceファイルを作成。ホスト名を取得してからクラスタ内のインスタンス名として定義する。


Controller

# INTERNAL_IPは直接コントローラーのIPを設定

$ INTERNAL_IP="192.168.1.100"
# ホスト名を取得。etcdクラスタ内で一意となる名前であれば良。
$ ETCD_NAME=$(hostname -s)
# etcd.serviceファイルの生成
$ cat > etcd.service <<EOF
[Unit]
Description=etcd
Documentation=https://github.com/coreos
After=network.target

[Service]
Type=notify
Restart=always
RestartSec=5s
LimitNOFILE=40000
TimeoutStartSec=0
Environment="ETCD_UNSUPPORTED_ARCH=arm"
ExecStart=/usr/local/bin/etcd \\
--name
${ETCD_NAME} \\
--cert-file=/etc/etcd/kubernetes.pem
\\
--key-file=/etc/etcd/kubernetes-key.pem
\\
--peer-cert-file=/etc/etcd/kubernetes.pem
\\
--peer-key-file=/etc/etcd/kubernetes-key.pem
\\
--trusted-ca-file=/etc/etcd/ca.pem
\\
--peer-trusted-ca-file=/etc/etcd/ca.pem
\\
--peer-client-cert-auth
\\
--client-cert-auth
\\
--initial-advertise-peer-urls https://
${INTERNAL_IP}:2380 \\
--listen-peer-urls https://
${INTERNAL_IP}:2380 \\
--listen-client-urls https://
${INTERNAL_IP}:2379,http://127.0.0.1:2379 \\
--advertise-client-urls https://
${INTERNAL_IP}:2379 \\
--initial-cluster-token etcd-cluster-0
\\
--initial-cluster controller=https://
${INTERNAL_IP}:2380 \\
--initial-cluster-state new
\\
--data-dir=/var/lib/etcd

[Install]
WantedBy=multi-user.target
EOF


本来etcdはもっぱらクラスタとして複数インスタンスを登録して運用するものなのだが、今回はまず1インスタンスのみで動くかどうか検証する。具体的にはinitial-clusterのパラメータに1インスタンス(つまりコントローラー)の定義のみを登録している。クラスタを組む場合にはここに列挙すれば良い。

もう一つ大事なのはオリジナルは無いEnvironment="ETCD_UNSUPPORTED_ARCH=arm"というパラメータ。etcdはサポートされていないプラットフォーム上で稼働させる場合、例えそのプラットフォーム向けにコンパイルされたものでもワーニングを出力してプロセスを終了させてしまう。(WARNINGと出るがこれはエラーと同じ扱い。)このETCD_UNSUPPORTED_ARCHを明示的に指定することでワーニングを回避出来る。

最後にサービスファイルを所定の場所に移動しスタートさせる。


Controller

$ sudo mv etcd.service /etc/systemd/system/

$ sudo systemctl daemon-reload
$ sudo systemctl enable etcd
Created symlink /etc/systemd/system/multi-user.target.wants/etcd.service → /etc/systemd/system/etcd.service.
$ sudo systemctl start etcd
# 稼働確認
$ ETCDCTL_API=3 etcdctl member list
371464a192041f5c, started, controller, https://192.168.1.100:2380, https://192.168.1.100:2379

これで完了。


8. Bootstrapping the Kubernetes Control Plane

いよいよ佳境に入ってきた。


各種サービスのインストール

etcdとは異なりkubernetesの場合はARM用のバイナリが用意されているのでこれらを取得する。(ちなみにetcdと異なりビルドにはmakeが必要)またそれを踏まえてチュートリアルのバイナリ取得箇所を少し訂正する。

まず各サービスのバイナリを取得しコントローラーにインストールする。


Controller

# ARM版バイナリを取得

$ wget -q --show-progress --https-only --timestamping \
"https://storage.googleapis.com/kubernetes-release/release/v1.10.2/bin/linux/arm/kube-apiserver" \
"https://storage.googleapis.com/kubernetes-release/release/v1.10.2/bin/linux/arm/kube-controller-manager" \
"https://storage.googleapis.com/kubernetes-release/release/v1.10.2/bin/linux/arm/kube-scheduler" \
"https://storage.googleapis.com/kubernetes-release/release/v1.10.2/bin/linux/arm/kubectl"
# インストール
$ chmod +x kube-apiserver kube-controller-manager kube-scheduler kubectl
$ sudo mkdir -p /var/lib/kubernetes/
$ sudo mv kube-apiserver kube-controller-manager kube-scheduler kubectl /usr/local/bin/
# TLS証明書&キー及び設定ファイルの設置
$ sudo mkdir -p /var/lib/kubernetes/
# 第5章及び6章で生成した証明書、キー、設定ファイルをコピーしたフォルダに移動してから実行
$ sudo mv ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem encryption-config.yaml /var/lib/kubernetes/

次にAPI-Serverの.serviceファイルを生成


Controller

$ cat > kube-apiserver.service <<EOF

[Unit]
Description=Kubernetes API Server
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-apiserver \\
--admission-control=Initializers,NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota
\\
--advertise-address=192.168.1.100
\\
--allow-privileged=true
\\
--apiserver-count=1
\\
--audit-log-maxage=30
\\
--audit-log-maxbackup=3
\\
--audit-log-maxsize=100
\\
--audit-log-path=/var/log/audit.log
\\
--authorization-mode=Node,RBAC
\\
--bind-address=0.0.0.0
\\
--client-ca-file=/var/lib/kubernetes/ca.pem
\\
--enable-swagger-ui=true
\\
--etcd-cafile=/var/lib/kubernetes/ca.pem
\\
--etcd-certfile=/var/lib/kubernetes/kubernetes.pem
\\
--etcd-keyfile=/var/lib/kubernetes/kubernetes-key.pem
\\
--etcd-servers=https://192.168.1.100:2379
\\
--event-ttl=1h
\\
--experimental-encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml
\\
--insecure-bind-address=127.0.0.1
\\
--kubelet-certificate-authority=/var/lib/kubernetes/ca.pem
\\
--kubelet-client-certificate=/var/lib/kubernetes/kubernetes.pem
\\
--kubelet-client-key=/var/lib/kubernetes/kubernetes-key.pem
\\
--kubelet-https=true
\\
--runtime-config=api/all
\\
--service-account-key-file=/var/lib/kubernetes/ca-key.pem
\\
--service-cluster-ip-range=10.32.0.0/24
\\
--service-node-port-range=30000-32767
\\
--tls-ca-file=/var/lib/kubernetes/ca.pem
\\
--tls-cert-file=/var/lib/kubernetes/kubernetes.pem
\\
--tls-private-key-file=/var/lib/kubernetes/kubernetes-key.pem
\\
--v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF


Control Managerの.serviceファイルを生成。


Controller

$ cat > kube-controller-manager.service <<EOF

[Unit]
Description=Kubernetes Controller Manager
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-controller-manager \\
--address=0.0.0.0
\\
--cluster-cidr=10.200.0.0/16
\\
--cluster-name=kubernetes
\\
--cluster-signing-cert-file=/var/lib/kubernetes/ca.pem
\\
--cluster-signing-key-file=/var/lib/kubernetes/ca-key.pem
\\
--leader-elect=true
\\
--master=http://127.0.0.1:8080
\\
--root-ca-file=/var/lib/kubernetes/ca.pem
\\
--service-account-private-key-file=/var/lib/kubernetes/ca-key.pem
\\
--service-cluster-ip-range=10.32.0.0/24
\\
--v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF


次にSchedulerの.serviceファイルを生成。


Controller

$ cat > kube-scheduler.service <<EOF

[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-scheduler \\
--leader-elect=true
\\
--master=http://127.0.0.1:8080
\\
--v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF


これら全てのサービスを起動する。


Controller

$ sudo mv kube-apiserver.service kube-scheduler.service kube-controller-manager.service /etc/systemd/system/

$ sudo systemctl daemon-reload
$ sudo systemctl enable kube-apiserver kube-controller-manager kube-scheduler
$ sudo systemctl start kube-apiserver kube-controller-manager kube-scheduler
$ kubectl get componentstatuses
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-0 Healthy {"health":"true"}

ヘルスチェックが通れば完了。


API-ServerからKubeletへの認証

API-Serverから各Podを管理する為にはそれぞれのノードに配置されたKubeletへのアクセスが必要となる。まずはKubeletにアクセスする為のClusterRoleを定義する


Controller

#以下をコントローラーにて実行

$ cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:kube-apiserver-to-kubelet
rules:
- apiGroups:
- ""
resources:
- nodes/proxy
- nodes/stats
- nodes/log
- nodes/spec
- nodes/metrics
verbs:
- "*"
EOF
#以下の結果が返ってくれば成功
clusterrole "system:kube-apiserver-to-kubelet" created

このClusterRoleを実際にAPI-ServerがKubeletにアクセスする際に使用するユーザーと紐づける必要がある。このユーザーとはTLS認証編で記載した証明書発行のセクションにあるように、API-ServerのCNとして指定したkubernetesである。これはClusterRoleBindingの生成という方法で行う。


Controller

#以下をコントローラーにて実行

$ cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: system:kube-apiserver
namespace: ""
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:kube-apiserver-to-kubelet
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: kubernetes
EOF
#以下の結果が返ってくれば成功
clusterrolebinding "system:kube-apiserver" created


おわりに

etcdのインストールで少々躓いたが、それ以降は比較的順調に進んだ。(元のマニュアルの品質が高い)また、Kubernetesに限らずLinuxのsystemdのサービス定義にまで説明してくれているので、こういった事に疎い人間には大変参考になる。

次回はノード側の各種サービスをインストールする。