Edited at

k3sをVagrantで構築する(3台構成)


はじめに

k3sという軽量なKubernetes環境があるということで、Vagrantで構築してみました。

Vagrantで構築する場合、ネットワーク設定(flannel)で注意点があるため記録を残します。


構成

以下のように、3台のUbuntu 16.04マシンをそれぞれ、master, node1, node2として構成し、Node間はプライベートネットワークで接続します。

image.png


flannelのVXLANインターフェースが適切に設定されない問題

こちらのissueの通りですが、そのままインストールするとNode間の通信ができません。

k3sで使われているCNIのflannelはVXLANトンネルを利用してNode間通信を行います。その時に利用するVXLANの出入口となるNICがデフォルトではNodeの一番最初のNICとなります。

Vagrantの場合、必ずNAT用のNICが最初に作成されてしまうため、デフォルトではNAT用のインターフェースが選択されてしまい都合が良くありません。

kubeadm等で構築する場合は、flanneldの実行引数--ifaceで明示的に指定可能ですが、k3sではflannelが組み込まれているため指定ができません。

そのため、今回はk3sでは--no-flannelフラグを付けてflannelインストールをスキップし、別途flannelをインストールしました。

なお、k3sの実行オプションとして--flannel-ifaceを付けるPRもあるため、取り込まれたらk3sのflannelを利用しても設定できるようになります。

--2019/4/26追記

マージされていました。


Master Nodeへk3sをインストール

公式のインストーラーを用いて以下のように設定します。INSTALL_K3S_EXECの環境変数を用いてオプションを渡してあげます。

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--no-flannel --node-ip=192.168.33.11" sh -

/var/lib/rancher/k3s/server/node-tokenにNode追加用のトークンが払い出されていますので、メモしておきます。


Node1,2を追加

先ほどメモしたトークンを用いてNode1, 2をagentとして追加します。以下はNode1用です。

export K3S_TOKEN=<トークン>

export K3S_URL=https://192.168.33.11:6443
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--no-flannel --node-ip=192.168.33.12" sh -


CNIプラグインのインストール

すべてのNodeにおいて、CNIプラグインを配置しておく必要があるため、あらかじめ公式のリリースページよりcni-plugins-xxxx.tgzをインストールし、/opt/cni/binに展開しておきます。


flannelをインストール

flannel自身のデプロイはkubectlを使って行います。

公式のマニフェストファイルをダウンロードして、以下のように修正します。

ポイントは以下の2点です。


  • flanneldのDaemonSetで起動オプションに--ifaceを追加


    • 以下の例はamd64用のDaemonSetに設定しましたが、環境にあわせて適切に設定してください。



  • CNI設定のConfigMapを環境にあわせて設定


    • k3sのデフォルトにあわせて10.42.0.0/16で設定しました。



--- kube-flannel.yaml.org       2019-03-21 09:28:45.427370300 +0000

+++ kube-flannel.yaml 2019-03-20 14:37:30.155241900 +0000
@@ -124,7 +124,7 @@
}
net-conf.json: |
{
- "Network": "10.244.0.0/16",
+ "Network": "10.42.0.0/16",
"Backend": {
"Type": "vxlan"
}
@@ -174,6 +174,7 @@
args:
- --ip-masq
- --kube-subnet-mgr
+ - --iface=enp0s8
resources:
requests:
cpu: "100m"

修正したファイルをkubectlで適用します。

vagrant@master:~$ kubectl apply -f kube-flannel.yaml


確認

以上で構築は完了しました。VXLANインターフェースの設定やNode間通信が問題ないかを確認します。


VXLANインターフェース

vagrant@master:~$ ip -d a show flannel.1

4: flannel.1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN group default
link/ether 6a:02:aa:4b:49:0d brd ff:ff:ff:ff:ff:ff promiscuity 0
vxlan id 1 local 192.168.33.11 dev enp0s8 srcport 0 0 dstport 8472 nolearning ageing 300
inet 10.42.0.0/32 scope global flannel.1
valid_lft forever preferred_lft forever
inet6 fe80::6802:aaff:fe4b:490d/64 scope link
valid_lft forever preferred_lft forever

プライベートのインターフェースが設定されています。


Node間通信

NginxのDeploymentを適当に作成しておきます。

vagrant@master:~$ kubectl run --image=nginx --replicas=5 nginx

kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
deployment.apps/nginx created
vagrant@master:~$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-7cdbd8cdc9-824qd 1/1 Running 0 25s 10.42.1.12 node1 <none> <none>
nginx-7cdbd8cdc9-9sct7 1/1 Running 0 25s 10.42.2.11 node2 <none> <none>
nginx-7cdbd8cdc9-bxfhb 1/1 Running 0 25s 10.42.2.12 node2 <none> <none>
nginx-7cdbd8cdc9-csd4p 1/1 Running 0 25s 10.42.1.13 node1 <none> <none>
nginx-7cdbd8cdc9-wcn9s 1/1 Running 0 25s 10.42.0.13 master <none> <none>


  • Master -> Pods の通信

vagrant@master:~$ ping 10.42.1.12 -c 1

PING 10.42.1.12 (10.42.1.12) 56(84) bytes of data.
64 bytes from 10.42.1.12: icmp_seq=1 ttl=63 time=0.425 ms

--- 10.42.1.12 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.425/0.425/0.425/0.000 ms

vagrant@master:~$ ping 10.42.2.11 -c 1
PING 10.42.2.11 (10.42.2.11) 56(84) bytes of data.
64 bytes from 10.42.2.11: icmp_seq=1 ttl=63 time=0.802 ms

--- 10.42.2.11 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.802/0.802/0.802/0.000 ms


  • Pod -> Pods の通信

vagrant@master:~$ kubectl run --generator=run-pod/v1 -it test --image=busybox /bin/sh

If you don't see a command prompt, try pressing enter.
/ # ping 10.42.0.13 -c 1
PING 10.42.0.13 (10.42.0.13): 56 data bytes
64 bytes from 10.42.0.13: seq=0 ttl=64 time=0.075 ms

--- 10.42.0.13 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.075/0.075/0.075 ms

/ # ping 10.42.1.12 -c 1
PING 10.42.1.12 (10.42.1.12): 56 data bytes
64 bytes from 10.42.1.12: seq=0 ttl=62 time=0.484 ms

--- 10.42.1.12 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.484/0.484/0.484 ms

/ # ping 10.42.2.11 -c 1
PING 10.42.2.11 (10.42.2.11): 56 data bytes
64 bytes from 10.42.2.11: seq=0 ttl=62 time=0.433 ms

--- 10.42.2.11 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.433/0.433/0.433 ms

すべて通信できることが確認できました。


Vagrantfile

最後に、すべてをまとめたVagrantファイルを以下に置いておきます。

kube-flannel.yamlは修正済みのものがすでにVagrantfileと同じフォルダに置かれているものとします。


Vagrantfile

# -*- mode: ruby -*-

# vi: set ft=ruby :

$configureCommon = <<-SHELL

# apt-get update
# apt-get upgrade -y

## cni pluginsを展開
mkdir -p /opt/cni/bin
curl -sSL https://github.com/containernetworking/plugins/releases/download/v0.7.5/cni-plugins-amd64-v0.7.5.tgz | tar xzf - -C /opt/cni/bin

SHELL

$configureMaster = <<-SHELL

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

## k3sのデプロイ flannelをOFF プライベートIPをkubeletのIPとするように指定
## ここで、flannelをOFFにしているのは、現在ではVxLANの送出IFの指定ができず、Vagrant環境の場合、NATインターフェースが選択されてしまうため都合が悪い
## k3sのFlannelはあきらめて、flannelは別途構築する
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--no-flannel --node-ip=${IPADDR}" sh -

## flannelのデプロイ
kubectl apply -f /vagrant/kube-flannel.yaml

## agent登録用のトークンを共有フォルダに配置
cp /var/lib/rancher/k3s/server/node-token /vagrant/token

SHELL

$configureNode = <<-SHELL

export K3S_TOKEN=$(cat /vagrant/token)
export K3S_URL=https://192.168.33.11:6443
# プライベートネットワークのNICのIPアドレスを変数に格納
IPADDR=$(ip a show enp0s8 | grep "inet " | awk '{print $2}' | cut -d / -f1)

## k3sのデプロイ flannelをOFF プライベートIPをkubeletのIPとするように指定
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--no-flannel --node-ip=${IPADDR}" sh -

SHELL

Vagrant.configure(2) do |config|

node_num = 3

(1..node_num).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"
# ネットワークを指定
private_ip = "192.168.33.#{i+10}"
s.vm.network "private_network", ip: private_ip

# 共通
s.vm.provision "shell", inline: $configureCommon

if i == 1 then
# For Master
s.vm.provision "shell", inline: $configureMaster
else
# For Nodes
s.vm.provision "shell", inline: $configureNode
end

end
end
end