

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# 高可用性アプリケーションの実行
<a name="application"></a>

お客様は、変更を行う場合や特にトラフィックの急増時など、アプリケーションを常に利用できることを期待しています。スケーラブルで回復力のあるアーキテクチャにより、中断することなくアプリケーションやサービスを実行し、ユーザーを満足させます。スケーラブルなインフラストラクチャは、ビジネスのニーズに応じて増減します。単一障害点を排除することは、アプリケーションの可用性を向上させ、回復力を高めるための重要なステップです。

Kubernetes を使用すると、アプリケーションを運用し、可用性と回復力に優れた方法で実行できます。宣言型管理により、アプリケーションを設定すると、Kubernetes は引き続き[現在の状態を目的の状態と照合しようとします](https://kubernetes.io/docs/concepts/architecture/controller/#desired-vs-current)。

## 推奨事項
<a name="_recommendations"></a>

### Pod Disruption Budgets を設定する
<a name="_configure_pod_disruption_budgets"></a>

 [Pod Disruption Budgets](https://kubernetes.io/docs/tasks/run-application/configure-pdb/) は、アプリケーションが同時に発生する中断の量を制限するために使用されます。ワークロードの一部を常に利用できるようにすることが重要な場合は、ワークロード用に設定する必要があります。EKS Auto Mode、Karpenter、Cluster Autoscaler は、スケールダウン時に設定された Pod Disruption Budgets を認識し、準拠します。EKS Auto Mode、Karpenter、マネージド型ノードグループは、ノードの更新時に Pod Disruption Budgets にも準拠します。

### シングルトンポッドの実行を避ける
<a name="_avoid_running_singleton_pods"></a>

アプリケーション全体が 1 つの Pod で実行されている場合、その Pod が終了するとアプリケーションは使用できなくなります。個々のポッドを使用してアプリケーションをデプロイする代わりに、[デプロイ](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)を作成します。デプロイによって作成されたポッドが失敗または終了した場合、デプロイ[コントローラー](https://kubernetes.io/docs/concepts/architecture/controller/)は新しいポッドを起動して、指定された数のレプリカポッドが常に実行されていることを確認します。

### 複数のレプリカを実行する
<a name="_run_multiple_replicas"></a>

デプロイを使用してアプリケーションの複数のレプリカポッドを実行すると、可用性の高い方法で実行できます。1 つのレプリカが失敗しても、残りのレプリカは機能します。ただし、Kubernetes が損失を補うために別の Pod を作成するまで、容量が減ります。さらに、[Horizontal Pod Autoscaler ](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/)を使用して、ワークロードの需要に基づいてレプリカを自動的にスケーリングできます。

### ノード間でレプリカをスケジュールする
<a name="_schedule_replicas_across_nodes"></a>

複数のレプリカを実行することは、すべてのレプリカが同じノードで実行されていて、ノードが使用できなくなった場合にはあまり役に立ちません。ポッドアンチアフィニティまたはポッドトポロジの分散制約を使用して、デプロイのレプリカを複数のワーカーノードに分散することを検討してください。

複数の AZs で実行することで、一般的なアプリケーションの信頼性をさらに向上させることができます。

#### Pod アンチアフィニティルールの使用
<a name="_using_pod_anti_affinity_rules"></a>

以下のマニフェストは、ポッドを別々のノードと AZ に配置することを **Kubernetes スケジューラに指示します。 AZs 個別のノードや AZ は必要ありません。そうすると、各 AZ でポッドが実行されると、Kubernetes はポッドをスケジュールできなくなります。アプリケーションに必要なレプリカが 3 つしかない場合は、 `requiredDuringSchedulingIgnoredDuringExecution`に を使用できます。Kubernetes `topologyKey: topology.kubernetes.io/zone`スケジューラは同じ AZ で 2 つのポッドをスケジュールしません。

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: spread-host-az
  labels:
    app: web-server
spec:
  replicas: 4
  selector:
    matchLabels:
      app: web-server
  template:
    metadata:
      labels:
        app: web-server
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - web-server
              topologyKey: topology.kubernetes.io/zone
            weight: 100
          - podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - web-server
              topologyKey: kubernetes.io/hostname
            weight: 99
      containers:
      - name: web-app
        image: nginx:1.16-alpine
```

#### ポッドトポロジの分散制約の使用
<a name="_using_pod_topology_spread_constraints"></a>

ポッドのアンチアフィニティルールと同様に、ポッドトポロジの分散制約により、ホストや AZs などのさまざまな障害 (またはトポロジ) ドメインでアプリケーションを使用できるようになります。このアプローチは、異なるトポロジドメインのそれぞれに複数のレプリカを配置することで、耐障害性と可用性を確保しようとする場合に非常に効果的です。一方、ポッドのアンチアフィニティルールは、互いにアンチアフィニティを持つポッドが反発効果を持つため、トポロジドメインに 1 つのレプリカがある場合に簡単に結果を生成できます。このような場合、専用ノード上の 1 つのレプリカは耐障害性には適していません。また、 リソースの適切な使用にも適していません。トポロジの分散制約を使用すると、スケジューラがトポロジドメイン全体に適用しようとするスプレッドまたはディストリビューションをより細かく制御できます。このアプローチで使用する重要なプロパティを以下に示します。

1. `maxSkew` は、トポロジドメイン間でモノが不均等になる最大ポイントを制御または決定するために使用します。たとえば、アプリケーションに 10 個のレプリカがあり、3 つの AZs にデプロイされている場合、均等に分散することはできませんが、分散の不均等さに影響を与えることができます。この場合、 は 1～10 の範囲で指定`maxSkew`できます。値 1 は、 のようなスプレッド`4,3,3`、`3,4,3`または 3 つの AZs `3,3,4`にまたがるスプレッドになる可能性があることを意味します。対照的に、値が 10 の場合、 のようなスプレッド`10,0,0`、`0,10,0`または 3 つの AZs `0,0,10`にまたがるスプレッドになる可能性があります。

1. `topologyKey` はノードラベルの 1 つのキーであり、ポッドディストリビューションに使用するトポロジドメインのタイプを定義します。たとえば、ゾーンスプレッドには次のキーと値のペアがあります。

   ```
   topologyKey: "topology.kubernetes.io/zone"
   ```

1. `whenUnsatisfiable` プロパティは、必要な制約が満たされない場合にスケジューラがどのように応答するかを決定するために使用されます。

1. `labelSelector` は、指定した制約に従ってポッドを配置する場所を決定するときにスケジューラがポッドを認識できるように、一致するポッドを見つけるために使用されます。

上記の他に、[Kubernetes ドキュメント](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/)でさらに詳しく読むことができるフィールドがあります。

**ポッドトポロジーが 3 つの AZs**  
 ![\[Pod topology spread constraints across 3 AZs\]](http://docs.aws.amazon.com/ja_jp/eks/latest/best-practices/images/reliability/pod-topology-spread-constraints.jpg) 

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: spread-host-az
  labels:
    app: web-server
spec:
  replicas: 10
  selector:
    matchLabels:
      app: web-server
  template:
    metadata:
      labels:
        app: web-server
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: "topology.kubernetes.io/zone"
        whenUnsatisfiable: ScheduleAnyway
        labelSelector:
          matchLabels:
            app: express-test
      containers:
      - name: web-app
        image: nginx:1.16-alpine
```

### Kubernetes メトリクスサーバーを実行する
<a name="_run_kubernetes_metrics_server"></a>

Kubernetes [メトリクスサーバー](https://github.com/kubernetes-sigs/metrics-server)をインストールして、アプリケーションのスケーリングに役立てます。[HPA](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) や [VPA](https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler) などの Kubernetes Autoscaler アドオンは、アプリケーションのメトリクスを追跡してスケーリングする必要があります。metrics-server は、スケーリングの決定に使用できるリソースメトリクスを収集します。メトリクスは kubelets から収集され、[Metrics API 形式で](https://github.com/kubernetes/metrics)提供されます。

メトリクスサーバーはデータを保持せず、モニタリングソリューションではありません。その目的は、CPU とメモリの使用状況メトリクスを他のシステムに公開することです。アプリケーションの状態を経時的に追跡する場合は、Prometheus や Amazon CloudWatch などのモニタリングツールが必要です。

[EKS ドキュメント](https://docs.aws.amazon.com/eks/latest/userguide/metrics-server.html)に従って、EKS クラスターに metrics-server をインストールします。

## 水平ポッドオートスケーラー (HPA)
<a name="_horizontal_pod_autoscaler_hpa"></a>

HPA は、需要に応じてアプリケーションを自動的にスケーリングし、ピークトラフィック中に顧客に影響を与えないようにできます。これは、リソースメトリクスを提供する APIsする Kubernetes のコントロールループとして実装されます。

HPA は、次の APIs からメトリクスを取得できます。1. Resource Metrics API `metrics.k8s.io` とも呼ばれる — ポッド 2 の CPU とメモリの使用量を提供します。 `custom.metrics.k8s.io`— Prometheus などの他のメトリクスコレクターからのメトリクスを提供します。これらのメトリクスは Kubernetes クラスター**の内部**にあります。3。 `external.metrics.k8s.io`— Kubernetes クラスターの**外部**にあるメトリクス (SQS キューの深さ、ELB レイテンシーなど) を提供します。

これらの 3 つの APIs のいずれかを使用して、アプリケーションをスケールするための メトリクスを指定する必要があります。

### カスタムメトリクスまたは外部メトリクスに基づくアプリケーションのスケーリング
<a name="_scaling_applications_based_on_custom_or_external_metrics"></a>

カスタムメトリクスまたは外部メトリクスを使用して、CPU またはメモリ使用率以外のメトリクスでアプリケーションをスケーリングできます。[カスタムメトリクス](https://github.com/kubernetes-sigs/custom-metrics-apiserver) API サーバーは、HPA がアプリケーションの自動スケーリングに使用できる `custom-metrics.k8s.io` API を提供します。

[Prometheus Adapter for Kubernetes Metrics APIs](https://github.com/directxman12/k8s-prometheus-adapter) を使用して Prometheus からメトリクスを収集し、HPA で を使用できます。この場合、Prometheus アダプターは Prometheus メトリクスを [Metrics API 形式で](https://github.com/kubernetes/metrics/blob/master/pkg/apis/metrics/types.go)公開します。

Prometheus Adapter をデプロイしたら、kubectl を使用してカスタムメトリクスをクエリできます。 `kubectl get —raw /apis/custom.metrics.k8s.io/v1beta1/`

外部メトリクスは、名前が示すように、Horizontal Pod Autoscaler に Kubernetes クラスターの外部にあるメトリクスを使用してデプロイをスケールする機能を提供します。たとえば、バッチ処理ワークロードでは、SQS キューで処理中のジョブの数に基づいてレプリカの数をスケールするのが一般的です。

Kubernetes ワークロードをオートスケーリングするには、KEDA (Kubernetes Event-driven Autoscaling) を使用できます。これは、多数のカスタムイベントに基づいてコンテナスケーリングを駆動できるオープンソースプロジェクトです。この [AWS ブログ](https://aws.amazon.com/blogs/mt/autoscaling-kubernetes-workloads-with-keda-using-amazon-managed-service-for-prometheus-metrics/)では、Amazon Managed Service for Prometheus for Kubernetes ワークロードの自動スケーリングを使用する方法について説明します。

## 垂直ポッドオートスケーラー (VPA)
<a name="_vertical_pod_autoscaler_vpa"></a>

VPA は、アプリケーションの「適切なサイズ」に役立つように、Pod の CPU とメモリの予約を自動的に調整します。リソース割り当てを増やすことで実行される垂直スケーリングが必要なアプリケーションの場合、[VPA](https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler) を使用してポッドレプリカを自動的にスケーリングしたり、スケーリングに関する推奨事項を提供したりできます。

VPA の現在の実装では Pod にインプレース調整が実行されないため、VPA でスケーリングする必要がある場合、アプリケーションは一時的に使用できなくなる可能性があります。代わりに、スケーリングが必要な Pod を再作成します。

 [EKS ドキュメント](https://docs.aws.amazon.com/eks/latest/userguide/vertical-pod-autoscaler.html)には、VPA を設定するためのチュートリアルが含まれています。

 [Fairwinds Goldilocks ](https://github.com/FairwindsOps/goldilocks/)プロジェクトは、CPU およびメモリのリクエストと制限に関する VPA レコメンデーションを視覚化するためのダッシュボードを提供します。VPA 更新モードでは、VPA の推奨事項に基づいて Pod を自動スケーリングできます。

## アプリケーションの更新
<a name="_updating_applications"></a>

最新のアプリケーションには、高い安定性と可用性を備えた迅速なイノベーションが必要です。Kubernetes は、顧客を中断することなくアプリケーションを継続的に更新するためのツールを提供します。

可用性を犠牲にすることなく変更を迅速にデプロイできるようにするベストプラクティスをいくつか見てみましょう。

### ロールバックを実行するメカニズムがある
<a name="_have_a_mechanism_to_perform_rollbacks"></a>

元に戻すボタンがあると、災害を回避できます。本番環境クラスターを更新する前に、別の下位環境 (テスト環境または開発環境) でデプロイをテストするのがベストプラクティスです。CI/CD パイプラインを使用すると、デプロイの自動化とテストに役立ちます。継続的デプロイパイプラインを使用すると、アップグレードに欠陥が発生した場合に、古いバージョンにすばやく戻ることができます。

デプロイを使用して、実行中のアプリケーションを更新できます。これは通常、コンテナイメージを更新することによって行われます。`kubectl` を使用して、次のようなデプロイを更新できます。

```
kubectl --record deployment.apps/nginx-deployment set image nginx-deployment nginx=nginx:1.16.1
```

`--record` 引数はデプロイの変更を記録し、ロールバックを実行する必要がある場合に役立ちます。 は、クラスター内のデプロイに記録された変更`kubectl rollout history deployment`を表示します。を使用して変更をロールバックできます`kubectl rollout undo deployment <DEPLOYMENT_NAME>`。

デフォルトでは、ポッドの再作成を必要とするデプロイを更新すると、デプロイは[ローリング更新](https://kubernetes.io/docs/tutorials/kubernetes-basics/update/update-intro/)を実行します。つまり、Kubernetes はデプロイで実行中のポッドの一部のみを更新し、すべてのポッドを一度に更新するわけではありません。Kubernetes が `RollingUpdateStrategy`プロパティを使用してローリング更新を実行する方法を制御できます。

デプロイの*ローリング更新*を実行するときは、 [https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#max-unavailable](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#max-unavailable)プロパティを使用して、更新中に使用できないポッドの最大数を指定できます。Deployment の `Max Surge`プロパティを使用すると、必要な数のポッドに対して作成できるポッドの最大数を設定できます。

ロールアウトが顧客`max unavailable`を混乱させないように調整することを検討してください。例えば、Kubernetes `max unavailable`はデフォルトで 25% を設定します。つまり、100 個のポッドがある場合、ロールアウト中にアクティブに動作しているポッドは 75 個のみです。アプリケーションで最低 80 個の Pod が必要な場合は、このロールアウトが中断される可能性があります。代わりに、 を 20% `max unavailable`に設定して、ロールアウト全体で少なくとも 80 個の機能ポッドがあることを確認できます。

### ブルー/グリーンデプロイを使用する
<a name="_use_bluegreen_deployments"></a>

変更には本質的にリスクが伴いますが、元に戻すことができない変更は致命的になる可能性があります。*ロールバック*を通じて時間を効果的に戻すことができる手順を変更すると、機能強化と実験の安全性が向上します。ブルー/グリーンデプロイでは、問題が発生した場合に変更をすばやく取り消す方法があります。このデプロイ戦略では、新しいバージョンの環境を作成します。この環境は、更新されるアプリケーションの最新バージョンと同じです。新しい環境がプロビジョニングされると、トラフィックは新しい環境にルーティングされます。新しいバージョンがエラーを発生させずに必要な結果を生成する場合、古い環境は終了します。それ以外の場合、トラフィックは古いバージョンに復元されます。

Kubernetes でブルー/グリーンデプロイを実行するには、既存のバージョンのデプロイと同じ新しいデプロイを作成します。新しいデプロイのポッドがエラーなしで実行されていることを確認したら、アプリケーションのポッドにトラフィックをルーティングする サービスの`selector`仕様を変更することで、新しいデプロイへのトラフィックの送信を開始できます。

[Flux](https://fluxcd.io)、[Jenkins](https://www.jenkins.io)、["](https://spinnaker.io) などの多くの継続的統合ツールを使用すると、ブルー/グリーンデプロイを自動化できます。AWS Containers ブログには、AWS Load Balancer Controller を使用したチュートリアルが含まれています。[AWS Load Balancer Controller を使用したブルー/グリーンデプロイ、Canary デプロイ、A/B テスト](https://aws.amazon.com/blogs/containers/using-aws-load-balancer-controller-for-blue-green-deployment-canary-deployment-and-a-b-testing/) 

### Canary デプロイを使用する
<a name="_use_canary_deployments"></a>

Canary デプロイは、変更からリスクを大幅に排除できる Blue/Green デプロイのバリアントです。このデプロイ戦略では、古いデプロイと並行してポッド数が少ない新しいデプロイを作成し、トラフィックのごく一部を新しいデプロイに振り向けます。メトリクスが、新しいバージョンのパフォーマンスが既存のバージョンと同じかそれ以上であることを示している場合は、新しいデプロイへのトラフィックを徐々に増やし、すべてのトラフィックが新しいデプロイに転送されるまでスケールアップします。問題が発生した場合は、すべてのトラフィックを古いデプロイにルーティングし、新しいデプロイへのトラフィックの送信を停止できます。

Kubernetes には Canary デプロイを実行するネイティブな方法はありませんが、[Istio](https://docs.flagger.app/tutorials/istio-progressive-delivery) で [Flagger](https://github.com/weaveworks/flagger) などのツールを使用できます。

## ヘルスチェックと自己修復
<a name="_health_checks_and_self_healing"></a>

バグのないソフトウェアはありませんが、Kubernetes はソフトウェア障害の影響を最小限に抑えるのに役立ちます。以前は、アプリケーションがクラッシュした場合、アプリケーションを手動で再起動して状況を修復する必要がありました。Kubernetes を使用すると、ポッド内のソフトウェア障害を検出し、新しいレプリカに自動的に置き換えることができます。Kubernetes を使用すると、アプリケーションの状態をモニタリングし、異常なインスタンスを自動的に置き換えることができます。

Kubernetes は 3 [種類のヘルスチェック](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/)をサポートしています。

1. Liveness プローブ

1. スタートアッププローブ (Kubernetes バージョン 1.16 以降でサポート)

1. 準備状況プローブ

 Kubernetes エージェントである [Kubelet](https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/) は、上記のすべてのチェックを実行する責任があります。Kubelet は Pod の状態を 3 つの方法で確認できます。kubelet は、Pod のコンテナ内でシェルコマンドを実行するか、コンテナに HTTP GET リクエストを送信するか、指定されたポートで TCP ソケットを開くことができます。

コンテナ内でシェルスクリプトを実行する `exec`ベースのプローブを選択した場合は、`timeoutSeconds`値の有効期限が切れ*る前に*シェルコマンドが終了していることを確認します。そうしないと、ノードに`<defunct>`プロセスが発生し、ノードに障害が発生します。

## 推奨事項
<a name="_recommendations_2"></a>

### Liveness Probe を使用して異常なポッドを削除する
<a name="_use_liveness_probe_to_remove_unhealthy_pods"></a>

Liveness プローブは、プロセスが実行され続けるがアプリケーションが応答しなくなる*デッドロック*状態を検出できます。たとえば、ポート 80 でリッスンするウェブサービスを実行している場合、Pod のポート 80 で HTTP GET リクエストを送信するように Liveness プローブを設定できます。Kubelet は定期的に GET リクエストを Pod に送信し、レスポンスを期待します。Pod が 200～399 の間に応答した場合、kubelet は Pod が正常であると見なします。そうしないと、Pod は異常としてマークされます。Pod がヘルスチェックに継続的に失敗した場合、kubelet はそれを終了します。

を使用して`initialDelaySeconds`、最初のプローブを遅延させることができます。

Liveness Probe を使用する場合は、Kubernetes がすべての Pod を置き換えようとし、アプリケーションがオフラインになるため、すべての Pod が同時に Liveness Probe に失敗する状況でアプリケーションが実行されないようにしてください。さらに、Kubernetes は引き続き Liveness Probes にも失敗する新しい Pod を作成し、コントロールプレーンに不要な負荷をかけます。外部データベースなど、Pod の外部にある要素に依存するように Liveness Probe を設定しないでください。つまり、応答しない external-to-your-Pod データベースは、Pod が Liveness Probes に失敗しないようにする必要があります。

Sandor Szücs の投稿[「LIVENESS PROBES ARE DANGEROUS](https://srcco.de/posts/kubernetes-liveness-probes-are-dangerous.html)」では、プローブの設定ミスによって発生する可能性のある問題について説明しています。

### 起動に時間がかかるアプリケーションに Startup Probe を使用する
<a name="_use_startup_probe_for_applications_that_take_longer_to_start"></a>

アプリの起動にさらに時間が必要な場合は、Startup Probe を使用して Liveness and Readiness Probe を遅延させることができます。たとえば、データベースからキャッシュをハイドレートする必要がある Java アプリケーションは、完全に機能するまでに最大 2 分かかる場合があります。Liveness または Readiness Probe が完全に機能するまでは失敗する可能性があります。Startup Probe を設定すると、Liveness または Readiness Probe が実行される前に Java アプリが*正常*になります。

Startup Probe が成功するまで、他のすべてのプローブは無効になります。Kubernetes がアプリケーションの起動を待機する最大時間を定義できます。最大設定時間が経過しても Pod が起動プローブに失敗した場合、Pod は終了し、新しい Pod が作成されます。

Startup Probe は Liveness Probe に似ています。失敗すると、Pod が再作成されます。Ricardo A. が記事[「Fantastic Probes and How To Configure Them](https://medium.com/swlh/fantastic-probes-and-how-to-configure-them-fef7e030bd2f)」で説明しているように、アプリケーションの起動時間が予測できない場合には、スタートアッププローブを使用する必要があります。アプリケーションの起動に 10 秒かかることがわかっている場合は、`initialDelaySeconds`代わりに で Liveness/Readiness Probe を使用する必要があります。

### Readiness Probe を使用して部分的な利用不能を検出する
<a name="_use_readiness_probe_to_detect_partial_unavailability"></a>

Liveness プローブは、Pod を終了 (したがってアプリを再起動) して解決されたアプリの障害を検出しますが、Readiness Probe はアプリが*一時的に*使用できない可能性のある状態を検出します。このような状況では、アプリが一時的に応答しなくなることがありますが、このオペレーションが完了すると再び正常であることが予想されます。

たとえば、強力なディスク I/O オペレーション中に、アプリケーションが一時的にリクエストを処理できない場合があります。ここでは、アプリケーションの Pod を終了することは解決策ではありません。同時に、Pod に送信される追加のリクエストが失敗する可能性があります。

Readiness Probe を使用すると、アプリの一時的な使用不能を検出し、再び機能するまで Pod へのリクエストの送信を停止できます。*障害によって Pod が再作成される Liveness Probe とは異なり、Readiness Probe が失敗すると、Pod は Kubernetes Service からトラフィックを受信しません*。準備プローブが成功すると、Pod はサービスからのトラフィックの受信を再開します。

Liveness Probe と同様に、Pod の外部にあるリソース (データベースなど) に依存する Readiness Probe を設定しないでください。設定の不十分な準備状況によってアプリケーションが機能しなくなるシナリオを次に示します。アプリケーションのデータベースに到達できない場合に Pod の準備状況プローブが失敗すると、同じヘルスチェック基準を共有するため、他の Pod レプリカも同時に失敗します。この方法でプローブを設定すると、データベースが使用できないたびに Pod の準備プローブが失敗し、Kubernetes は*すべての* Pod へのトラフィックの送信を停止します。

Readiness Probes を使用する副作用は、デプロイの更新にかかる時間を短縮できることです。準備プローブが成功しない限り、新しいレプリカはトラフィックを受信しません。それまでは、古いレプリカは引き続きトラフィックを受信します。



## 中断への対応
<a name="_dealing_with_disruptions"></a>

Pod の有効期間は限られています。長時間稼働している Pod がある場合でも、Pod が正常に終了することを確認するのが賢明です。アップグレード戦略によっては、Kubernetes クラスターのアップグレードで新しいワーカーノードの作成が必要になる場合があります。そのため、すべての Pod を新しいノードで再作成する必要があります。適切な終了処理と Pod Disruption Budgets を使用すると、Pod が古いノードから削除され、新しいノードで再作成されるため、サービスの中断を回避できます。

ワーカーノードをアップグレードする推奨方法は、新しいワーカーノードを作成し、古いノードを終了することです。ワーカーノードを終了する前に、`drain`終了する必要があります。ワーカーノードがドレインされると、そのすべてのポッドは*安全に*エビクションされます。ここでのキーワードは安全です。ワーカーのポッドが削除されると、単に`SIGKILL`シグナルが送信されるわけではありません。代わりに、削除されるポッド内の各コンテナのメインプロセス (PID 1) に`SIGTERM`シグナルが送信されます。`SIGTERM` シグナルが送信されると、Kubernetes は`SIGKILL`シグナルが送信される前にプロセスに時間 (猶予期間) を与えます。この猶予期間はデフォルトで 30 秒です。デフォルトを上書きするには、kubectl の `grace-period`フラグを使用するか、Podspec `terminationGracePeriodSeconds`で宣言します。

 `kubectl delete pod <pod name> —grace-period=<seconds>` 

通常、メインプロセスに PID 1 がないコンテナがあります。Python ベースのサンプルコンテナを考えてみましょう。

```
$ kubectl exec python-app -it ps
 PID USER TIME COMMAND
 1   root 0:00 {script.sh} /bin/sh ./script.sh
 5   root 0:00 python app.py
```

この例では、シェルスクリプトは `SIGTERM`を受け取ります。この例では Python アプリケーションであるメインプロセスは`SIGTERM`シグナルを取得しません。Pod が終了すると、Python アプリケーションは突然強制終了されます。これは、コンテナ[https://docs.docker.com/engine/reference/builder/#entrypoint](https://docs.docker.com/engine/reference/builder/#entrypoint)の を変更して Python アプリケーションを起動することで修正できます。または、[dumb-init](https://github.com/Yelp/dumb-init) などのツールを使用して、アプリケーションがシグナルを処理できるようにすることもできます。

[コンテナフック](https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks)を使用して、コンテナの開始または停止時にスクリプトまたは HTTP リクエストを実行することもできます。`PreStop` フックアクションは、コンテナが`SIGTERM`シグナルを受信する前に実行され、このシグナルが送信される前に完了する必要があります。`terminationGracePeriodSeconds` 値は、`SIGTERM`シグナルが送信されたときではなく、`PreStop`フックアクションの実行が開始されたときから適用されます。

## 推奨事項
<a name="_recommendations_3"></a>

### Pod Disruption Budgets で重要なワークロードを保護する
<a name="_protect_critical_workload_with_pod_disruption_budgets"></a>

アプリケーションのレプリカ数が宣言されたしきい値を下回った場合、Pod Disruption Budget または PDB は一時的に削除プロセスを停止できます。使用可能なレプリカの数がしきい値を超えると、削除プロセスは続行されます。PDB を使用して、 `minAvailable`とレプリカ`maxUnavailable`の数を宣言できます。たとえば、アプリのコピーを少なくとも 3 つ使用できるようにする場合は、PDB を作成できます。

```
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: my-svc-pdb
spec:
  minAvailable: 3
  selector:
    matchLabels:
      app: my-svc
```

上記の PDB ポリシーは、3 つ以上のレプリカが使用可能になるまでエビクションプロセスを停止するように Kubernetes に指示します。ノードドレイニングは を尊重します`PodDisruptionBudgets`。EKS マネージド型ノードグループのアップグレード中、[ノードは 15 分のタイムアウトでドレインされます](https://docs.aws.amazon.com/eks/latest/userguide/managed-node-update-behavior.html)。15 分後、更新が強制されない場合 (オプションは EKS コンソールでローリング更新と呼ばれます）、更新は失敗します。更新を強制すると、ポッドは削除されます。

セルフマネージド型ノードの場合、[AWS Node Termination Handler](https://github.com/aws/aws-node-termination-handler) などのツールを使用して、EC2 [メンテナンスイベントや EC2 スポットの中断などEC2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/monitoring-instances-status-check_sched.html)2 インスタンスが使用できなくなる可能性のあるイベントに Kubernetes コントロールプレーンが適切に応答するようにすることもできます。 [EC2 ](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-interruptions.html) Kubernetes API を使用してノードをコーディングし、新しい Pod がスケジュールされていないことを確認してからドレインし、実行中の Pod を終了します。

Pod anti-affinity を使用して、異なるノードでデプロイの Pod をスケジュールし、ノードのアップグレード中の PDB 関連の遅延を回避できます。

### カオスエンジニアリングを実践する
<a name="_practice_chaos_engineering"></a>

カオスエンジニアリングは、本番環境の乱れに耐えられるシステムの能力の信頼性を構築するために、分散システムで実験する分野です。

ブログで Dominik Tornow は、[Kubernetes が「ユーザーがシステムの望ましい状態の表現をシステムに提供する](https://medium.com/@dominik.tornow/the-mechanics-of-kubernetes-ac8112eaa302)*」宣言システムであることを説明しています。次に、システムは現在の状態と望ましい状態を考慮して、現在の状態から望ましい状態に移行するコマンドのシーケンスを決定します。* 「�� つまり、Kubernetes は常に*目的の状態*を保存し、システムが逸脱すると、Kubernetes は状態を復元するアクションを実行します。たとえば、ワーカーノードが使用できなくなった場合、Kubernetes はポッドを別のワーカーノードに再スケジュールします。同様に、`replica`クラッシュした場合、[Deployment Contoller](https://kubernetes.io/docs/concepts/architecture/controller/#design) は新しい を作成します`replica`。このようにして、Kubernetes コントローラーは障害を自動的に修正します。

[Gremlin](https://www.gremlin.com) などのカオスエンジニアリングツールは、Kubernetes クラスターの耐障害性をテストし、単一障害点を特定するのに役立ちます。クラスター (およびそれ以降) に人為的カオスを導入するツールは、システムの弱点を発見し、ボトルネックや設定ミスを特定し、制御された環境で問題を修正する機会を与える可能性があります。カオスエンジニアリングの哲学は、予期しないダウンタイムを最小限に抑えるために、意図的にモノを破壊し、インフラストラクチャをストレステストすることを提唱しています。

### Service Mesh を使用する
<a name="_use_a_service_mesh"></a>

サービスメッシュを使用して、アプリケーションの耐障害性を向上させることができます。サービスメッシュにより、service-to-service通信が可能になり、マイクロサービスネットワークのオブザーバビリティが向上します。ほとんどのサービスメッシュ製品は、アプリケーションのネットワークトラフィックを傍受して検査する各サービスと一緒に小さなネットワークプロキシを実行することで機能します。アプリケーションを変更せずに、アプリケーションをメッシュに配置することができます。サービスプロキシの組み込み機能を使用すると、ネットワーク統計の生成、アクセスログの作成、分散トレースのアウトバウンドリクエストへの HTTP ヘッダーの追加を行うことができます。

サービスメッシュは、自動リクエストの再試行、タイムアウト、サーキットブレーク、レート制限などの機能により、マイクロサービスの耐障害性を高めるのに役立ちます。

複数のクラスターを操作する場合は、サービスメッシュを使用して、クラスター間のservice-to-service通信を有効にできます。

### サービスメッシュ
<a name="_service_meshes"></a>
+  [Istio](https://istio.io) 
+  [LinkerD](http://linkerd.io) 
+  [コンサル](https://www.consul.io) 



## オブザーバビリティ
<a name="_observability"></a>

オブザーバビリティは、モニタリング、ログ記録、トレースを含む包括的な用語です。マイクロサービスベースのアプリケーションは、本質的に分散されます。単一のシステムのモニタリングで十分なモノリシックアプリケーションとは異なり、分散アプリケーションアーキテクチャでは、各コンポーネントのパフォーマンスをモニタリングする必要があります。クラスターレベルのモニタリング、ログ記録、分散トレースシステムを使用して、顧客を混乱させる前にクラスター内の問題を特定できます。

トラブルシューティングとモニタリング用の Kubernetes 組み込みツールは限られています。metrics-server はリソースメトリクスを収集してメモリに保存しますが、保持しません。kubectl を使用して Pod のログを表示できますが、Kubernetes は自動的にログを保持しません。また、分散トレースの実装は、アプリケーションコードレベルまたはサービスメッシュを使用して行われます。

Kubernetes の拡張性はここにあります。Kubernetes を使用すると、任意の一元的なモニタリング、ログ記録、トレースソリューションを導入できます。

## 推奨事項
<a name="_recommendations_4"></a>

### アプリケーションをモニタリングする
<a name="_monitor_your_applications"></a>

最新のアプリケーションでモニタリングする必要があるメトリクスの数は継続的に増加しています。これは、お客様の課題の解決に集中できるように、アプリケーションを自動的に追跡する方法がある場合に役立ちます。[Prometheus](https://prometheus.io) や [CloudWatch Container Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/ContainerInsights.html) などのクラスター全体のモニタリングツールは、クラスターとワークロードをモニタリングし、問題が発生した場合、または問題が発生する前にシグナルを提供できます。

モニタリングツールを使用すると、運用チームがサブスクライブできるアラートを作成できます。イベントのアラームをアクティブ化するルールを検討してください。イベントが悪化すると、停止したり、アプリケーションのパフォーマンスに影響を与えたりする可能性があります。

モニタリングすべきメトリクスが不明な場合は、次の方法からヒントを得ることができます。
+  [RED メソッド](https://www.weave.works/blog/a-practical-guide-from-instrumenting-code-to-specifying-alerts-with-the-red-method)。リクエスト、エラー、期間を表します。
+  [USE メソッド](http://www.brendangregg.com/usemethod.html)。使用率、飽和度、エラーを表します。

Sysdig の記事 [Kubernetes でのアラートのベストプラクティス](https://sysdig.com/blog/alerting-kubernetes/)には、アプリケーションの可用性に影響を与える可能性のあるコンポーネントの包括的なリストが含まれています。

### Prometheus クライアントライブラリを使用してアプリケーションメトリクスを公開する
<a name="_use_prometheus_client_library_to_expose_application_metrics"></a>

アプリケーションの状態をモニタリングし、標準メトリクスを集約することに加えて、[Prometheus クライアントライブラリ](https://prometheus.io/docs/instrumenting/clientlibs/)を使用してアプリケーション固有のカスタムメトリクスを公開し、アプリケーションのオブザーバビリティを向上させることもできます。

### 一元的なログ記録ツールを使用してログを収集し、保持する
<a name="_use_centralized_logging_tools_to_collect_and_persist_logs"></a>

EKS でのログ記録は、コントロールプレーンログとアプリケーションログの 2 つのカテゴリに分類されます。EKS コントロールプレーンのログ記録は、コントロールプレーンからアカウントの CloudWatch Logs に直接監査ログと診断ログを提供します。アプリケーションログは、クラスター内で実行されている Pod によって生成されるログです。アプリケーションログには、ビジネスロジックアプリケーションと CoreDNS、Cluster Autoscaler、Prometheus などの Kubernetes システムコンポーネントを実行する Pod によって生成されたログが含まれます。

 [EKS は 5 種類のコントロールプレーンログ](https://docs.aws.amazon.com/eks/latest/userguide/control-plane-logs.html)を提供します。

1. Kubernetes API サーバーコンポーネントログ

1. 監査 

1. オーセンティケーター

1. コントローラーマネージャー

1. スケジューラー

コントローラーマネージャーとスケジューラのログは、ボトルネックやエラーなどのコントロールプレーンの問題の診断に役立ちます。デフォルトでは、EKS コントロールプレーンログは CloudWatch Logs に送信されません。コントロールプレーンのログ記録を有効にし、アカウント内のクラスターごとにキャプチャする EKS コントロールプレーンログのタイプを選択できます。

アプリケーションログを収集するには、[Fluent Bit](http://fluentbit.io)、[Fluentd](https://www.fluentd.org)、[CloudWatch Container Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/deploy-container-insights-EKS.html) などのログアグリゲータツールをクラスターにインストールする必要があります。

Kubernetes ログアグリゲータツールは DaemonSets として実行され、ノードからコンテナログをスクレイプします。その後、アプリケーションログは一元管理された保存先に送信されます。例えば、CloudWatch Container Insights は Fluent Bit または Fluentd のいずれかを使用してログを収集し、CloudWatch Logs に送信して保存できます。Fluent Bit と Fluentd は、Elasticsearch や InfluxDB などの多くの一般的なログ分析システムをサポートしているため、Fluent ビットまたは Fluentd のログ設定を変更することで、ログのストレージバックエンドを変更できます。

### 分散トレースシステムを使用してボトルネックを特定する
<a name="_use_a_distributed_tracing_system_to_identify_bottlenecks"></a>

一般的な最新のアプリケーションには、ネットワーク上に分散されたコンポーネントがあり、その信頼性は、アプリケーションを構成する各コンポーネントが適切に機能するかどうかによって異なります。分散トレースソリューションを使用して、リクエストのフローとシステムの通信方法を理解できます。トレースは、アプリケーションネットワークにボトルネックが存在する場所を示し、カスケード障害を引き起こす可能性のある問題を防ぐことができます。

アプリケーションにトレースを実装するには、2 つのオプションがあります。共有ライブラリを使用してコードレベルで分散トレースを実装するか、サービスメッシュを使用できます。

コードレベルでトレースを実装すると、不利になる可能性があります。この方法では、コードを変更する必要があります。Polyglot アプリケーションがある場合、これはさらに複雑になります。また、サービス全体でさらに別のライブラリを維持する責任もあります。

[LinkerD](http://linkerd.io) や [Istio](http://istio.io) などの Service Mesh を使用して、アプリケーションコードへの最小限の変更でアプリケーションに分散トレースを実装できます。サービスメッシュを使用して、メトリクスの生成、ログ記録、トレースを標準化できます。

[AWS X-Ray](https://aws.amazon.com/xray/) などのトレースツールである [Jaeger](https://www.jaegertracing.io) は、共有ライブラリとサービスメッシュの両方の実装をサポートしています。

(共有ライブラリとサービスメッシュ) の両方の実装をサポートする [AWS X-Ray](https://aws.amazon.com/xray/) や [Jaeger](https://www.jaegertracing.io) などのトレースツールを使用することを検討してください。これにより、後でサービスメッシュを採用する場合にツールを切り替える必要がなくなります。