k8s のマネージドサービスとして GKE や EKS などで出揃った感はあるけど、マネージドサービスでは k8s クラスタの全ての機能を使うことはできないという認識です。特にネットワークなどインフラよりな低レイヤーな部分はマネージドサービス側でいい感じに隠蔽して、利用者は意識する機会は少ないです。最近は仕事でも k8s など docker コンテナ基盤を扱う機会が増えてきていますが、インフラ屋さんとしてはこのような低レイヤーな部分が気になることがあるので、k8s クラスタを手軽に作れる環境が欲しくなりました。
というわけで、Vagrant を使って手元の仮想環境の管理をしつつ、ansible で k8s クラスタの構築する環境を作りました。ただし、ansible で k8s クラスタを構築する、といっても ansible で完結しておらず、一手間が必要です。というわけで、以下のレポジトリ でどのように 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
を全面的に採用しています。
https://github.com/nabeo/vagrant-k8s-metallb を git clone
してきたディレクトリで make up
を実行します。内部的には各 VM 定義に対して vagrant up
が実行され、Vagrant の ansible_local
によるプロビジョニングが実施されます。ansible_local
のプロビジョニングでは以下を実施していないため、後の手順で手動で実施する必要があります。
- k8s-node の k8s クラスタへの参加と worker ノードとしての登録
- metallb の構築
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.yaml
metallb-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 が立ち上がっているはずです。
試しに 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 で構築していますが、ここでは詳しくは触れません。