k8s のマネージドサービスとして GKE や EKS などで出揃った感はあるけど、マネージドサービスでは k8s クラスタの全ての機能を使うことはできないという認識です。特にネットワークなどインフラよりな低レイヤーな部分はマネージドサービス側でいい感じに隠蔽して、利用者は意識する機会は少ないです。最近は仕事でも k8s など docker コンテナ基盤を扱う機会が増えてきていますが、インフラ屋さんとしてはこのような低レイヤーな部分が気になることがあるので、k8s クラスタを手軽に作れる環境が欲しくなりました。
というわけで、Vagrant を使って手元の仮想環境の管理をしつつ、ansible で k8s クラスタの構築する環境を作りました。ただし、ansible で k8s クラスタを構築する、といっても ansible で完結しておらず、一手間が必要です。というわけで、以下のレポジトリ でどのように k8s クラスタを作っているかを解説してみます。
構築する k8s クラスタ環境
レポジトリの README.md にありますが、構築する環境は以下のようなネットワークになっています。
client (172.17.1.0/24 / ASN 64512)
-------+--------------+------------
| |
eth1|.1 enp0s8|.10
+----+----+ +-----+-----+
| rt-01 | | client-01 |
+----+----+ +-----------+
eth2|.1
| k8s-cluster (172.17.0.0/24 / ASN 64522)
-------+-----+------------------+-----------------+-----------------+--------
| | | |
enp0s8|.10 enp0s8|.21 enp0s8|.22 enp0s8|.23
+-------+-------+ +------+------+ +------+------+ +------+------+
| k8s-master-01 | | k8s-node-01 | | k8s-node-02 | | k8s-node-03 |
+---------------+ +-------------+ +-------------+ +-------------+
レポジトリ名から予想がつきますが、k8s の LoadBalancer として metallb を使うため、BGP ルーター(rt-01) も構築しています。また、metallb で使用する AS 番号として 64522 を定義しています。また、k8s の CNI プラグインとして flannel を採用しています。各ネットワークのアドレスブロックは以下のようにしています。
- docker0 : 172.17.255.0/24
- k8s
- Flannel Pod Network CIDR : 10.244.0.0/16
- Service CIDR : 10.244.0.0/16
- BGP network : 172.17.254.0/24
- ASNs
- client 64512
- k8s-cluster 64522
また、k8s クラスタの管理には kubeadm を全面的に採用しています。
k8s クラスタの構築
k8s 環境の構築
https://github.com/nabeo/vagrant-k8s-metallb を git clone してきたディレクトリで make up を実行します。内部的には各 VM 定義に対して vagrant up が実行され、Vagrant の ansible_local によるプロビジョニングが実施されます。ansible_local のプロビジョニングでは以下を実施していないため、後の手順で手動で実施する必要があります。
k8s-node の k8s クラスタへの参加と worker ノードとしての登録
まず、make k8s-master-01-ssh で k8s-master-01 ノードに ssh ログインします。
k8s-master-01 で kubeadm token create --print-join-command を実行して、worker ノードが k8s クラスタに参加するためのトークン発行と k8s クラスタに参加する worker ノードで実行するべき kubeadm join コマンドを表示させます。
次に、各 worker ノードで k8s-master-01 ノードで取得した kubeadm join コマンドを実行して、k8s クラスタに参加させます。
この時点では worker ノードは k8s クラスタに参加していますが、worker ノードとしては認識されていないので、k8s-master-01 で以下を実行して worker ノードとして登録します。
kubectl label nodes <hostname> node-role.kubernetes.io/node= kubectl label nodes <hostname> type=worker
全ての worker ノードの準備が整ったら、 kubectl get nodes では以下のように表示されていると思います。
NAME STATUS ROLES AGE VERSION k8s-master-01 Ready master 42d v1.15.1 k8s-node-01 Ready node 42d v1.15.1 k8s-node-02 Ready node 5d18h v1.15.1 k8s-node-03 Ready node 5d18h v1.15.1
metallb の構築
Vagrantfile では vm との synced_folder として ansible プレイブックを配置している ansible ディレクトリの他に雑多なファイルを格納するための shared ディレクトリを登録しています。k8s クラスタで使用するマニフェストファイルも shared ディレクトリに配置しています。
ということで k8s-master-01 で shared/k8s-configs にある以下のファイルを kubectl apply で読み込ませます。
metallb.yamlmetallb-bgp.yaml
metallb.yaml は metallb の v0.7.3 をベースにして、Vagrant 環境で使えるように調整しています。metallb-bgp.yaml は metallb を BGP モードで使用し、rt-01 に BGP ピアを貼るようにしています。
metallb は k8s クラスタの metallb-system という名前空間を使用しています。1つの controller pod と worker ノード数分の speaker pod が立ち上がっているはずです。
k8s クラスタで遊ぶ
試しに nginx をデプロイしてみます。以下のマニフェストを kubectl apply で読み込ませます
--- apiVersion: apps/v1beta2 kind: Deployment metadata: name: nginx-deployment spec: replicas: 6 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx-container image: nginx:alpine ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx spec: ports: - name: http port: 80 protocol: TCP targetPort: 80 selector: app: nginx type: LoadBalancer
ここでは nginx サービスの type を LoadBalancer とすることで metallb を使うようにしています。kubectl apply によって環境がデプロイされると、rt-01 では以下のように nginx サービスの EXTERNAL-IP である 172.17.254.1 の next hop が worker ノードに向いているような経路が BGP で広報されたことがわかります。
vagrant@rt-01:~$ gobgp monitor adj-in
2019-07-27T07:32:17Z [ROUTE] 172.17.254.1/32 via 172.17.0.23 aspath [64522] attrs [{Origin: ?}]
2019-07-27T07:32:17Z [ROUTE] 172.17.254.1/32 via 172.17.0.21 aspath [64522] attrs [{Origin: ?}]
2019-07-27T07:32:17Z [ROUTE] 172.17.254.1/32 via 172.17.0.22 aspath [64522] attrs [{Origin: ?}]
また、rt-01 では gobgpd で受け取った経路を quagga の zebra でカーネル経路に落とし込んでいるので以下のように ip route でも確認できます。
172.17.254.1 proto zebra metric 20
nexthop via 172.17.0.22 dev enp0s8 weight 1
nexthop via 172.17.0.21 dev enp0s8 weight 1
nexthop via 172.17.0.23 dev enp0s8 weight 1
gobgpd と quagga を使った BGP ルータの構築も https://github.com/nabeo/vagrant-k8s-metallb で構築していますが、ここでは詳しくは触れません。