Kubernetesにアプリケーションをデプロイするときに見落としがちないくつかのこと

Kubernetesにアプリケーションをデプロイするときに見落としがちないくつかのこと

スコフィールド初心者の運用と保守の話

私の経験では、ほとんどの人(Helmまたは手動yamlを使用)はアプリケーションをKubernetesにデプロイし、いつでも安定して実行できると考えています。
ただし、実際の使用プロセスではまだいくつかの「トラップ」が発生しています。Kubernetesでアプリケーションを起動する前に注意が必要ないくつかの問題を理解するために、これらの「トラップ」をここにリストします。

Kubernetesスケジューリングの概要


スケジューラーは、kubernetesの監視メカニズムを使用して、ノードにまだスケジュールされていない、クラスター内に新しく作成されたポッドを検出します。スケジューラーは、見つかったスケジュールされていない各ポッドを適切なノードにスケジュールして実行します。クラスターのデフォルトのスケジューラーとして、kube-schedulerは、新しく作成されたポッドまたはスケジュールされていないポッドごとにポッドを実行するための最適なノードを選択します。ただし、ポッド内の各コンテナには異なるリソース要件があり、ポッド自体にも異なるリソース要件があります。したがって、ポッドがノードにスケジュールされる前に、これらの特定のリソーススケジューリング要件に従ってクラスター内のノードをフィルター処理する必要があります。

クラスターでは、ポッドのスケジューリング要求を満たすすべてのノードは、スケジュール可能なノードと呼ばれます。ポッドのリソース要求を満たすことができるノードがない場合、スケジューラーが適切なノードを見つけるまで、ポッドはスケジュールされていない状態のままになります。

スケジューリングを決定する際に考慮する必要のある要素には、個々のリソース要求と全体的なリソース要求、ハードウェア/ソフトウェア/ポリシーの制限、アフィニティと非アフィニティの要件、データの局所性、負荷間の干渉などがあります。スケジュールの詳細については、公式ウェブサイトを参照してください

ポッドのリクエストと制限


簡単な例を見てみましょう。ここでは、yaml情報の一部のみをインターセプトします。


apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx-demo
    image: nginx
    resources:
      limits:
        memory: "100Mi"
        cpu: 100m
      requests:
        memory: "1000Mi"
        cpu: 100m

デフォルトでは、サービスデプロイメントファイルが作成されます。リソースフィールドを書き込まない場合、Kubernetesクラスターはデフォルトのポリシーを使用し、ポッドにリソース制限を課しません。つまり、ポッドはメモリとCPUリソースを使用できます。自由にノードノードの。しかし、これは問題を引き起こします:リソースの競合。
例:ノードノードには8Gメモリがあり、2つのポッドが実行されています。
動作開始時には、両方のポッドの実行に必要なメモリは2Gのみです。現時点では問題ありませんが、メモリリークが原因でポッドの1つが突然7Gに増加した場合、またはプロセスが突然増加した場合、ノードの8Gメモリは明らかに現時点では十分ではありません。使用されます。これにより、サービスが非常に遅くなるか、利用できなくなります。
したがって、通常の状況では、サービスをデプロイするときに、同様の問題を回避するためにポッドのリソースを制限する必要があります。

サンプルファイルに示されているように、リソースを追加する必要があります。


requests: 表示运行服务所需要的最少资源,本例为需要内存100Mi,CPU 100m
limits: 表示服务能使用的最大资源,本例最大资源限制在内存1000Mi,CPU 100m

どういう意味ですか?写真は千の言葉の価値があります。
PS:@@@画画私は本当にベストを尽くしました@@@

Kubernetesにアプリケーションをデプロイするときに見落としがちないくつかのこと

活力と準備のプローブ


Kubernetesコミュニティでよく議論されるもう1つのホットトピック。LivenessおよびReadinessプローブを習得することは、フォールトトレラントソフトウェアを実行してダウンタイムを最小限に抑えるメカニズムを提供するため、非常に重要です。ただし、構成が正しくない場合、アプリケーションのパフォーマンスに深刻な影響を与える可能性があります。これら2つのプローブの概要と、それらについて推論する方法は次のとおりです。

活性プローブ:コンテナが実行されているかどうかを検出します。アクティビティプローブが失敗した場合、kubeletはコンテナを強制終了し、コンテナは再起動戦略を受け入れます。「コンテナ」がアクティビティプローブを提供しない場合、デフォルトのステータスは「成功」です。

Livenessプローブはより頻繁に実行されるため、設定は可能な限り簡単です。たとえば、1秒に1回実行するように設定すると、1秒に追加のリクエストが追加されるため、これに必要な追加のリソースを考慮する必要があります。リクエスト。通常、Livenessのヘルスチェックインターフェイスを提供します。これは、プロセスが開始され、リクエストを処理できることを示す応答コード200を返します。

準備プローブ:コンテナーが要求を処理する準備ができているかどうかを検出します。レディプローブが失敗した場合、エンドポイントはポッドに一致するすべてのサービスのエンドポイントからポッドのIPアドレスを削除します。

準備プローブの検査要件は、アプリケーション全体が実行中であり、要求を受信する準備ができていることを示しているため、比較的高くなっています。一部のアプリケーションでは、データベースからレコードが返された後にのみ要求が受け入れられます。よく考えられた準備プローブを使用することで、より高いレベルの可用性とゼロのダウンタイム展開を実現できます。

活性と準備プローブの検出方法は同じで、3つあります

  1. サバイバルコマンドを定義します。
    コマンドが正常に実行され、戻り値がゼロの場合、Kubernetesはこの検出が成功したと見なします。コマンドの戻り値がゼロ以外の場合、この活性検出は失敗します。
  2. ライブHTTPリクエストインターフェイスを定義します。HTTPリクエストを
    送信し、200以上400未満のリターンコードを返して成功を示し、その他のリターンコードは失敗を示します。
  3. TCPサバイバル検出
    定義して、tcpSocket要求を実行ポートに送信します。接続できる場合は成功を意味し、そうでない場合は失敗します。
    例を見てみましょう。例として、一般的なTCPサバイバル検出を示します。

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx-demo
    image: nginx
    livenessProbe:
      tcpSocket:
        port: 80
      initialDelaySeconds: 10
      periodSeconds: 10
    readinessProbe:
      tcpSocket:
        port: 80
      initialDelaySeconds: 10
      periodSeconds: 10
livenessProbe 部分定义如何执行 Liveness 探测:
1. 探测的方法是:通过tcpSocket连接nginx的80端口。如果执行成功,返回值为零,Kubernetes 则认为本次 Liveness 探测成功;如果命令返回值非零,本次 Liveness 探测失败。

2. initialDelaySeconds: 10 指定容器启动 10 之后开始执行 Liveness 探测,一般会根据应用启动的准备时间来设置。比如应用正常启动要花 30 秒,那么 initialDelaySeconds 的值就应该大于 30。

3. periodSeconds: 10 指定每 10 秒执行一次 Liveness 探测。Kubernetes 如果连续执行 3 次 Liveness 探测均失败,则会杀掉并重启容器。

readinessProbe 探测一样,但是 readiness 的 READY 状态会经历了如下变化:
1. 刚被创建时,READY 状态为不可用。
2. 20 秒后(initialDelaySeconds + periodSeconds),第一次进行 Readiness 探测并成功返回,设置 READY 为可用。
3. 如果Kubernetes连续 3 次 Readiness 探测均失败后,READY 被设置为不可用。

ポッドのデフォルトネットワークポリシーを設定する

Kubernetesは「フラット」ネットワークトポロジを使用します。デフォルトでは、すべてのポッドが相互に直接通信できます。しかし、場合によっては、これを望まないか、不要なことさえあります。潜在的なセキュリティリスクがいくつかあります。たとえば、脆弱なアプリケーションが使用されている場合、ハッカーはネットワーク上のすべてのポッドにトラフィックを送信するためのフルアクセスを提供できます。多くのセキュリティ分野と同様に、最小アクセスポリシーもこれに適用されます。理想的には、ネットワークポリシーを作成して、許可されるコンテナ間接続を明確に指定します。

たとえば、以下は特定の名前空間内のすべての入力トラフィックを拒否する単純な戦略です。


---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-ingress-flow
spec:
  podSelector: {}
  policyTypes:
    - Ingress

この構成の概略図

Kubernetesにアプリケーションをデプロイするときに見落としがちないくつかのこと

フックと初期化コンテナによるカスタム動作


Kubernetesシステムを使用する際の主な目標の1つは、既成の開発者に可能な限りゼロのダウンタイムデプロイメントを提供することです。これは、アプリケーションがそれ自体をシャットダウンし、使用済みリソースをクリーンアップするさまざまな方法があるため、困難です。私たちが特に困難に遭遇したアプリケーションの1つは、Nginxでした。これらのポッドのローリング展開を開始すると、アクティブな接続が正常に終了する前にドロップされていることに気付きました。広範囲にわたるオンライン調査の結果、Kubernetesはポッドを終了する前にNginxが接続をドレインするのを待っていないことが判明しました。プレストップフックを使用して、この機能を注入することができ、この変更によりダウンタイムをゼロにすることができました。

通常、たとえば、Nginxへのローリングアップグレードを実行したいのですが、Kubernetesはポッドを停止する前にNginxが接続を終了するのを待ちません。これにより、停止したnginxがすべての接続を適切に閉じることができなくなり、不合理になります。したがって、このような問題を解決するには、停止する前にフックを使用する必要があります。

デプロイメントファイルにライフサイクルを追加できます


lifecycle:
  preStop:
    exec:
      command: ["/usr/local/bin/nginx-killer.sh"]
nginx-killer.sh

#!/bin/bash
sleep 3
PID=$(cat /run/nginx.pid)
nginx -s quit
while [ -d /proc/$PID ]; do
    echo "Waiting while shutting down nginx..."
    sleep 10
done

このように、Kubernetesはポッドを閉じる前にnginx-killer.shスクリプトを実行して、定義した方法でnginxを閉じます。

もう1つの状況は、initコンテナを使用することです
。Initコンテナは、初期化に使用されるコンテナです。複数の場合があります。複数ある場合、これらのコンテナは定義された順序で実行されます。すべてのInitコンテナが実行された後でのみ実行されます。 、メインコンテナが起動します。
例:


 initContainers:
        - name: init
          image: busybox
          command: ["chmod","777","-R","/var/www/html"]
          imagePullPolicy: Always
          volumeMounts:
          - name: volume
            mountPath: /var/www/html
      containers:
      - name: nginx-demo
        image: nginx
        ports:
        - containerPort: 80
          name: port
        volumeMounts:
        - name: volume
          mountPath: /var/www/html

データディスクをnginxの/ var / www / htmlにマウントしました。メインコンテナが実行される前に、/ var / www / htmlの権限を777に変更して、メインコンテナを使用したときに権限の問題が発生しないようにしました。
もちろん、これはほんの少しの栗です。InitContainerには、初期構成など、より強力な機能があります。

カーネルチューニング(カーネルパラメーターの最適化)


最後に、より高度なテクノロジーを最後まで残して、haha
Kubernetesは非常に柔軟なプラットフォームであり、適切と思われる方法でサービスを実行できるように設計されています。通常、高性能サービスがあり、一般的なredisなどの厳しいリソース要件がある場合、起動後に次のプロンプトが表示されます


WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

これには、システムのカーネルパラメータを変更する必要があります。幸い、Kubernetesを使用すると、特定の実行中のポッドにのみ適用可能なカーネルパラメーターを変更できる特権コンテナーを実行できます。以下は、/ proc / sys / net / core / somaxconnパラメーターを変更するために使用した例です。


initContainers:
   - name: sysctl
      image: alpine:3.10
      securityContext:
          privileged: true
       command: ['sh', '-c', "echo 511 > /proc/sys/net/core/somaxconn"]

総括する


Kubernetesはすぐに使用できるソリューションを提供しますが、プログラムの安定した動作を保証するためにいくつかの重要な手順を実行する必要もあります。プログラムを開始する前に、必ず複数のテストを実施し、主要な指標を観察し、リアルタイムで調整してください。
サービスをKubernetesクラスターにデプロイする前に、いくつかの質問をすることができます。

  • メモリ、CPUなど、プログラムにはいくつのリソースが必要ですか?
  • サービスの平均トラフィックとピークトラフィックはどれくらいですか?
  • サービスを拡張するのにどのくらいの時間がかかりますか?また、新しいポッドがトラフィックを受け入れるのにどのくらいの時間がかかりますか?
  • ポッドは正常に停止していますか?オンラインサービスに影響を与えずにそれを行う方法は?
  • サービスの問題が他のサービスに影響を与えず、大規模なサービスのダウンタイムを引き起こさないようにするにはどうすればよいでしょうか。
  • 私たちの権限は大きすぎますか?安全ですか?
    ついに完成、ウーウーウー〜それはとても難しいです

写真
PS:フォローアップ記事はdev.kubeops.netに同期されます

注:記事の写真はインターネットからのものです。侵害がある場合は、時間内に削除するために私に連絡してください。

おすすめ

転載: blog.51cto.com/15060545/2657311