高可用性Kubernetes Clusterを構築する-その1

検証用に高可用性のKubernetes Clusterを、kubeadmの公式ガイドを参考にVagrant環境にインストールする方法をまとめました。

私が担当している某BGM配信サービスでKubernetesを使用していますが、最近のバージョンではなかなか上がらなかった推奨Dockerバージョンが上り、標準のDNSがCoreDNSに変更されていたりするので、バージョンアップした方が良い気がしてきました。ですが、マメにバージョンアップしていなかったせいで、バージョンアップが難しい状況になっています。そこで、一から構築する方法をとりました。 構築はkubeadmを使用します。このKubernetes Clusterの構築方法はkubeadmのバージョンアップと共に変わってきており、今回はv1.13で紹介されている方法で構築します。

構成

OSはUbuntu 18.04LTSを使用し、kubernetesはVersion 1.13、kube-apiserver用のロードバランサを1台、Control Plane Node兼ワーカー共用ホストを3台の全4台のサーバを準備します。 こちら(https://kubernetes.io/docs/setup/independent/ha-topology/)の説明にあるように本来Control Plane Nodeとワーカーを別ホストにする方が安定性は良いのですが、構築の検証用のため、この構成で構築したいと思います。 これらのサーバは、メモリの最低の推奨環境が2Gbなので、それぞれメモリを2Gbにしています。

ホスト名 IPアドレス 役割
host1 192.168.33.21 APIロードバランサー
host2 192.168.22.22 Kubernetes control plane node/worker1
host3 192.168.22.23 Kubernetes control plane node/worker2
host4 192.168.22.24 Kubernetes control plane node/worker3

構築用のVgrantファイル

構築用のVagrantファイルは以下のようにしました。一度に4台のサーバを立ち上げます。

# -*- mode: ruby -*-
# vi: set ft=ruby :

HOST_COUNT = 4
BOX_IMAGE = "ubuntu/bionic64"

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
  # The most common configuration options are documented and commented below.
  # For a complete reference, please see the online documentation at
  # https://docs.vagrantup.com.

  # Every Vagrant development environment requires a box. You can search for
  # boxes at https://atlas.hashicorp.com/search.
  config.vm.box = BOX_IMAGE

  # Disable automatic box update checking. If you disable this, then
  # boxes will only be checked for updates when the user runs
  # `vagrant box outdated`. This is not recommended.
  # config.vm.box_check_update = false

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # config.vm.network "forwarded_port", guest: 80, host: 8080

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  #config.vm.network "private_network", ip: "192.168.33.20"

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  # config.vm.network "public_network"

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  # config.vm.synced_folder "../data", "/vagrant_data"

  # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies
  # such as FTP and Heroku are also available. See the documentation at
  # https://docs.vagrantup.com/v2/push/atlas.html for more information.
  # config.push.define "atlas" do |push|
  #   push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME"
  # end
  #config.vm.synced_folder ".", "/vagrant_data"

  (1..HOST_COUNT).each do |i|
    config.vm.define "host#{i}" do |subconfig|
      subconfig.vm.box = BOX_IMAGE
      subconfig.vm.hostname = "host#{i}"
      subconfig.vm.network :private_network, ip: "192.168.33.#{i + 20}"

      subconfig.vm.provider "virtualbox" do |vb1|
        # Display the VirtualBox GUI when booting the machine
        # Customize the amount of memory on the VM:
        vb1.memory = "2048"
        vb1.customize ["modifyvm", :id, "--paravirtprovider", "kvm"]
      end
    end
  end
  
  # Enable provisioning with a shell script. Additional provisioners such as
  # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
  # documentation for more information about their specific syntax and use.  config.vm.provision "shell", inline: "sudo apt install -y python"

  config.vm.provision "shell", inline: <<-SHELL
    sudo apt-get update
    sudo apt-get install -y python python-simplejson language-pack-ja-base language-pack-ja
  SHELL
end

ロードバランサーの構築

kube-apiserver用のロードバランサーを構築します。ロードバランサのソフトウェアは、haproxyを使用します。

haproxyのセットアップ

apt install haproxy

haproxyの設定

haproxyの設定は、/etc/haproxy/haproxy.cnfに以下のように設定します。

global
    log /dev/log    local0
    log /dev/log    local1 notice
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    stats timeout 30s
    user haproxy
    group haproxy
    daemon

    # Default SSL material locations
    ca-base /etc/ssl/certs
    crt-base /etc/ssl/private

    # Default ciphers to use on SSL-enabled listening sockets.
    # For more information, see ciphers(1SSL). This list is from:
    #  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
    # An alternative list with additional directives can be obtained from
    #  https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy
    ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS
    ssl-default-bind-options no-sslv3

defaults
    log global
    mode    http
    option  httplog
    option  dontlognull
    timeout connect 5000
    timeout client  50000
         timeout server  50000
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.http
    errorfile 500 /etc/haproxy/errors/500.http
    errorfile 502 /etc/haproxy/errors/502.http
    errorfile 503 /etc/haproxy/errors/503.http
    errorfile 504 /etc/haproxy/errors/504.http

frontend kubeapi
    bind *:6443
    mode tcp
    option tcplog
    default_backend kube_cp

backend kube_cp
    mode tcp
    option tcplog
    option tcp-check
    balance roundrobin
    server host2    192.168.33.22:6443 check port 6443
    server host3    192.168.33.23:6443 check port 6443
    server host4    192.168.33.24:6443 check port 6443

設定後、haproxyを再起動します。

sudo systemctl restart haproxy

前準備

クラスタを構成するホストに、docker、kubelet、kubeadminをインストールします。以下の設定は、全てのホストに対して実行します。

swapを無効にする

swapを無効にすることがKubenetes nodeサーバに対して必須構成なので、swapを無効にします。 vagrantで使用するboxによってはswapがない場合もあるので、この場合は設定しなくて大丈夫です。

sudo swapoff -a

vm.swappinessの設定を0にします。起動後も有効になるように、/etc/sysctl.confに以下の行を追加します。

vm.swappiness = 0

再読み込みします。

sudo sysctl -p

以下のコマンドでswap領域を確認できるので、このパーティションを/etc/fstabから削除します。 fstabのパーティションタイプがswap担っているので、この行を削除すると良いです。

cat /proc/swaps

Dockerのインストール

Dockerをインストールします。kubernetesではDockerはバージョン(18.06.0)が指定されているので、指定されたバージョンをインストールします。 これと違うバージョンではkubernetesが動作しないようです。

sudo su

# Install Docker CE
## Set up the repository:
### Update the apt package index
    apt-get update

### Install packages to allow apt to use a repository over HTTPS
    apt-get update && apt-get install apt-transport-https ca-certificates curl software-properties-common

### Add Docker’s official GPG key
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -

### Add docker apt repository.
    add-apt-repository \
    "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
    $(lsb_release -cs) \
    stable"

## Install docker ce.
apt-get update && apt-get install -y docker-ce=18.06.0~ce~3-0~ubuntu

# Setup daemon.
cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

mkdir -p /etc/systemd/system/docker.service.d

# Restart docker.
systemctl daemon-reload
systemctl restart docker

kubelet kubeadm kubectlのインストール

以下のコマンドをルートユーザで実行します。

apt-get update && apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

Masterノードのcgroup driverを設定

Masterノードの場合はcfgroup driverを指定します。 今回dockerを使用するので、kubeadmが自動的に認識して/var/lib/kubelet/kubeadm-flags.env に設定してくれます。

hostsファイルにホストを設定

/etc/hostsに各ホストが名前で参照できるように、以下の行を追加してIPアドレスを設定します。

192.168.33.21  host1
192.168.33.22  host2
192.168.33.23  host3
192.168.33.24  host4

1台目(host2)からsshログインできるようにする

1台目(host2)からhost3, host4へsshログインできるように設定します。この設定は、作成した証明書やキーファイルを各ホストにコピーするために行います。

sshキー作成

rootユーザでパスワード無しのsshkeyをhost2で作成します。

vagrant@host2:~$ sudo su
root@host2:/home/vagrant# ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:VyAkqa3mKCEP0Q0h5gzGmfu6ZZ7qW7JR6r07i+gPGng your_email@example.com
The key's randomart image is:
+---[RSA 4096]----+
|+o+.  .oo .      |
|*=.   .. . .     |
| +.o o      .    |
|... o .    .     |
| ... .  S .      |
|= o.o    .       |
|+OEB             |
|=+#.o            |
|=@=O=            |
+----[SHA256]-----+
root@host2:/home/vagrant# cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys

他のホストへログインできるように設定

作成したキーファイルの公開鍵を他のホストにコピーしてhost2からsshログインできるようにします。

作成したキーを一時的に/vagrantディレクトリ(vagrantで設定されたホストと共有するフォルダ)へコピー

root@host2:/home/vagrant# cp /root/.ssh/id_rsa.pub /vagrant
oot@host2:/home/vagrant# exit
exit
vagrant@host2:~$ exit
ログアウト
Connection to 127.0.0.1 closed.

コピーしたファイルを他のホストへ設定

$ vagrant ssh host3

Welcome to Ubuntu 18.04.1 LTS (GNU/Linux 4.15.0-43-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sun Jan 20 00:51:17 UTC 2019

  System load:  0.0               Processes:             93
  Usage of /:   14.5% of 9.63GB   Users logged in:       0
  Memory usage: 6%                IP address for enp0s3: 10.0.2.15
  Swap usage:   0%                IP address for enp0s8: 192.168.33.23


  Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

0 個のパッケージがアップデート可能です。
0 個のアップデートはセキュリティアップデートです。


Last login: Sun Jan 20 00:02:09 2019 from 10.0.2.2

vagrant@host3:~$ cat /vagrant/id_rsa.pub >> ~/.ssh/authorized_keys

同じように、host4へもコピーします。操作は同じなので記載は省略します。

確認

host2へログインして、以下のように接続確認します。

ssh-agent起動

sudo su
root@host2:/home/vagrant# eval $(ssh-agent)
Agent pid 1044

キーを追加

root@host2:/home/vagrant# ssh-add ~/.ssh/id_rsa
Identity added: /root/.ssh/id_rsa (/root/.ssh/id_rsa)

接続

root@host2:/home/vagrant# ssh -A host3
The authenticity of host 'host3 (192.168.33.23)' can't be established.
ECDSA key fingerprint is SHA256:m4aEJu5UA1Bz/ervjgQhlJ+aYUkktASYv9krfbmV2PI.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'host3' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 18.04.1 LTS (GNU/Linux 4.15.0-43-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sun Jan 20 01:37:20 UTC 2019

  System load:  0.0               Processes:             96
  Usage of /:   14.0% of 9.63GB   Users logged in:       0
  Memory usage: 6%                IP address for enp0s3: 10.0.2.15
  Swap usage:   0%                IP address for enp0s8: 192.168.33.23

 * MicroK8s is Kubernetes in a snap. Made by devs for devs.
   One quick install on a workstation, VM, or appliance.

   - https://bit.ly/microk8s

 * Full K8s GPU support is now available!

   - https://blog.ubuntu.com/2018/12/10/using-gpgpus-with-kubernetes


  Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

0 個のパッケージがアップデート可能です。
0 個のアップデートはセキュリティアップデートです。



The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

root@host3:~# exit
ログアウト
Connection to host3 closed.
root@host2:/home/vagrant#

同じようにhost4に対しても行います。以上でClusterを構築する前準備が完了です。 次に、Clusterを構築します。続きは次の投稿で。