クラスター リソースが不足している場合、Cluster Autoscaler は新しいノードをプロビジョニングし、クラスターに追加します。 Kubernetes を使用する場合、ノードを作成してクラスターに結合するプロセスに数分かかる場合があります。この間、これ以上の拡張は不可能であるため、アプリケーションは接続で圧倒されやすくなります。 仮想マシンのプロビジョニングには数分かかる場合があり、その間はアプリケーションを拡張できない可能性があります。 このような長い待ち時間をなくすにはどうすればよいでしょうか? プロアクティブなスケーリング、または: - クラスター オートスケーラーの仕組みを理解し、その効果を最大化します。
- Kubernetes スケジューラを使用して、ノードに別の Pod を割り当てます。そして
- スケーリングを改善するためにワーカーノードを積極的に構成します。
注: この記事のすべてのコードはLearnK8s GitHubに公開されています。 Linode はこれらのソリューションをサポートできます。最近、Lincode が Akamai ソリューション ファミリーに加わりました。今Linodeに登録すると、100ドル相当の無料利用枠が付与され、Linodeクラウドプラットフォームが提供するさまざまなサービスを自由にご利用いただけます。詳細と登録はこちらをクリックしてください↓↓↓ Akamai Linode のクラウド コンピューティング サービスと機能について詳しくご覧ください。 KubernetesでのCluster Autoscaler の仕組みCluster Autoscaler は、自動スケーリングをトリガーするときに使用可能なメモリやCPUをチェックしませんが、イベントに反応して、スケジュールできないすべてのPodをチェックします。スケジューラがPod を収容できるノードを見つけられない場合、そのPod はスケジュール不可能であると言われます。 これをテストするために、次のようなクラスターを作成できます。 bash $ linode-cli lke cluster-create \ --label learnk8s \ --region eu-west \ --k8s_version 1.23 \ --node_pools.count 1 \ --node_pools.type g6-standard-2 \ --node_pools.autoscaler.enabled enabled \ --node_pools.autoscaler.max 10 \ --node_pools.autoscaler.min 1 \ $ linode-cli lke kubeconfig-view "insert cluster id here" --text | tail +2 | base64 -d > kubeconfig 以下の詳細にご注意ください: - 各ノードには 4GB のメモリと 2 つの vCPU があります (例: 「g6-standard-2」インスタンス)
- クラスターにはノードが1つだけあり、
- クラスターオートスケーラーは1ノードから10ノードまでスケールするように構成されている
次のコマンドでインストールが成功したことを確認できます。 bash $ kubectl get pods -A --kubecnotallow=kubeconfig 多くの場合、環境変数を含むkubeconfigファイルをエクスポートすると便利なので、次のように実行できます。 bash $ export KUBECONFIG=${PWD}/kubeconfig $ kubectl get pods アプリケーションをデプロイする1GBのメモリと250m* の CPU を必要とするアプリケーションをデプロイしてみましょう。 注: m =コアの容量の 1000 分の 1 なので、 250m = CPUの容量の25%になります。 yaml apiVersion: apps/v1 kind: Deployment metadata: name: podinfo spec: replicas: 1 selector: matchLabels: app: podinfo template: metadata: labels: app: podinfo spec: containers: - name: podinfo image: stefanprodan/podinfo ports: - containerPort: 9898 resources: requests: memory: 1G cpu: 250m 次のコマンドを使用して、リソースをクラスターに送信します。 bash $ kubectl apply -f podinfo.yaml するとすぐに何かが発見されるでしょう。まず、3 つのPod がほぼ即座に実行を開始し、1 つのPod が「保留中」状態になります。
その後すぐに: - 数分後、オートスケーラーは追加のポッドを作成し、
- 4 番目のPod は新しいノードにデプロイされます。
最後に、4番目のポッドが新しいノードにデプロイされます 4 番目のポッドが最初のノードにデプロイされないのはなぜですか?割り当てられたリソースを見てみましょう。 Kubernetesノードにおけるリソースの割り当てKubernetesクラスターにデプロイされたポッドは、メモリ、 CPU 、およびストレージ リソースを消費します。さらに、同じノード上で、オペレーティング システムとKubeletもメモリとCPUを消費します。 Kubernetesワーカーノードでは、メモリとCPU は次のように分割されます。 - オペレーティング システムとシステム デーモン (SSH、Systemd など) を実行するために必要なリソース。
- Kubelet、コンテナ ランタイム、ノード障害検出器などの Kubernetes エージェントを実行するために必要なリソース。
- Pod で利用可能なリソース。
- 削除しきい値用に予約されたリソース。
Kubernetes ノードに割り当てられたリソースと予約されたリソース クラスターがDaemonSet ( kube-proxyなど) を実行している場合、使用可能なメモリとCPUの量はさらに減少します。 したがって、すべてのポッドを同じノードに配置できるように要件を下げましょう。 yaml apiVersion: apps/v1 kind: Deployment metadata: name: podinfo spec: replicas: 4 selector: matchLabels: app: podinfo template: metadata: labels: app: podinfo spec: containers: - name: podinfo image: stefanprodan/podinfo ports: - containerPort: 9898 resources: requests: memory: 0.8G # <- lower memory cpu: 200m # <- lower CPU我们可以使用下列命令修改这个部署: bash $ kubectl apply -f podinfo.yaml インスタンスの動作を最適化するために適切な量のCPUとメモリを選択することは、難しい作業です。 Learnk8s の計算ツールを使用すると、これをより迅速に行うことができます。 1 つの問題は解決しましたが、新しいノードを作成するのにかかる時間はどうでしょうか? 遅かれ早かれ 4 つ以上のレプリカが必要になりますが、新しいPodを作成する前に本当に数分間待つ必要がありますか? 一言で言えば:はい! Linode は、新しい仮想マシンを最初から作成して構成し、クラスターに接続する必要があります。このプロセスには 2 分以上かかることがよくあります。 しかし、代替手段があります。必要なときに、構成済みのノードを事前に作成することができます。 たとえば、常に予備ノードを準備しておくようにAutoscalerを構成できます。 Pod がスタンバイ ノードにデプロイされると、 Autoscaler はプロアクティブに別のスタンバイ ノードを作成できます。 Autoscalerにはそのような機能は組み込まれていませんが、簡単に再作成できます。 ノードと同じ数のリソースを要求するポッドを作成できます。 yaml apiVersion: apps/v1 kind: Deployment metadata: name: overprovisioning spec: replicas: 1 selector: matchLabels: run: overprovisioning template: metadata: labels: run: overprovisioning spec: containers: - name: pause image: k8s.gcr.io/pause resources: requests: cpu: 900m memory: 3.8G 次のコマンドを使用して、リソースをクラスターに送信します。 bash kubectl apply -f placeholder.yaml このポッドはまったく何もしません。 プレースホルダーポッドを使用してノード上のすべてのリソースを保護する このノードの役割は、ノードが完全に利用できるようにすることだけです。 次に、ワークロードを拡張する必要があるときに、このプレースホルダーPod をすぐにクリアできるようにする必要があります。このためにPriority Classを使用できます。 yaml apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: overprovisioning value: -1 globalDefault: false description: "Priority class used by overprovisioning." --- apiVersion: apps/v1 kind: Deployment metadata: name: overprovisioning spec: replicas: 1 selector: matchLabels: run: overprovisioning template: metadata: labels: run: overprovisioning spec: priorityClassName: overprovisioning # <-- containers: - name: pause image: k8s.gcr.io/pause resources: requests: cpu: 900m memory: 3.8G用下列命令将其提交至集群: bash kubectl apply -f placeholder.yaml この時点で設定作業は完了です。 Autoscaler がノードを作成するまでしばらく待つ必要がある場合があります。その後、2 つのノードが作成されます。 - 4つのポッドを持つノード
- プレースホルダーポッドを含むノード
デプロイメントを5 つのレプリカに拡張するとどうなりますか?オートスケーラーが別の新しいノードを作成するまで待機しますか? 次のコマンドでテストします。 bash kubectl scale deployment/podinfo --replicas=5 様子を見よう: - 5 番目の Pod はすぐに作成され、10 秒以内に実行状態に変わります。
- プレースホルダー Pod はクリアされ、5 番目の Pod のためのスペースが確保されます。
プレースホルダーポッドは、通常のポッドのためのスペースを確保するためにクリアされます それから: - クラスター オートスケーラーは保留中のプレースホルダーポッドを認識し、新しいノードをプロビジョニングします。
- プレースホルダーPod は新しく作成されたノードにデプロイされます。
保留中のポッドは、クラスタオートスケーラーをトリガーして新しいノードを作成します。 より多くのノードを持つことができるのに、なぜ積極的にノードを作成するのでしょうか? プレースホルダーポッドを複数のレプリカに拡張することができ、各レプリカには標準のワークロードを受け入れる準備が整った事前構成済みのKubernetesノードが含まれます。ただし、これらのノードはアイドル状態ですが、それによって発生する料金はクラウド サービスの料金に含まれます。したがって、ノードを作成しすぎないように注意してください。 水平ポッドオートスケーラーとクラスターオートスケーラーの使用このテクノロジーが何を意味するのかを理解するために、クラスター オートスケーラーと水平ポッド オートスケーラー( HPA )を組み合わせることができます。 HPA を使用すると、デプロイメント内のレプリカの数を増やすことができます。 アプリケーションが受信するトラフィックが増えるにつれて、 Autoscaler でリクエストを処理するレプリカの数を調整できるようになります。ポッドが利用可能なリソースをすべて使い果たすと、クラスター オートスケーラーがトリガーされて新しいノードが作成され、 HPA が引き続きレプリカを作成できるようになります。 上記の効果をテストするために新しいクラスターを作成できます。 bash $ linode-cli lke cluster-create \ --label learnk8s-hpa \ --region eu-west \ --k8s_version 1.23 \ --node_pools.count 1 \ --node_pools.type g6-standard-2 \ --node_pools.autoscaler.enabled enabled \ --node_pools.autoscaler.max 10 \ --node_pools.autoscaler.min 3 \ $ linode-cli lke kubeconfig-view "insert cluster id here" --text | tail +2 | base64 -d > kubeconfig-hpa 次のコマンドを使用して、インストール プロセスが成功したことを確認します。 bash $ kubectl get pods -A --kubecnotallow=kubeconfig-hpa 環境変数を使用してkubeconfigファイルをエクスポートすると便利です。これを行うには、次のコマンドを実行します。 bash $ export KUBECONFIG=${PWD}/kubeconfig-hpa $ kubectl get pods 次に、 Helmを使用してPrometheusをインストールし、このデプロイメントに関連するメトリックを表示します。 Helmの詳しいインストール方法は公式ウェブサイトで確認できます。 bash $ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts $ helm install prometheus prometheus-community/prometheus Kubernetes为HPA提供了一个控制器,借此可以动态增减副本数量。然 HPAにもいくつかの制限があります。 - 箱から出してすぐには使用できません。メトリックを集約して公開するには、Metrics Server をインストールする必要があります。
- PromQL クエリはそのままでは動作しません。
幸いなことに、 KEDAを使用できます。KEDA は、いくつかの便利な機能 ( Prometheusからのメトリックの読み取りを含む) によってHPAコントローラーの使用を拡張します。 KEDA は、次の 3 つのコンポーネントに適用できるオートスケーラーです。 - スケーラー
- メトリックス アダプター
- コントローラ
KEDAアーキテクチャ Helm経由でKEDAをインストールできます。 bash $ helm repo add kedacore https://kedacore.github.io/charts $ helm install keda kedacore/keda PrometheusとKEDAをインストールしたら、デプロイメントを作成しましょう。 この実験では、1 秒あたり一定数のリクエストを処理できるアプリケーションを使用します。各ポッドは1 秒あたり最大 10 件のリクエストを処理できます。 Pod が11 番目のリクエストを受信した場合、リクエストを一時停止し、後で処理します。 yaml apiVersion: apps/v1 kind: Deployment metadata: name: podinfo spec: replicas: 4 selector: matchLabels: app: podinfo template: metadata: labels: app: podinfo annotations: prometheus.io/scrape: "true" spec: containers: - name: podinfo image: learnk8s/rate-limiter:1.0.0 imagePullPolicy: Always args: ["/app/index.js", "10"] ports: - containerPort: 8080 resources: requests: memory: 0.9G --- apiVersion: v1 kind: Service metadata: name: podinfo spec: ports: - port: 80 targetPort: 8080 selector: app: podinfo 次のコマンドを使用して、リソースをクラスターに送信します。 bash $ kubectl apply -f rate-limiter.yaml トラフィックを生成するには、 Locustを使用できます。次のYAML定義は、分散負荷テスト クラスターを作成します。 yaml apiVersion: v1 kind: ConfigMap metadata: name: locust-script data: locustfile.py: |- from locust import HttpUser, task, between class QuickstartUser(HttpUser): @task def hello_world(self): self.client.get("/", headers={"Host": "example.com"}) --- apiVersion: apps/v1 kind: Deployment metadata: name: locust spec: selector: matchLabels: app: locust-primary template: metadata: labels: app: locust-primary spec: containers: - name: locust image: locustio/locust args: ["--master"] ports: - containerPort: 5557 name: comm - containerPort: 5558 name: comm-plus-1 - containerPort: 8089 name: web-ui volumeMounts: - mountPath: /home/locust name: locust-script volumes: - name: locust-script configMap: name: locust-script --- apiVersion: v1 kind: Service metadata: name: locust spec: ports: - port: 5557 name: communication - port: 5558 name: communication-plus-1 - port: 80 targetPort: 8089 name: web-ui selector: app: locust-primary type: LoadBalancer --- apiVersion: apps/v1 kind: DaemonSet metadata: name: locust spec: selector: matchLabels: app: locust-worker template: metadata: labels: app: locust-worker spec: containers: - name: locust image: locustio/locust args: ["--worker", "--master-host=locust"] volumeMounts: - mountPath: /home/locust name: locust-script volumes: - name: locust-script configMap: name: locust-script 次のコマンドを実行してクラスターに送信します。 bash $ kubectl locust.yaml Locust会读取下列locustfile.py文件,该文件存储在一个ConfigMap中: py from locust import HttpUser, task, between class QuickstartUser(HttpUser): @task def hello_world(self): self.client.get("/") このファイルは特別なことは何もせず、単にURLにリクエストを送信します。 Locustダッシュボードに接続するには、ロードバランサーのIPアドレスを指定する必要があります。これを行うには、次のコマンドを使用してアドレスを取得します。 bash $ kubectl get service locust -o jsnotallow='{.status.loadBalancer.ingress[0].ip}' 次にブラウザを開いてIPアドレスにアクセスします。 注意する必要がある問題が 1 つあります。それは、 Horizontal Pod Autoscalerです。 KEDA オートスケーラーは、 ScaledObjectと呼ばれる特別なオブジェクトを使用して、水平オートスケーラーをカプセル化します。 yaml apiVersion: keda.sh/v1alpha1 kind: ScaledObject metadata: name: podinfo spec: scaleTargetRef: kind: Deployment name: podinfo minReplicaCount: 1 maxReplicaCount: 30 cooldownPeriod: 30 pollingInterval: 1 triggers: - type: prometheus metadata: serverAddress: http://prometheus-server metricName: connections_active_keda query: | sum(increase(http_requests_total{app="podinfo"}[60s])) threshold: "480" # 8rps * 60s KEDA はPrometheusによって収集されたメトリックに接続し、それをKubernetesに送信できます。最後に、これらのメトリックを使用してHorizontal Pod Autoscaler (HPA)も作成します。 次のコマンドを使用して、 HPA を手動で確認できます。 bash $ kubectl get hpa $ kubectl describe hpa keda-hpa-podinfo 次のコマンドを使用してオブジェクトを送信します。 bash $ kubectl apply -f scaled-object.yaml 次に、拡張効果をテストできます。 Locustダッシュボードで次の設定で実験を開始します。 - ユーザー数: 300
- 出現率: 0.4
- ホスト: http://podinfo
クラスターと水平ポッドオートスケーラーを組み合わせる ご覧の通り、レプリカの数が増えました! 効果は良いのですが、気づいたかどうか分からない問題があります。 デプロイメントが8 つのポッドに拡張された後、新しいノードに新しいポッドが作成されるまでに数分かかります。この間、現在の8 つのレプリカはそれぞれ10 件のリクエストしか処理できないため、1 秒あたりに処理されるリクエストの数は増加していません。 ボリュームを縮小して実験を繰り返してみましょう。 bash kubectl scale deployment/podinfo --replicas=4 # or wait for the autoscaler to remove pods 今回は、プレースホルダーPodを使用してオーバープロビジョニングを実装します。 yaml apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: overprovisioning value: -1 globalDefault: false description: "Priority class used by overprovisioning." --- apiVersion: apps/v1 kind: Deployment metadata: name: overprovisioning spec: replicas: 1 selector: matchLabels: run: overprovisioning template: metadata: labels: run: overprovisioning spec: priorityClassName: overprovisioning containers: - name: pause image: k8s.gcr.io/pause resources: requests: cpu: 900m memory: 3.9G 次のコマンドを実行してクラスターに送信します。 bash kubectl apply -f placeholder.yaml Locustダッシュボードを開き、次の設定で実験を繰り返します。 - ユーザー数: 300
- 出現率: 0.4
- ホスト: http://podinfo
クラスターと水平ポッドオートスケーラーをオーバープロビジョニングと組み合わせる 今回は、バックグラウンドで新しいノードが作成され、1 秒あたりのリクエスト数は停止せず、増減し続けます。素晴らしい! 要約するこの記事では、次の内容について説明します。 - クラスター オートスケーラーは CPU やメモリの使用状況を追跡しませんが、代わりに保留中のポッドを監視します。
- 使用可能なメモリと CPU の合計量を持つ Pod を作成することで、Kubernetes ノードをプロアクティブに構成できます。
- Kubernetes ノードは、Kubelet、オペレーティング システム、およびドレインしきい値用に特定のリソースを予約します。
- Prometheus と KEDA を一緒に使用して、PromQL クエリを通じてポッドをスケーリングできます。
この記事の内容は大丈夫でしょうか?今すぐ Linode プラットフォームで試してみませんか?今すぐ登録すると、100 ドル相当の無料クレジットを獲得できることをお忘れなく。早速、この記事で紹介した機能やサービスを実際に体験してみましょう↓↓↓ Akamai Linode のクラウド コンピューティング サービスと機能について詳しくご覧ください。 高可用性 MySQL/MariaDB リファレンス アーキテクチャと豊富なアプリケーション例について学ぶには、 Akamai Zhihu アカウントをフォローしてください。
|