kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

〜スマートスピーカーやVoiceflowの記事は右メニューのカテゴリからどうぞ。〜

kubeadm on Vagrantでマルチマスターやってみた①

※2020/03/08追記 k8sのセットアップを行うプロビジョニング用スクリプト(scripts/common/00-setup-k8s.sh)については少し変更しています。

前回のhard wayでなんとなくk8sの雰囲気がわかったので、今度はkubeadmを使ってマルチマスターをやってみたいと思います。

ざっとググってみたけど、kubeadmはシングルマスターの記事が多いのと、さらにvagrantになると少しvirtualbox特有のクセみたいなものもあって、なかなかマルチマスターk8s on vagrantな記事はお目にかかりません。であればやってみようというのが今回の目的です。

以下要件。

  • ネットワーク構成は基本的にhard wayを踏襲します。
  • vagrant上で構築します。お手軽だしオンプレに近い環境つくれると思うので。
  • マルチマスター構成、ただしetcdはstacked(さすがにVM台数的に辛い)
    • master x 3
    • worker x 3
    • loadbalancer x 1 ※ master用
  • 構築はkubeadmを使います。
  • CNIはCalico、といってもflannelとあまりよく違いがわかってないけど、Calicoの仕様によりpodネットワークは192.168.0.0/16になります。

こんな感じ。

f:id:kun432:20200224235455p:plain

Vagrant

レポジトリは以下にあります。最初に少しVagrant部分の説明をします。

github.com

Vagrantfile

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

Vagrant.configure("2") do |config|
  config.vm.box = "centos/7"

  config.vm.provider "virtualbox" do |vb|
    vb.memory = "512"
  end

  config.vm.synced_folder "./share", "/Vagrant" , type: "virtualbox"

  # must be at the top
  config.vm.define "lb-0" do |c|
      c.vm.hostname = "lb-0"
      c.vm.network "private_network", ip: "10.240.0.40"

      c.vm.provision :shell, :path => "scripts/common/00-setup-initial.sh"
      c.vm.provision :shell, :path => "scripts/lb/setup-haproxy.sh"

      c.vm.provider "virtualbox" do |vb|
        vb.memory = "256"
      end
  end

  (0..2).each do |n|
    config.vm.define "controller-#{n}" do |c|
        c.vm.hostname = "controller-#{n}"
        c.vm.network "private_network", ip: "10.240.0.1#{n}"
        c.vm.provider "virtualbox" do |v|
          v.gui = false
          v.cpus = 2
          v.memory = 2048
        end

        c.vm.provision :shell, :path => "scripts/common/00-setup-initial.sh"
        c.vm.provision :shell, :path => "scripts/common/00-setup-k8s.sh"
    end
  end

  (0..2).each do |n|
    config.vm.define "worker-#{n}" do |c|
        c.vm.hostname = "worker-#{n}"
        c.vm.network "private_network", ip: "10.240.0.2#{n}"
        c.vm.provider "virtualbox" do |v|
          v.gui = false
          v.cpus = 1
          v.memory = 1024
        end

        c.vm.provision :shell, :path => "scripts/common/00-setup-initial.sh"
        c.vm.provision :shell, :path => "scripts/common/00-setup-k8s.sh"
    end
  end

end

これでloadbalancer x 1、master x 3、worker x 3を構築します。結構リソースは必要です。プロビジョニングでスクリプトをそれぞれ呼んでいます。ちなみにsynced_folderを使っているのは、master間でファイルの受け渡しが発生するためです(sshの設定するのがめんどくさかった)

プロビジョニングで使っているスクリプトの中身はこんな感じです。

scripts/common/00-setup-initial.sh

全台共通で使っています。hostsファイルの設定、SELinuxの停止、firewalldの停止だけです。

#!/bin/bash

set -euo pipefail

cat <<EOF | sudo tee -a /etc/hosts
10.240.0.10 controller-0
10.240.0.11 controller-1
10.240.0.12 controller-2
10.240.0.20 worker-0
10.240.0.21 worker-1
10.240.0.22 worker-2
EOF

# disable SELinux
sudo setenforce 0
sudo sed -i -e "s/^SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config

# disable firewalld
sudo systemctl stop firewalld
sudo systemctl disable firewalld

scripts/lb/setup-haproxy.sh

loadbalancer用のスクリプトです。haproxyの設定を行っています。これはhard wayのものをそのままにいくつかコメントアウトしただけです。(hard wayはubuntuベース、こちらはcentos

#!/bin/bash

set -euo pipefail

yum update -y
yum install -y haproxy

grep -q -F 'net.ipv4.ip_nonlocal_bind=1' /etc/sysctl.conf || echo 'net.ipv4.ip_nonlocal_bind=1' >> /etc/sysctl.conf

cat >/etc/haproxy/haproxy.cfg <<EOF
global
    log /dev/log    local0
    log /dev/log    local1 notice
    chroot /var/lib/haproxy
    #stats socket /run/haproxy/admin.sock mode 660 level admin
    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/
    ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS
    ssl-default-bind-options no-sslv3
defaults
    log global
    mode    tcp
    option  tcplog
    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 k8s
    bind 10.240.0.40:6443
    default_backend k8s_backend
backend k8s_backend
    balance roundrobin
    mode tcp
    server controller-0 10.240.0.10:6443 check inter 1000
    server controller-1 10.240.0.11:6443 check inter 1000
    server controller-2 10.240.0.12:6443 check inter 1000
EOF

systemctl restart haproxy
systemctl enable haproxy

scripts/common/00-setup-k8s.sh

masterとworker用にk8sコンポーネントのインストールと基本設定を行っています。kubernetesやdockerのバージョンは決め打ちにしています。バージョンコントロールは自分で制御したいので。

#!/bin/bash

set -euo pipefail

KUBERNETES_VERSION=1.17.3
DOCKER_VERSION=19.03.4
CONTAINERD_VERSION=1.2.10

# disable swap off
sudo swapoff -a
sudo sed -i '/ swap /s/^\(.*\)$/#\1/g' /etc/fstab
sudo rm -rf /swapfile

# install kubernetes repository
cat <<EOF | sudo tee -a /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
exclude=kube*
EOF

# install kubeadm, kubelet, kubectl
sudo yum install -y kubelet-${KUBERNETES_VERSION} kubeadm-${KUBERNETES_VERSION} kubectl-${KUBERNETES_VERSION} --disableexcludes=kubernetes

# enable kubelet
sudo systemctl enable --now kubelet

# enable network bridge
cat <<'EOF' | sudo tee -a /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sudo sysctl --system

# install docker
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install -y --setopt=obsoletes=0 docker-ce-$DOCKER_VERSION docker-ce-cli-$DOCKER_VERSION containerd.io-${CONTAINERD_VERSION}
sudo systemctl enable docker && sudo systemctl start docker
sudo usermod -aG docker vagrant

# cgoup
sudo mkdir -p /etc/docker
cat <<'EOF' | sudo tee -a /etc/docker/daemon.json
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ]
}
EOF
sudo mkdir -p /etc/systemd/system/docker.service.d

# Restart Docker
sudo systemctl daemon-reload
sudo systemctl restart docker

# get private network IP addr and set bind it to kubelet
IPADDR=$(ip a show eth1 | grep inet | grep -v inet6 | awk '{print $2}' | cut -f1 -d/)
sudo sed -i "/KUBELET_EXTRA_ARGS=/c\KUBELET_EXTRA_ARGS=--node-ip=$IPADDR" /etc/sysconfig/kubelet

# restart kubelet
sudo systemctl daemon-reload
sudo systemctl restart kubelet

やっていることはざっくりこんな感じ。

  • kubernetesを動かすにはswapを無効にする必要があります。単純にfstabコメントアウトするだけではダメで、swapファイル自体も消してます。
  • kubernetesyumレポジトリを追加
  • kubeadm, kubelet, kubectlをインストール
  • ネットワークブリッジを有効化するためのカーネルパラメータを変更
  • dockerをインストール
  • dockerでgroupドライバーとしてsystemdを使う設定を追加
  • dockerを再起動
  • vagrant、というかvirtualboxでは標準でNAT用インタフェースとして10.0.2.15が割り当てられますが、これはホスト間の通信に使えません。kubeletは標準でこれをバインドしようとするので、これを回避するために設定を追加
  • kubeletを再起動

Vagrantの起動

master/worker専用のプロビジョニング用ファイルとかもあるんですが、まだ未完成なのでとりあえず進めます。

レポジトリをcloneします。

$ git clone https://github.com/kun432/kubernetes-by-kubeadm-on-vagrant.git
$ cd kubernetes-by-kubeadm-on-vagrant

vagrant upでVMを起動します。結構時間がかかります。マシンパワーがないと辛いかもしれません。

$ vagrant up

7台起動していればOKです。

$ vagrant status
Current machine states:

lb-0                      running (virtualbox)
controller-0              running (virtualbox)
controller-1              running (virtualbox)
controller-2              running (virtualbox)
worker-0                  running (virtualbox)
worker-1                  running (virtualbox)
worker-2                  running (virtualbox)

This environment represents multiple VMs. The VMs are all listed
above with their current state. For more information about a specific
VM, run `vagrant status NAME`.

今日はここまで。プロビジョニングしかできていない・・・次回はmaster/workerの設定について。

なお、プロビジョニング用スクリプトは以下を参考にさせてもらいました。ありがとうございます。

qiita.com