PodのAZ間分散方法、VictoriaMetricsのvmstorageをEFSでマルチAZ化した取り組みについてご紹介いたします。
2 0 2 2 年 3 月 2 3 日李 俊 起ステートフルPodのマルチAZ化のために行ったこと
View Slide
自己紹介い じゅんぎ李 俊起・ KDDI株式会社/SRE・ 運用自動化、運用共通機能提供・ 監視基盤をEKS上に構築するために奮闘中
本日のアジェンダ・ VictoriaMetricsについて・ マルチAZ構成のために試したこと(Podのスケジューリング設定について)・ まとめ
VictoriaMetricsとは・ Prometheusメトリクスデータの長期保存/冗長化ツール・ 書き込み、読み込み、データ保存等、機能ごとにコンポーネントが分かれているDistributed System
VictoriaMetricsのアーキテクチャ・vminsertPrometheusのRemoteWrite APIを通じてメトリクスを各vmstorageに分散して格納する・vmstoragePrometheusのデータが保存される領域複数のvmstorageにデータを分割して格納≒RAID0(ストライピング)・vmselectGrafana等よりPromQLを受け付けて各vmstorageからデータを集計しマージするこの部分をマルチAZ化したい≒ PodをAZごとに分散させる
ワーカーノードをAZごとに配置して、Podを各ワーカーノードにデプロイすればいいじゃん
Podのスケジューリング(配置)設定・ nodeSelector・ node (Anti-)Affinity・ Inter-pod (Anti-)Affinity・ TopologySpreadConstraints
nodeSelector・ nodeのラベルでpodを配置するnodeを選ぶ最もシンプルな方法・ 複雑な条件文は指定できない・ podを分散する事はできない※built-in node labelsWell-Known Labels, Annotations and Taints | KubernetesapiVersion: apps/v1kind: Deploymentmetadata:labels:app: nginxname: nginxspec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- image: nginxname: nginxnodeSelector:topology.kubernetes.io/zone: ap-northeast-1c
node (Anti-)Affinity・ nodeのラベルでpodを配置するnodeを指定(除外)する考え方はnodeSeletorと一緒・ 複雑な条件文が書ける・ podを分散する事はできないapiVersion: apps/v1kind: Deployment・・spec:replicas: 3・・spec:affinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: topology.kubernetes.io/zoneoperator: Invalues:- ap-northeast-1a
Inter-pod (Anti-)Affinity・ podの配置状態を見てpodを配置するnodeを決定・ podを分散する事ができる・ 1つのnode上に2つ以上同一podを配置できない(podAntiAffinityの場合)apiVersion: apps/v1kind: Deployment・・spec:replicas: 3・・template:metadata:labels:app: nginxspec:affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- nginxtopologyKey: topology.kubernetes.io/zone「labelSelector」のPodがある(ない)「topologyKey」ドメイン(region,AZ等)のnode上にpodをスケジューリングする
Inter-pod Anti-Affinityの例apiVersion: apps/v1kind: Deployment・・spec:replicas: 3・・template:metadata:labels:app: nginxspec:affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- nginxtopologyKey: topology.kubernetes.io/zoneEKS ClusterVPCWorker NodeAZ-a subnet AZ-c subnetWorker Node
Inter-pod Anti-Affinityの例apiVersion: apps/v1kind: Deployment・・spec:replicas: 3・・template:metadata:labels:app: nginxspec:affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- nginxtopologyKey: topology.kubernetes.io/zoneEKS ClusterVPCWorker NodeAZ-a subnet AZ-c subnetWorker Nodeapp=nginxPod1つ目のpodはapp=nginxラベルを持つPodがまだ存在しないため、AZ-aとAZ-cのどちらかのnodeにPodがスケジューリングされるapp=nginxPod
Inter-pod Anti-Affinityの例apiVersion: apps/v1kind: Deployment・・spec:replicas: 3・・template:metadata:labels:app: nginxspec:affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- nginxtopologyKey: topology.kubernetes.io/zoneEKS ClusterVPCWorker NodeAZ-a subnet AZ-c subnetWorker Nodeapp=nginxPodapp=nginxPod2つ目のpodはAZ-aのnode上にすでにapp=nginxラベルを持つPodが存在するため、AZ-c上のnodeにPodがスケジューリングされるapp=nginxPod
Inter-pod Anti-Affinityの例apiVersion: apps/v1kind: Deployment・・spec:replicas: 3・・template:metadata:labels:app: nginxspec:affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: appoperator: Invalues:- nginxtopologyKey: topology.kubernetes.io/zoneEKS ClusterVPCWorker NodeAZ-a subnet AZ-c subnetWorker Nodeapp=nginxPodapp=nginxPodapp=nginxPodすでに各AZ上にPodが存在していて、3つ目のPodはスケジューリングされない(Pending状態になる)
TopologySpreadConstraints・ ドメイン(region,AZ等)間のPodの偏り(maxSkew)でpodを配置するnodeを決定・ 最も柔軟な設定が可能apiVersion: apps/v1kind: Deployment・・spec:replicas: 3・・template:metadata:labels:app: nginxspec:topologySpreadConstraints:- maxSkew: 1topologyKey: topology.kubernetes.io/zonewhenUnsatisfiable: DoNotSchedulelabelSelector:matchLabels:app: nginx「topologyKey」に指定したドメイン間のpod数の差異を「maxSkew」 で指定した数まで許容し、それを超えないようにPodがスケジューリングされる
TopologySpreadConstraintsの例apiVersion: apps/v1kind: Deployment・・spec:replicas: 3・・template:metadata:labels:app: nginxspec:topologySpreadConstraints:- maxSkew: 1topologyKey: topology.kubernetes.io/zonewhenUnsatisfiable: DoNotSchedulelabelSelector:matchLabels:app: nginxEKS ClusterVPCWorker NodeAZ-a subnet AZ-c subnetWorker Nodeapp=nginxPod1つ目のpodはどこに配置されてもAZ間のPod数の差異(maxSkew)は1なのでAZ-aとAZ-cのどちらかのnodeにPodがスケジューリングされるapp=nginxPod
TopologySpreadConstraintsの例apiVersion: apps/v1kind: Deployment・・spec:replicas: 3・・template:metadata:labels:app: nginxspec:topologySpreadConstraints:- maxSkew: 1topologyKey: topology.kubernetes.io/zonewhenUnsatisfiable: DoNotSchedulelabelSelector:matchLabels:app: nginxEKS ClusterVPCWorker NodeAZ-a subnet AZ-c subnetWorker Nodeapp=nginxPodapp=nginxPodapp=nginxPod2つ目のpodはAZ-a上に配置されたらAZ間のPod数の差異(maxSkew)が2になってしまうため、AZ-c上のnodeにPodがスケジューリングされる
TopologySpreadConstraintsの例apiVersion: apps/v1kind: Deployment・・spec:replicas: 3・・template:metadata:labels:app: nginxspec:topologySpreadConstraints:- maxSkew: 1topologyKey: topology.kubernetes.io/zonewhenUnsatisfiable: DoNotSchedulelabelSelector:matchLabels:app: nginxEKS ClusterVPCWorker NodeAZ-a subnet AZ-c subnetWorker Nodeapp=nginxPodapp=nginxPodapp=nginxPodapp=nginxPod3つ目のpodもどこに配置されてもAZ間のPod数の差異(maxSkew)は1なのでAZ-aとAZ-cのどちらかのnodeにPodがスケジューリングされる
これでマルチAZ化対応完了?・vmstoragePrometheusのデータが保存される領域複数のvmstorageにデータを分割して格納≒RAID0(ストライピング)※再掲StatefulSet + EBSやTopologySpreadConstraints等でAZを固定するとAZ障害で片方のAZがダウンした時、不完全なデータになる。
・データ保存をマルチAZで使用可能なEFSにすることで、 AZを固定せずDeploymentでのデプロイが可能・1つのAZ(ワーカーノード)にPodが集中する可能性はあるが、AZ障害時に生きているAZ(ワーカーノード)で新しいPodがEFSがマウントされた状態で作成され、完全なデータで継続的に監視ができるEKSクラスターAZ-a AZ-cPODService(ELB)Service(ELB)DeploymentPODEFSPODPODDeploymentDeployment / EFSで解決
まとめ・ ステートフルなPodのマルチAZ化には考慮が必要・ ステートレスなPodも負荷分散やダウンタイムが生じないよう、TopologySpreadConstraints等で均等に分散※Podスケジューリングの詳細については以下で検索Assigning Pods to Nodes | Kubernetes
ご清聴ありがとうございました。