Vagrant
kubernetes

VagrantでkubeadmでKubernetesを起動する

今更ながらのVagrantの勉強を兼ね、vagrant upでKubernetesクラスターを簡単に起動するためのVagrantfileを作成したのでメモ。


参考資料


Vagrantfile

Masterはシングルで複数NodeのKubernetesクラスターを作成する。

注意すべき点は以下。


  • 各VMはNAT用に10.0.2.15という同じIP持っており、apiserverがそちらにバインドされてしまうため、kubeadm init--apiserver-advertise-addressなどを引数に設定

  • 同じくkubeletも10.0.2.15にバインドされてしまうため、kubeletの引数に--nodeipを指定する必要があり、そのためkubeletサービスのSystemdユニット定義から参照される/etc/default/kubelet(Ubuntu)または/etc/sysconfig/kubelet(CentOS)を修正する

  • Masterノード上で生成したkubeadm joinコマンドを、各Nodeはscpで取得して実行


Ubuntu

ネットワークプラグインはFlannelを使ってみる。


Vagrantfile

# -*- mode: ruby -*-

# vi: set ft=ruby :

$configureBox = <<-SHELL

# パッケージ更新
apt-get update
apt-get upgrade -y

# Dockerの前提パッケージ
apt-get install -y apt-transport-https ca-certificates curl software-properties-common
# Dockerのレポジトリ追加
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
# Dockerのインストール
apt-get update
apt-get install -y docker-ce=$(apt-cache madison docker-ce | grep 17.03 | head -1 | awk '{print $3}')
apt-mark hold docker-ce
# vagrantユーザーをdockerグループに追加
usermod -aG docker vagrant

# Flannelの場合に必要
# デフォルトが1なのでコメントアウト
# echo net.bridge.bridge-nf-call-iptables = 1 >> /etc/sysctl.conf
# sysctl -p

# スワップを無効化する
# スワップ領域がないのでコメントアウト
# swapoff -a
# プロビジョニングで実行する場合はバックスラッシュのエスケープが必要なことに注意
# sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
# sed -i '/ swap / s/^
\\(.*\\)$/#\\1/g' /etc/fstab

# Kubernetesの前提パッケージ
# apt-get update
# apt-get install -y apt-transport-https curl
# Kubernetesのレポジトリ追加
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
# kubeadm、kubelet、kubectlのインストール
apt-get update
# apt-get install -y kubelet=1.12.2-00 kubeadm=1.12.2-00 kubectl=1.12.2-00
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

# プライベートネットワークのNICのIPアドレスを変数に格納
IPADDR=$(ip a show enp0s8 | grep inet | grep -v inet6 | awk '{print $2}' | cut -f1 -d/)
# kubeletがプライベートネットワークのNICにバインドするように設定
sed -i "/KUBELET_EXTRA_ARGS=/c\KUBELET_EXTRA_ARGS=--node-ip=$IPADDR" /etc/default/kubelet
# kubeletを再起動
systemctl daemon-reload
systemctl restart kubelet

SHELL

$configureMaster = <<-SHELL

echo "This is master"

# プライベートネットワークのNICのIPアドレスを変数に格納
IPADDR=$(ip a show enp0s8 | grep inet | grep -v inet6 | awk '{print $2}' | cut -f1 -d/)
# ホスト名を変数に格納
HOSTNAME=$(hostname -s)

# kubeadm initの実行
# Flannelの場合
kubeadm init --apiserver-advertise-address=$IPADDR --apiserver-cert-extra-sans=$IPADDR --node-name $HOSTNAME --pod-network-cidr=10.244.0.0/16
# Calicoの場合
# kubeadm init --apiserver-advertise-address=$IPADDR --apiserver-cert-extra-sans=$IPADDR --node-name $HOSTNAME --pod-network-cidr=192.168.0.0/16

# vagrantユーザーがkubectlを実行できるようにする
sudo --user=vagrant mkdir -p /home/vagrant/.kube
cp -i /etc/kubernetes/admin.conf /home/vagrant/.kube/config
chown $(id -u vagrant):$(id -g vagrant) /home/vagrant/.kube/config

# Flannelのインストール
export KUBECONFIG=/etc/kubernetes/admin.conf
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/bc79dd1505b0c8681ece4de4c0d86c5cd2643275/Documentation/kube-flannel.yml
# Calicoのインストール
# export KUBECONFIG=/etc/kubernetes/admin.conf
# kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml
# kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml

# kubectl joinコマンドを保存する
kubeadm token create --print-join-command > /etc/kubeadm_join_cmd.sh
chmod +x /etc/kubeadm_join_cmd.sh

# sshでのパスワード認証を許可する
sed -i "/^[^#]*PasswordAuthentication[[:space:]]no/c\PasswordAuthentication yes" /etc/ssh/sshd_config
systemctl restart sshd

SHELL

$configureNode = <<-SHELL

echo "This is worker"

apt-get install -y sshpass
sshpass -p "vagrant" scp -o StrictHostKeyChecking=no vagrant@192.168.33.11:/etc/kubeadm_join_cmd.sh .
# sshpass -p "vagrant" scp -o StrictHostKeyChecking=no vagrant@172.16.33.11:/etc/kubeadm_join_cmd.sh .
sh ./kubeadm_join_cmd.sh

SHELL

Vagrant.configure(2) do |config|

(1..3).each do |i|

if i == 1 then
vm_name = "master"
else
vm_name = "node#{i-1}"
end

config.vm.define vm_name do |s|

# ホスト名
s.vm.hostname = vm_name
# ノードのベースOSを指定
s.vm.box = "ubuntu/xenial64"
# ネットワークを指定
# pod-network-cidrと重ならないように注意
private_ip = "192.168.33.#{i+10}"
# private_ip = "172.16.33.#{i+10}"
s.vm.network "private_network", ip: private_ip

# ノードのスペックを指定
s.vm.provider "virtualbox" do |v|
v.gui = false
if i == 1 then
v.cpus = 2
v.memory = 1024
else
v.cpus = 1
v.memory = 1024
end
end

# 共通のプロビジョニング
s.vm.provision "shell", inline: $configureBox

if i == 1 then
# Masterのプロビジョニング
s.vm.provision "shell", inline: $configureMaster
else
# Nodeのプロビジョニング
s.vm.provision "shell", inline: $configureNode
end

end
end
end



CentOS

こちらはネットワークプラグインはCalicoを使ってみる。CalicoのPodネットワーク192.168.0.0/16と重ならないようにするため、VirtualBoxのプライベートネットワークは172.16.33.0/24を使用する。


Vagrantfile

# -*- mode: ruby -*-

# vi: set ft=ruby :

$configureBox = <<-SHELL

# パッケージ更新
yum update -y

# Dockerの前提パッケージ
yum install -y yum-utils device-mapper-persistent-data lvm2
# Dockerのレポジトリ追加
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# Dockerのインストール
VERSION=$(yum list docker-ce --showduplicates | sort -r | grep 17.03 | head -1 | awk '{print $2}')
yum install -y --setopt=obsoletes=0 docker-ce-$VERSION docker-ce-selinux-$VERSION
systemctl enable docker && systemctl start docker
# vagrantユーザーをdockerグループに追加
usermod -aG docker vagrant

# スワップを無効化する
swapoff -a
# プロビジョニングで実行する場合はバックスラッシュのエスケープが必要なことに注意
# sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
sed -i '/ swap / s/^
\\(.*\\)$/#\\1/g' /etc/fstab

# Kubernetesのレポジトリ追加
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
exclude=kube*
EOF

# SELinuxを無効化
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

# kubeadm、kubelet、kubectlのインストール
# yum install -y kubelet-1.12.2-0 kubeadm-1.12.2-0 kubectl-1.12.2-0 --disableexcludes=kubernetes
yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
systemctl enable kubelet && systemctl start kubelet

cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system

# プライベートネットワークのNICのIPアドレスを変数に格納
IPADDR=$(ip a show eth1 | grep inet | grep -v inet6 | awk '{print $2}' | cut -f1 -d/)
# kubeletがプライベートネットワークのNICにバインドするように設定
sed -i "/KUBELET_EXTRA_ARGS=/c\KUBELET_EXTRA_ARGS=--node-ip=$IPADDR" /etc/sysconfig/kubelet
# kubeletを再起動
systemctl daemon-reload
systemctl restart kubelet

SHELL

$configureMaster = <<-SHELL

echo "This is master"

# プライベートネットワークのNICのIPアドレスを変数に格納
IPADDR=$(ip a show eth1 | grep inet | grep -v inet6 | awk '{print $2}' | cut -f1 -d/)
# ホスト名を変数に格納
HOSTNAME=$(hostname -s)

# kubeadm initの実行
# Flannel
# kubeadm init --apiserver-advertise-address=$IPADDR --apiserver-cert-extra-sans=$IPADDR --node-name $HOSTNAME --pod-network-cidr=10.244.0.0/16
# Calico
kubeadm init --apiserver-advertise-address=$IPADDR --apiserver-cert-extra-sans=$IPADDR --node-name $HOSTNAME --pod-network-cidr=192.168.0.0/16

# vagrantユーザーがkubectlを実行できるようにする
sudo --user=vagrant mkdir -p /home/vagrant/.kube
cp -i /etc/kubernetes/admin.conf /home/vagrant/.kube/config
chown $(id -u vagrant):$(id -g vagrant) /home/vagrant/.kube/config

# Flannelのインストール
# export KUBECONFIG=/etc/kubernetes/admin.conf
# kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/bc79dd1505b0c8681ece4de4c0d86c5cd2643275/Documentation/kube-flannel.yml
# Calicoのインストール
export KUBECONFIG=/etc/kubernetes/admin.conf
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/rbac-kdd.yaml
kubectl apply -f https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml

# kubectl joinコマンドを保存する
kubeadm token create --print-join-command > /etc/kubeadm_join_cmd.sh
chmod +x /etc/kubeadm_join_cmd.sh

# sshでのパスワード認証を許可する
sed -i "/^[^#]*PasswordAuthentication[[:space:]]no/c\PasswordAuthentication yes" /etc/ssh/sshd_config
systemctl restart sshd

SHELL

$configureNode = <<-SHELL

echo "This is worker"

yum install -y sshpass
# sshpass -p "vagrant" scp -o StrictHostKeyChecking=no vagrant@192.168.33.11:/etc/kubeadm_join_cmd.sh .
sshpass -p "vagrant" scp -o StrictHostKeyChecking=no vagrant@172.16.33.11:/etc/kubeadm_join_cmd.sh .
sh ./kubeadm_join_cmd.sh

SHELL

Vagrant.configure(2) do |config|

(1..3).each do |i|

if i == 1 then
vm_name = "master"
else
vm_name = "node#{i-1}"
end

config.vm.define vm_name do |s|

# ホスト名
s.vm.hostname = vm_name
# ノードのベースOSを指定
s.vm.box = "centos/7"
# ネットワークを指定
# pod-network-cidrと重ならないように注意
# private_ip = "192.168.33.#{i+10}"
private_ip = "172.16.33.#{i+10}"
s.vm.network "private_network", ip: private_ip

# ノードのスペックを指定
s.vm.provider "virtualbox" do |v|
v.gui = false
if i == 1 then
v.cpus = 2
v.memory = 1024
else
v.cpus = 1
v.memory = 1024
end
end

# 共通のプロビジョニング
s.vm.provision "shell", inline: $configureBox

if i == 1 then
# Masterのプロビジョニング
s.vm.provision "shell", inline: $configureMaster
else
# Nodeのプロビジョニング
s.vm.provision "shell", inline: $configureNode
end

end
end
end



動作確認


Ubuntu

$ vagrant up

Bringing machine 'master' up with 'virtualbox' provider...
Bringing machine 'node1' up with 'virtualbox' provider...
Bringing machine 'node2' up with 'virtualbox' provider...
==> master: Importing base box 'ubuntu/xenial64'...
==> master: Matching MAC address for NAT networking...

(省略)

node2: Run 'kubectl get nodes' on the master to see this node join the cluster.
sotoiwa@sotonombp:~/workspace/vagrant-k8s-ubuntu
$ vagrant ssh master
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-140-generic x86_64)

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

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

0 packages can be updated.
0 updates are security updates.

New release '18.04.1 LTS' available.
Run 'do-release-upgrade' to upgrade to it.

*** System restart required ***
vagrant@master:~$ kubectl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master Ready master 3m34s v1.13.0 192.168.33.11 <none> Ubuntu 16.04.5 LTS 4.4.0-140-generic docker://17.3.3
node1 Ready <none> 2m3s v1.13.0 192.168.33.12 <none> Ubuntu 16.04.5 LTS 4.4.0-140-generic docker://17.3.3
node2 Ready <none> 37s v1.13.0 192.168.33.13 <none> Ubuntu 16.04.5 LTS 4.4.0-140-generic docker://17.3.3
vagrant@master:~$ kubectl get po --all-namespaces -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-system coredns-86c58d9df4-mkg9w 1/1 Running 0 3m26s 10.244.0.2 master <none> <none>
kube-system coredns-86c58d9df4-rkzfp 1/1 Running 0 3m26s 10.244.0.3 master <none> <none>
kube-system etcd-master 1/1 Running 0 2m39s 192.168.33.11 master <none> <none>
kube-system kube-apiserver-master 1/1 Running 0 2m41s 192.168.33.11 master <none> <none>
kube-system kube-controller-manager-master 1/1 Running 0 2m24s 192.168.33.11 master <none> <none>
kube-system kube-flannel-ds-amd64-27mm7 1/1 Running 0 48s 192.168.33.13 node2 <none> <none>
kube-system kube-flannel-ds-amd64-l8tj7 1/1 Running 0 2m14s 192.168.33.12 node1 <none> <none>
kube-system kube-flannel-ds-amd64-q6bhm 1/1 Running 0 3m26s 192.168.33.11 master <none> <none>
kube-system kube-proxy-bqpx8 1/1 Running 0 48s 192.168.33.13 node2 <none> <none>
kube-system kube-proxy-dltht 1/1 Running 0 3m26s 192.168.33.11 master <none> <none>
kube-system kube-proxy-gg6sl 1/1 Running 0 2m14s 192.168.33.12 node1 <none> <none>
kube-system kube-scheduler-master 1/1 Running 0 2m48s 192.168.33.11 master <none> <none>
vagrant@master:~$


CentOS

$ vagrant up

Bringing machine 'master' up with 'virtualbox' provider...
Bringing machine 'node1' up with 'virtualbox' provider...
Bringing machine 'node2' up with 'virtualbox' provider...
==> master: Importing base box 'centos/7'...
==> master: Matching MAC address for NAT networking...

(省略)

node2: Run 'kubectl get nodes' on the master to see this node join the cluster.
sotoiwa@sotonombp:~/workspace/vagrant-k8s-centos
$ vagrant ssh master
[vagrant@master ~]$ kubectl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
master Ready master 10m v1.13.0 172.16.33.11 <none> CentOS Linux 7 (Core) 3.10.0-862.14.4.el7.x86_64 docker://17.3.3
node1 Ready <none> 7m v1.13.0 172.16.33.12 <none> CentOS Linux 7 (Core) 3.10.0-862.14.4.el7.x86_64 docker://17.3.3
node2 Ready <none> 3m51s v1.13.0 172.16.33.13 <none> CentOS Linux 7 (Core) 3.10.0-862.14.4.el7.x86_64 docker://17.3.3
[vagrant@master ~]$ kubectl get po --all-namespaces -o wide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-system calico-node-24jkl 2/2 Running 0 7m7s 172.16.33.12 node1 <none> <none>
kube-system calico-node-dnjbb 2/2 Running 0 4m4s 172.16.33.13 node2 <none> <none>
kube-system calico-node-hhscc 2/2 Running 0 10m 172.16.33.11 master <none> <none>
kube-system coredns-86c58d9df4-hlmpt 1/1 Running 0 10m 192.168.0.2 master <none> <none>
kube-system coredns-86c58d9df4-phbjg 1/1 Running 0 10m 192.168.0.3 master <none> <none>
kube-system etcd-master 1/1 Running 0 9m30s 172.16.33.11 master <none> <none>
kube-system kube-apiserver-master 1/1 Running 0 9m2s 172.16.33.11 master <none> <none>
kube-system kube-controller-manager-master 1/1 Running 3 9m4s 172.16.33.11 master <none> <none>
kube-system kube-proxy-cmc72 1/1 Running 0 7m7s 172.16.33.12 node1 <none> <none>
kube-system kube-proxy-h5z7t 1/1 Running 0 4m4s 172.16.33.13 node2 <none> <none>
kube-system kube-proxy-kbgm5 1/1 Running 0 10m 172.16.33.11 master <none> <none>
kube-system kube-scheduler-master 1/1 Running 3 9m30s 172.16.33.11 master <none> <none>
[vagrant@master ~]$