分散システムを複数ゾーンに均等にデプロイすることは、高可用性アーキテクチャを実現するためのコア戦略の 1 つです。ワークロードが増加すると、マルチゾーンバランススケジューリングポリシーは、クラスタのスケジューリング要件を満たすために、複数ゾーンのインスタンスを自動的にスケールアウトします。
前提条件
インスタンスをスケールアウトする各ゾーンに、少なくとも 1 つの vSwitch が作成されています。詳細については、「vSwitch の作成と管理」をご参照ください。vSwitch を作成した後、ノードプールの作成と管理を行う際に、対応する vSwitch を選択できます。
機能の説明
ノード自動スケーリングコンポーネントは、事前スケジューリングを通じてサービスをスケーリンググループにデプロイできるかどうかを判断し、スケールアウトリクエストを指定されたスケーリンググループに送信してインスタンスを生成できます。ただし、単一のスケーリンググループに複数ゾーンの vSwitch を構成する現在のメカニズムには問題があります。複数ゾーンのアプリケーション Pod がクラスタリソース不足のためにスケジュールできない場合、Container Service for Kubernetes(ACK)はスケーリンググループのスケールアウトをトリガーしますが、ゾーンとインスタンス間の関連付け情報を送信するメカニズムがないため、スケーリンググループはスケールアウトが必要な特定のゾーンを識別できません。これにより、インスタンスが複数ゾーンに均等に分散されるのではなく、単一ゾーンに集中する可能性があり、ゾーン全体で同時スケーリングを行うというビジネス要件を満たすことができません。
この問題を解決するために、ACK は ack-autoscaling-placeholder コンポーネントを導入しました。このコンポーネントは、リソースの冗長性を利用することでこの問題を修正します。このコンポーネントは、複数ゾーンのelasticscaling を同時ノードプールの指示スケーリングに変換します。詳細については、「ack-autoscaling-placeholder を使用して Pod を数秒でスケーリングする」をご参照ください。原則は次のとおりです。
各ゾーンにノードプールを作成し、ノードプールにラベルを追加します。ラベルは、ノードプールがデプロイされているゾーンを指定します。
ゾーンラベルに基づいて Pod をスケジュールするように nodeSelector を構成します。このように、ack-autoscaling-placehodler は各ゾーンにプレースホルダー Pod をスケジュールできます。デフォルトのプレースホルダー Pod には、アプリケーション Pod よりも重みが小さい PriorityClass があります。
これにより、保留中のアプリケーション Pod がプレースホルダー Pod を置き換えることができます。保留中のアプリケーション Pod が nodeSelector を使用してスケジュールされたプレースホルダー Pod を置き換えると、プレースホルダー Pod は保留中になります。ノード自動スケーリングコンポーネントで使用されるノードスケジューリングポリシーは、antiAffinity から nodeSelector に変更されます。このようにして、スケールアウトセクションからのノードリクエストを処理できます。
次の図は、既存のアーキテクチャに基づいて 2 つのゾーンで同時スケーリングを実現する方法を示しています。
ack-autoscaling-placeholder は、アプリケーション Pod とノード自動スケーリングコンポーネント間のブリッジであり、各ゾーンにプレースホルダー Pod を作成するために使用できます。プレースホルダー Pod のスケジューリング優先度は、実際のビジネスアプリケーションの優先度よりも低くなっています。
アプリケーション Pod が保留中の状態になると、プレースホルダー Pod をすばやくプリエンプションし、各ゾーンの既存のノードにデプロイされます。一方、プリエンプションされたプレースホルダー Pod は保留中の状態になります。
プレースホルダー Pod は nodeSelector を使用してスケジュールされます。ノード自動スケーリングコンポーネントは、対応するゾーンに同時にスケールアウトできます。
手順 1:各ゾーンのノードプールを作成し、カスタムノードラベルを構成する
ACK コンソール にログインします。左側のナビゲーションウィンドウで、[クラスタ] をクリックします。
[クラスタ] ページで、管理するクラスタを見つけ、その名前をクリックします。左側のナビゲーションウィンドウで、 を選択します。
[ノードプールの作成] をクリックし、プロンプトに従ってノードプールの構成を完了します。
この例では、ゾーン I で自動スケーリングが有効になっている auto-zone-I という名前のノードプールを作成する方法について説明します。次のセクションでは、主要なパラメータのみについて説明します。詳細については、「ノードプールの作成と管理」をご参照ください。
パラメータ
説明
ノードプール名
auto-zone-I
スケーリングモード
[自動] を選択して、自動スケーリングを有効にします。
vSwitch
ゾーン I の vSwitch を選択します。
ノードラベル
ノードラベルの キー を
available_zoneに、値 をiに設定します。ノードプールリストで、auto-zone-I ノードプールのステータスが [アクティブ] になると、ノードプールが正常に作成されます。
自動スケーリングが必要な各ゾーンに対して、上記の手順を繰り返して、自動スケーリングが有効になっているノードプールを作成します。

手順 2:プレースホルダーとプレースホルダーデプロイメントをデプロイする
ACK コンソールの左側のナビゲーションウィンドウで、 を選択します。
ack-autoscaling-placeholder を見つけてクリックします。 ack-autoscaling-placeholder ページで、[デプロイ] をクリックします。
[クラスタ] ドロップダウンリストからクラスタを、[名前空間] ドロップダウンリストから名前空間を選択し、[次へ] をクリックします。 [チャートバージョン] ドロップダウンリストからチャートバージョンを選択し、[パラメータ] を構成して、[OK] をクリックします。
作成が成功したら、左側のナビゲーションウィンドウで を選択すると、アプリケーションが [デプロイ済み] 状態になっていることがわかります。
詳細ページの左側のナビゲーションウィンドウで、 を選択します。
[Helm] ページで、ack-autoscaling-placeholder-default の 更新[アクション] 列の をクリックします。
[リリースの更新] パネルで、次の例に基づいて YAML ファイルを更新し、[OK] をクリックします。各ゾーンにプレースホルダーをデプロイし、各ゾーンにプレースホルダーデプロイメントを定義します。
この例では、ゾーン I、K、および H にプレースホルダーデプロイメントを作成する方法を示しています。
deployments: - affinity: {} annotations: {} containers: - image: registry-vpc.cn-beijing.aliyuncs.com/acs/pause:3.1 imagePullPolicy: IfNotPresent name: placeholder resources: requests: cpu: 3500m # プレースホルダーデプロイメントの CPU リクエスト。 memory: 6 # プレースホルダーデプロイメントのメモリリクエスト。 imagePullSecrets: {} labels: {} name: ack-place-holder-I # プレースホルダーデプロイメントの名前。 nodeSelector: {"avaliable_zone":i} # ゾーンラベル。このラベルは、手順 1 でノードプールを作成したときに指定したラベルと同じである必要があります。 replicaCount: 10 # 各スケールアウトアクティビティで作成される Pod の数。 tolerations: [] - affinity: {} annotations: {} containers: - image: registry-vpc.cn-beijing.aliyuncs.com/acs/pause:3.1 imagePullPolicy: IfNotPresent name: placeholder resources: requests: cpu: 3500m # プレースホルダーデプロイメントの CPU リクエスト。 memory: 6 # プレースホルダーデプロイメントのメモリリクエスト。 imagePullSecrets: {} labels: {} name: ack-place-holder-K # プレースホルダーデプロイメントの名前。 nodeSelector: {"avaliable_zone":k} # ゾーンラベル。このラベルは、手順 1 でノードプールを作成したときに指定したラベルと同じである必要があります。 replicaCount: 10 # 各スケールアウトアクティビティで作成される Pod の数。 tolerations: [] - affinity: {} annotations: {} containers: - image: registry-vpc.cn-beijing.aliyuncs.com/acs/pause:3.1 imagePullPolicy: IfNotPresent name: placeholder resources: requests: cpu: 3500m # プレースホルダーデプロイメントの CPU リクエスト。 memory: 6 # プレースホルダーデプロイメントのメモリリクエスト。 imagePullSecrets: {} labels: {} name: ack-place-holder-H # プレースホルダーデプロイメントの名前。 nodeSelector: {"avaliable_zone":h} # ゾーンラベル。このラベルは、手順 1 でノードプールを作成したときに指定したラベルと同じである必要があります。 replicaCount: 10 # 各スケールアウトアクティビティで作成される Pod の数。 tolerations: [] fullnameOverride: "" nameOverride: "" podSecurityContext: {} priorityClassDefault: enabled: true name: default-priority-class value: -1更新が成功すると、各ゾーンにプレースホルダーデプロイメントが作成されます。

手順 3:ワークロードの PriorityClass を作成する
priorityClass.yaml という名前のファイルを作成し、次の内容をファイルにコピーします。
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: high-priority value: 1000000 # 優先度の値を指定します。この値は、手順 2 で作成したワークロードのデフォルトの優先度の値よりも大きい必要があります。 globalDefault: false description: "この優先度クラスは、XYZ サービス Pod のみに使用する必要があります。"Pod に個別の PriorityClass を構成する必要がない場合は、グローバル PriorityClass をデフォルト構成として構成できます。構成が有効になると、PriorityClass が指定されていない Pod は自動的にこの優先度の値を採用し、プリエンプション機能が自動的に有効になります。
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: global-high-priority value: 1 # 優先度の値を指定します。この値は、手順 2 で作成したワークロードのデフォルトの優先度の値よりも大きい必要があります。 globalDefault: true description: "この優先度クラスは、XYZ サービス Pod のみに使用する必要があります。"ワークロードの PriorityClass を作成します。
kubectl apply -f priorityClass.yaml予期される出力:
priorityclass.scheduling.k8s.io/high-priority created
手順 4:ワークロードを作成する
この例では、ゾーン I を使用します。
workload.yaml という名前のファイルを作成し、次の内容をファイルにコピーします。
apiVersion: apps/v1 kind: Deployment metadata: name: placeholder-test labels: app: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: nodeSelector: # ノードの選択に使用するルールを指定します。 avaliable_zone: "i" priorityClassName: high-priority # 手順 3 で構成した PriorityClass の名前。グローバル構成が有効になっている場合は、これはオプションです。 containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80 resources: requests: cpu: 3 # ワークロードのリソースリクエストを指定します。 memory: 5ワークロードをデプロイします。
kubectl apply -f workload.yaml予期される出力:
deployment.apps/placeholder-test createdデプロイ後、 ページで、ワークロードの PriorityClass がプレースホルダー Pod の PriorityClass よりも高く、プレースホルダー Pod がスケールアウトされたノードで実行されていることがわかります。プレースホルダー Pod は、ノード自動スケーリングコンポーネントの同時スケーリングをトリガーして、次のワークロードスケーリングに備えます。

を選択します。 [ノード] ページで、ワークロード Pod がプレースホルダー Pod をホストしているノードで実行されていることがわかります。
