以下のドキュメントを参考にmasterの冗長化をやってみたのでメモしておきます。
http://kubernetes.io/docs/admin/high-availability/

ただし、”Kubernetesの高可用性サポートは、エンドツーエンド(e2e)テストでは継続的にテストされていません。”とか書いてあるので利用には注意が必要です。

ドキュメントを参考にmasterのha構成を作りますが、ドキュメントに書かれているpodのyamlは使わず、前回作成した環境に設定を追加していきます。

構成

システム構成は以下の通り。

kubernetes-ha.png

参考: http://kubernetes.io/images/docs/ha.svg

Worker NodeからはLoad Balancerを介してMaster Nodeに接続します。通信は全てhttpなのでLBはnginxを使います。LBはawsで構築するならelbとか置いたり環境に合わせて用意すれば良いと思います。Master Nodeは全てアクティブで3Node用意します。Master Nodeはetcdが状態を保持するので、このetcdを3台のクラスタにします。etcdがクラスタになっているのでmasterが1台落ちても動作するという仕組みになっています。今回はこの仕組みの動作確認までをやってみます。

クラスタはmaster3台とminion2台で作って、間にLBを1台はさみます。LBがSPOFなのは無視します。

ip hostname service
192.168.33.11 centos-lb-1 nginx
192.168.33.21 centos-master-1 etcd
kube-apiserver
kube-controller-manager
kube-scheduler
flanneld
192.168.33.22 centos-master-2 etcd
kube-apiserver
kube-controller-manager
kube-scheduler
flanneld
192.168.33.23 centos-master-3 etcd
kube-apiserver
kube-controller-manager
kube-scheduler
flanneld
192.168.33.31 centos-minion-1 kube-proxy
kubelet
flanneld
docker
192.168.33.32 centos-minion-2 kube-proxy
kubelet
flanneld
docker

下準備

今回もVagrantで上記の構成を作成します。

# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
config.vm.box = "centos/7"
config.vm.provision "shell", inline: <<-SHELL
yum install -y wget
cat << EOT > /etc/yum.repos.d/virt7-docker-common-release.repo
[virt7-docker-common-release]
name=virt7-docker-common-release
baseurl=http://cbs.centos.org/repos/virt7-docker-common-release/x86_64/os/
gpgcheck=0
EOT
yum -y install --enablerepo=virt7-docker-common-release kubernetes flannel
echo "192.168.33.11 centos-lb-1
192.168.33.21 centos-master-1
192.168.33.22 centos-master-2
192.168.33.23 centos-master-3
192.168.33.31 centos-minion-1
192.168.33.32 centos-minion-2" >> /etc/hosts

setenforce 0
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/sysconfig/selinux
SHELL
config.vm.define :lb1 do |node|
node.vm.network :private_network, ip: "192.168.33.11"
node.vm.provider "virtualbox" do |vb|
vb.memory = "1024"
end
end
config.vm.define :master1 do |node|
node.vm.network :private_network, ip: "192.168.33.21"
node.vm.provider "virtualbox" do |vb|
vb.memory = "2048"
end
end
config.vm.define :master2 do |node|
node.vm.network :private_network, ip: "192.168.33.22"
node.vm.provider "virtualbox" do |vb|
vb.memory = "2048"
end
end
config.vm.define :master3 do |node|
node.vm.network :private_network, ip: "192.168.33.23"
node.vm.provider "virtualbox" do |vb|
vb.memory = "2048"
end
end
config.vm.define :minion1 do |node|
node.vm.network :private_network, ip: "192.168.33.31"
node.vm.provider "virtualbox" do |vb|
vb.memory = "2048"
end
end
config.vm.define :minion2 do |node|
node.vm.network :private_network, ip: "192.168.33.32"
node.vm.provider "virtualbox" do |vb|
vb.memory = "2048"
end
end
end

前回同様にkubernetesのレポジトリなどを設定しておきます。firewalldが起動してあるのであれば、ここで停止しておきます。

サーバを起動します。

$ vagrant up

masterの設定

まずはmasterでetcdのクラスタが作りたいので、centos-master-[123]でetcdの設定をします。
centos-master-1から設定します。

root$ yum install etcd -y

以下の様にetcdの設定ファイルに記述します。
ETCD_NAMEでノード毎に名前をつけて、クラスタのメンバー情報を記述します。

root$ grep -v "^#" /etc/etcd/etcd.conf
ETCD_NAME=master1
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="http://centos-master-1:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://centos-master-1:2380"
ETCD_INITIAL_CLUSTER="master1=http://centos-master-1:2380,master2=http://centos-master-2:2380,master3=http://centos-master-3:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_ADVERTISE_CLIENT_URLS="http://0.0.0.0:2379"

設定が終わったらetcdを起動します。

root$ systemctl start etcd

centos-master-[23]はcentos-master-1で作成したetcdに追加するのでETCD_INITIAL_CLUSTER_STATEは設定せずに起動します。

master2設定ファイルは次の通りです。master3も同様に設定します。

root$ grep -v "^#" /etc/etcd/etcd.conf
ETCD_NAME=master2
ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_PEER_URLS="http://centos-master-2:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://centos-master-2:2380"
ETCD_INITIAL_CLUSTER="master1=http://centos-master-1:2380,master2=http://centos-master-2:2380,master3=http://centos-master-3:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
ETCD_ADVERTISE_CLIENT_URLS="http://0.0.0.0:2379"

master2, master3のetcdを起動します。起動するだけでクラスタにメンバーとして追加されます。

root$ systemctl start etcd

起動後、etcdが正しく動作しているか確認します。正しく設定できている場合は次の様にクラスタのメンバーが表示されることが確認できるはずです。

root$ etcdctl member list
7e58aa0ad17c572: name=master2 peerURLs=http://centos-master-2:2380 clientURLs=http://0.0.0.0:2379 isLeader=false
3708325235b44bf0: name=master3 peerURLs=http://centos-master-3:2380 clientURLs=http://0.0.0.0:2379 isLeader=false
a49d68bfe3a3090b: name=master1 peerURLs=http://centos-master-1:2380 clientURLs=http://0.0.0.0:2379 isLeader=true

root$ etcdctl cluster-health
member 7e58aa0ad17c572 is healthy: got healthy result from http://0.0.0.0:2379
member 3708325235b44bf0 is healthy: got healthy result from http://0.0.0.0:2379
member a49d68bfe3a3090b is healthy: got healthy result from http://0.0.0.0:2379
cluster is healthy

master1がLeaderとなっていることが確認できます。

試しに、ETCDのクラスタに読み書きしてみます。

root@centos-master-1$ etcdctl set foo bar
bar
root@centos-master-2$ etcdctl get foo
bar

正しく動作している場合は、centos-master-1でfoo=barと書き込みするとcentos-master-2でfooをgetするとbarと書き込んだ内容が表示されます。

etcdのクラスタ設定は完了したのでmasterの設定をしていきます。

etcdにkubernetesの設定をします。

root$ etcdctl mkdir /kube-centos/network
root$ etcdctl mk /kube-centos/network/config '{ "Network": "172.30.0.0/16", "SubnetLen": 24, "Backend": { "Type": "vxlan" } }'

centos-master-[123]で以下の設定をします。

root$ cat /etc/kubernetes/config
# Comma separated list of nodes in the etcd cluster
KUBE_ETCD_SERVERS="--etcd-servers=http://centos-master-N:2379"

# logging to stderr means we get it in the systemd journal
KUBE_LOGTOSTDERR="--logtostderr=true"

# journal message level, 0 is debug
KUBE_LOG_LEVEL="--v=0"

# Should this cluster be allowed to run privileged docker containers
KUBE_ALLOW_PRIV="--allow-privileged=false"

# How the controller-manager, scheduler, and proxy find the apiserver
KUBE_MASTER="--master=http://centos-master-N:8080"

api-serverの設定。api-serverが接続するetcdはローカルのetcdのみにしておきます。

root$ cat /etc/kubernetes/apiserver
# The address on the local server to listen to.
KUBE_API_ADDRESS="--insecure-bind-address=0.0.0.0"

# The port on the local server to listen on.
# KUBE_API_PORT="--port=8080"

# Port minions listen on
# KUBELET_PORT="--kubelet-port=10250"

# Comma separated list of nodes in the etcd cluster
KUBE_ETCD_SERVERS="--etcd-servers=http://127.0.0.1:2379"

# Address range to use for services
KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16"

# default admission control policies
#KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ServiceAccount,ResourceQuota"

# Add your own!
KUBE_API_ARGS=""

flanneldの設定。ここもflanneldが参照するetcdはローカルのものだけ指定します。

root$ cat /etc/sysconfig/flanneld
# etcd url location. Point this to the server where etcd runs
FLANNEL_ETCD_ENDPOINTS="http://centos-master-N:2379"

# etcd config key. This is the configuration key that flannel queries
# For address range assignment
FLANNEL_ETCD_PREFIX="/kube-centos/network"

# Any additional options that you want to pass
FLANNEL_OPTIONS="--iface=eth1"

masterで使うサービスを起動します。

root$ for SERVICES in etcd kube-apiserver kube-controller-manager kube-scheduler flanneld; do
systemctl restart $SERVICES;
systemctl enable $SERVICES;
systemctl status $SERVICES;
done

LBの設定

centos-lb-1にnginxをインストールします。

root$ yum install -y epel-release
root$ yum install -y nginx
root$ systemctl enable nginx

次の2つのProxy設定を追加します。

  • minionのflanneldがmasterのetcdに接続するための設定
  • minionのkubeletがapi-serverに接続するための設定
root$ cat /etc/nginx/conf.d/api-server.conf
upstream api_server {
server centos-master-1:8080;
server centos-master-2:8080 backup;
server centos-master-3:8080 backup;
}

server {
listen 8080;
location / {
proxy_pass http://api_server;
}
}
root$ cat /etc/nginx/conf.d/etcd.conf
upstream etcd {
server centos-master-1:2379;
server centos-master-2:2379 backup;
server centos-master-3:2379 backup;
}

server {
listen 2379;
location / {
proxy_pass http://etcd;
}
}

設定追加後、nginxを起動します。

root$ systemctl start nginx

curlで他のノードから接続するとapi-serverのレスポンスが返ってくることが確認できます。

root$ curl centos-lb-1:8080

minionの設定

centos-minion-[12]でminionの設定をします。

まず、minionで使うdockerをインストールします。

root$ yum install -y docker

kubeletの設定をします。ここで、api-serverにはlb経由で接続する設定をしておきます。KUBELET_API_SERVERという設定項目なのに–api-serversと複数形になっているところが謎ですね。KUBELET_HOSTNAMEはhost毎に読み替える必要があります。

# The address for the info server to serve on (set to 0.0.0.0 or "" for all interfaces)
KUBELET_ADDRESS="--address=0.0.0.0"

# The port for the info server to serve on
# KUBELET_PORT="--port=10250"

# You may leave this blank to use the actual hostname
KUBELET_HOSTNAME="--hostname-override=centos-minion-1"

# location of the api-server
KUBELET_API_SERVER="--api-servers=http://centos-lb-1:8080"

# pod infrastructure container
KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest"

# Add your own!
KUBELET_ARGS=""

flanneldも同様にlbに接続するように設定します。

root$ cat /etc/sysconfig/flanneld
# Flanneld configuration options

# etcd url location. Point this to the server where etcd runs
FLANNEL_ETCD_ENDPOINTS="http://centos-lb-1:2379"

# etcd config key. This is the configuration key that flannel queries
# For address range assignment
FLANNEL_ETCD_PREFIX="/kube-centos/network"

# Any additional options that you want to pass
FLANNEL_OPTIONS="--iface=eth1"

minionを登録します。

root$ kubectl config set-cluster default-cluster --server=http://centos-lb-1:8080
root$ kubectl config set-context default-context --cluster=default-cluster --user=default-admin
root$ kubectl config use-context default-context

動作確認

まず、nodeが登録されているか確認します。正しく登録されている場合は以下の様に表示されるはずです。

root$ kubectl get nodes
NAME STATUS AGE
centos-minion-1 Ready 3m
centos-minion-2 Ready 3m

前回と同様にdashboardをインストールして動作確認をしてみます。dashboardのyamlはapiserverの部分だけlbのアドレスに書き換えます。

root$ wget https://rawgit.com/kubernetes/dashboard/master/src/deploy/kubernetes-dashboard.yaml
root$ vi kubernetes-dashboard.yaml
- --apiserver-host=http://192.168.33.11:8080
root$ kubectl create --v=10 -f kubernetes-dashboard.yaml --server http://centos-lb-1:8080

しばらくすると起動するので待ちます。実行直後、Terminatingと表示されましたがすぐに起動を確認できました。

root$ kubectl get pods --all-namespaces -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE
kube-system kubernetes-dashboard-3331431211-5hvh3 0/1 Pending 0 38s <none> centos-minion-2
kube-system kubernetes-dashboard-3331431211-80k42 0/1 Terminating 0 38s <none> centos-minion-2
kube-system kubernetes-dashboard-3331431211-yte49 0/1 Terminating 0 38s <none> centos-minion-1
root$ kubectl get pods --all-namespaces -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE
kube-system kubernetes-dashboard-3331431211-5hvh3 1/1 Running 0 7m 172.30.60.2 centos-minion-2

lbのアドレスhttp://192.168.33.11:8080/uiに接続するとdashboardが表示されます。

master1を停止

master1を停止してpodを作ってみます。

$ vagrant halt master1
==> master1: Attempting graceful shutdown of VM...

$ vagrant status
Current machine states:

lb1 running (virtualbox)
master1 poweroff (virtualbox)
master2 running (virtualbox)
master3 running (virtualbox)
minion1 running (virtualbox)
minion2 running (virtualbox)
root$ etcdctl member list
7e58aa0ad17c572: name=master2 peerURLs=http://centos-master-2:2380 clientURLs=http://0.0.0.0:2379 isLeader=true
3708325235b44bf0: name=master3 peerURLs=http://centos-master-3:2380 clientURLs=http://0.0.0.0:2379 isLeader=false
a49d68bfe3a3090b: name=master1 peerURLs=http://centos-master-1:2380 clientURLs=http://0.0.0.0:2379 isLeader=false

master1が落ちたのでmaster2がLeaderになっていることが確認できます。

適当なpodをデプロイしてみます。

$ cat nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx-container
image: nginx
ports:
- containerPort: 80

root$ kubectl create --v=10 -f nginx-pod.yaml --server http://centos-lb-1:8080
pod "nginx-pod" created

しばらくするとpodがrunningになる。

root$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
nginx-pod 1/1 Running 0 4m 172.30.20.2 centos-minion-1

master1を落としてもmaster2でmasterの機能が動作していることが確認できました。なかなかいい感じですね。

おわり。

参考

  1. http://kubernetes.io/docs/admin/high-availability/
  2. http://kubernetes.io/docs/admin/high-availability/etcd.yaml
  3. http://kubernetes.io/docs/admin/high-availability/kube-scheduler.yaml
  4. http://kubernetes.io/docs/admin/high-availability/kube-controller-manager.yaml
  5. http://kubernetes.io/docs/admin/high-availability/kube-apiserver.yaml
  6. https://coreos.com/etcd/docs/latest/clustering.html
  7. https://coreos.com/etcd/docs/latest/etcd-live-cluster-reconfiguration.html
  8. http://kubernetes.io/docs/user-guide/kubectl/kubectl_api-versions/