はじめに
研究室にあるサーバーを数台使用し、Kubernetesクラスタを構築しています。
その構成について紹介したいと思います。
アーキテクチャ
基盤について
仮想化基盤
Proxmox VE 9.1.0 を利用しVMを作成しています。
Kubernetesクラスタ構築
kubesprayを用いてクラスタの構築を行っています。
kubesprayを用いることで、一度設定を作成すればクラスタの破棄や再構築、IPアドレスを変更した上での使い回しが容易であり、設定内容をソースコードとして管理することができます。
Control Planeの冗長化
kube-vipのBGPモードを利用し、Control Planeの各ノードがVIPを外部のBGPルーターに対してBGPで経路として広告するようにしています。ルーター側の経路選択(ECMP)により、複数のControl Planeノード間でVIP宛のアクセスを分散し冗長化しています。
Control Planeのノードは3台用意し、それぞれ別の物理マシン上のVMとしているため、仮に物理的に一つのマシンが故障したとしても残りのマシン上のVMでクラスタリングを維持することができます。
詳しくは、以下のブログに記載しています。
Argo CDによるGitOps
Argo CDを用いて GitOpsを実践しており、各コンポーネントはHelm ChartsをベースにGit上で管理しています。
ストレージ
今回は分散ストレージを運用するにあたり、リソース消費や運用の複雑さを最小限にしたかったため、Cephではなく比較的軽量なLonghornを採用しています。
LonghornはKubernetes向けに設計された、ブロックストレージ特化の分散ストレージであり、各ノードのローカルディスクを束ねて永続ストレージを提供します。
Longhornを導入すると、専用のStorageClassが自動で作成されます:
$ k get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
longhorn (default) driver.longhorn.io Delete Immediate true 3d18h
longhorn-static driver.longhorn.io Delete Immediate true 3d18h
ストレージを利用する際には、PVCでStorageClassと容量を指定するだけでよく、対応するPVはLonghornによって動的にプロビジョニングされます。
また、データは複数ノードにレプリケーションされるため、ノード障害が発生してもデータの可用性が保たれる点が大きな特徴です。
この内容については、以前ブログを書いています:
LonghornのUIには、以下のようにクラスタ全体のストレージ状況を可視化したダッシュボードやLonghornがPVCごとに作成したボリュームの一覧などを確認することができます。
また、ボリュームはPodが動作するノードにアタッチされる一方、裏側では複数ノードにデータのレプリカが配置され(ここではk8s-worker-3,4のvar/lib/longhorn)、高可用性を実現している様子も確認できます。
メトリクス・ログ管理
Prometheusによりメトリクスを収集し、Grafanaで可視化しています。
ログについては、Alloyが各ノードやPodからログを収集・転送する役割を担い、Loki がそのログを保存・検索する役割を担っています。
アーキテクチャは以下の通りです:
また、Alertmanager のデフォルトルールを利用し、異常発生時には Slack へ通知される構成としています。
以下はノードのメトリクスですが、このようなダッシュボードをGrafana上で確認することができます。
苦労点・工夫点
NICがLink Downとなる問題
こちらはKubernetesとは関係ないですが、ネットワークスイッチとサーバー間の通信が不安定になっていた問題が発生していました。
具体的には、Proxmox上のサーバーでNICドライバ(e1000e)の不具合によりサーバー側のNICが断続的にLINK DOWNしL2通信が不安定になっていた、という問題でした。
原因の切り分けから対応までを行った流れを以下の記事に書いているので、もしよければ参照してみてください。
Ingress Controllerによるアクセス先の集約
元々、LonghornやArgo CD、GrafanaのUIを見るために、各Serviceに対してポートフォワードして閲覧していました。しかし、必要なポートフォワードの数が徐々に増えていってしまい大変だったという課題がありました。
そこで、Ingress-Controllerを導入し、各ServiceにしていたアクセスをIngressに統一するようにしました。
そして、argocd.labといったホスト名に応じて、Ingressにて各Serviceへのリクエスト割り当てを行うようにしました。
MetalLBも導入し、Ingress ServiceをLoadBalancerとしてExternal IPを割り当て外部から接続できるようにしています。
$ kubectl -n ingress-nginx get svc ingress-nginx-controller
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.233.61.228 192.168.0.20 80:31230/TCP,443:30223/TCP 24m
argocd.labなどのホスト名はローカル環境用のため、/etc/hosts で MetalLBのExternal IPに名前解決するよう設定しています
なお、アーキテクチャ図は以下の通りです:
以下は、Argo CDへの割り当て例です。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd
namespace: argocd
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
ingressClassName: nginx
tls:
- hosts:
- argocd.lab
secretName: argocd-lab-tls
rules:
- host: argocd.lab
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
number: 443
これにより、何個ものポートフォワードの必要なしに、ホスト名を指定した形でローカルから各アプリケーションのUIを閲覧することができるようになりました。
cert-managerによるHTTPS化
Ingress経由で公開している各Web UIに対して、cert-managerを用いてHTTPSを導入しました。
自己署名のルートCAを作成し、ClusterIssuerとCertificateを通じて各ドメイン用の証明書を発行することで、ローカル環境でも警告なしに安全な通信を行えるようにしています。
以下は、Ingress経由でローカルに公開しているargocd.labというドメインに対して自前のルートCAによって発行されたサーバー証明書を示しています。
まとめ
現段階の、研究室で私が運用しているKubernetesクラスタのアーキテクチャについては説明をしてみました。今後アップデートが生じると思うので都度更新していければと思います。
自宅クラスタを試そうと思っている方などに、参考になると幸いです。








