K8s-----ポッドの詳細説明

目次

1. ポッドの紹介

1. Podの基本概念

2. ポッド定義(リソースリスト)

2. ポッド関連の例

1.コンテナの初期化(initコンテナ)

2. イメージプルポリシー

3. ポッドコンテナ再起動ポリシー (restartPolicy)

3. ポッドの進化

1. リソースの制限

2. ヘルスチェック:プローブ(Probe)とも呼ばれます

2.1 livenessProbe (ライブネスプローブ)

2.2 readinessProbe (レディネスプローブ)

2.3 アクションの開始と終了

3. ポッドのステータス

4. ポッドのスケジューリング

1. 自動スケジュール設定

1.1 リストウォッチ監視メカニズム

1.2 スケジューリングプロセス

2. 方向性のあるスケジューリング

2.1 NodeName(ノード名)

2.2 NodeSeletor(ノードタグ)

3. アフィニティのスケジューリング

3.1 NodeAffinity(ノードアフィニティ)

3.2 PodAffinity(ポッドアフィニティ)

3.3 PodAntiAffinity (ポッドアンチアフィニティ)

4. ポッドの汚染

4.1 NoExecuteインスタンス

4.2 NoSchedule インスタンス

5. ポッドトレランス(Toleration)

例 1: NoSchedule テイントの設定

例 2: NoExecute テイントの設定


1. ポッドの紹介

1. Podの基本概念

ポッドは、kubernetes の最小のリソース管理コンポーネントです。ポッドは、コンテナ化されたアプリケーションの実行を最小限に抑えるリソース オブジェクトでもあります。ポッドは、クラスター内で実行されているプロセスを表します。 kubernetes の他のほとんどのコンポーネントはポッドを中心に展開し、ポッド機能をサポートおよび拡張します。

たとえば、ステートフルセットやデプロイメントなどのコントローラー オブジェクトはポッドの実行を管理するために使用され、サービス オブジェクトとイングレス オブジェクトはアプリケーションを公開するために使用され、persistent Volumes ストレージ リソース オブジェクトはポッドにストレージを提供するために使用されます。

Kubernetes クラスターで Pod を使用するには 2 つの方法があります。

  • ポッド内でコンテナを実行する 「各ポッドに 1 つのコンテナ」モードが最も一般的な使用法です。この使用法では、ポッドをポッドのカプセル化として考えることができます。単一コンテナの場合、kubernetes はコンテナを直接管理するのではなく、ポッドを管理します。
  • ポッド内で複数のコンテナを同時に実行します。ポッドは、同時に緊密に結合して連携する必要がある複数のコンテナをカプセル化することもできます。これらのコンテナは共有します。 Pod 内のコンテナは相互に連携でき、サービス ユニットと呼ばれます。たとえば、1 つのコンテナがファイルを共有し、別のサイドカー コンテナがこれらのファイルを更新します。 Pod はこれらのコンテナのストレージ リソースをエンティティとして管理します。

ポッドの下のコンテナは同じノード上で実行する必要があります。最新のコンテナ テクノロジでは、コンテナが 1 つのプロセスのみを実行することが推奨されています。コンテナの PID 名前空間のプロセス番号は 1 です。コンテナはシグナルを直接受け入れて処理できます。プロセスが終了すると、コンテナ ライフサイクルが終了しました。

コンテナー内で複数のプロセスを実行する場合は、ツリー構造で複数のプロセスのライフサイクル管理を完了するために、Linux オペレーティング システムの init プロセスと同様の管理および制御プロセスが必要です。それぞれのコンテナーで実行されているプロセスは実行できません。ネットワーク通信を直接完了します。これはコンテナ間の分離メカニズムによるものです。k8s の Pod リソース抽象化は、この問題を正式に解決します。Pod オブジェクトはコンテナのコレクションです。これらのコンテナはネットワーク、UTS、および IPC 名前空間を共有するため、ドメイン名、主文名、ネットワークインターフェースが同じであり、IPC経由で直接通信できます。

名前空間 関数
mnt(マウント) ディスクマウントポイントとファイルシステム分離機能を提供します
ipc(プロセス間通信) プロセス間通信のための分離機能を提供します
ネット(ネットワーク) ネットワーク分離機能を提供する
uts(Unix タイムシェアリング) ホスト名分離機能を提供する
ピド プロセス番号分離機能を提供する
ユーザー ユーザー分離機能を提供する

ポッド内のコンテナを一時停止する

ポッド リソースの基礎となる基本的なコンテナの一時停止は、各コンテナにネットワーク ネームスペースとその他の共有メカニズムを提供します。一時停止は、ポッド コンテナ間の共有操作を管理します。このサブコンテナは、コンテナの作成方法を正確に認識できる必要があります。共有オペレーティング環境。コンテナはこれらのコンテナのライフサイクルも管理できます。このセカンダリ コンテナの概念を実現するために、kubernetes はポーズ コンテナをポッド内のすべてのコンテナのセカンダリ コンテナとして使用します。 この一時停止コンテナには 2 つのコア機能があります。1 つは、Pod 全体の Linux 名前空間の基礎を提供することです。もう 1 つは、PID 名前空間を開始することです。PID 1 のプロセス (初期プロセス) として機能します。各ポッド内でゾンビプロセスをリサイクルします。


一時停止コンテナを使用すると、ポッド内のすべてのコンテナが 2 つのリソース (ネットワークとストレージ) を共有できるようになります。

通信網

  • 各ポッドには一意の IP アドレスが割り当てられます。ポッド内のすべてのコンテナは、IP アドレスやポートを含むネットワーク スペースを共有します。ポッド内のコンテナは、localhost を使用して相互に通信できます。ポッド内のコンテナが外部と通信するとき、それらのコンテナは、共有ネットワークを割り当てる必要があります。リソース (ホストのポート マッピングを使用するなど)

ストレージ

  • Pod は複数の共有ボリュームを指定でき、Pod 内のすべてのコンテナが共有ボリュームにアクセスできます。ボリュームは、コンテナー後のファイル損失を防ぐために、ポッド内のストレージ リソースを永続化するために使用することもできます。

概要:
各ポッドには、「ベース コンテナ」と呼ばれる特別な一時停止コンテナがあります。一時停止コンテナに対応するイメージは、kubernetes プラットフォームの一部です。一時停止コンテナに加えて、 , 各ポッド番号には、密接に関連したユーザー アプリケーション コンテナーが 1 つ以上含まれています。

kubernetesの一時停止コンテナは主にコンテナごとに以下の機能を提供します。

  • ポッド内で Linux 名前空間 (ネットワーク名前空間など) を共有するための基盤として機能します。
  • PID 名前空間を有効にし、init プロセスを開始します。

このような Pod の概念と特殊な構成構造を伴う kubernetes の目的は何でしょうか?

  • 理由 1: コンテナのグループを単位として扱う場合、コンテナ全体に対して単純に判断して効果的なアクションを実行することは困難です。たとえば、コンテナーが停止した場合、コンテナー全体が停止したと見なされますか?そこで、Podの基本コンテナとして業務に関係のない一時停止コンテナを導入し、そのステータスをコンテナグループ全体のステータスとして表現することで、この問題を解決できます。
  • 理由 2: ポッド内の複数のアプリケーション コンテナが一時停止コンテナの IP を共有します。一時停止コンテナによってマウントされたボリュームを共有すると、アプリケーション コンテナ間の通信の問題が簡素化され、コンテナ間のファイル共有の問題も解決されます。

一時停止コンテナを生成する理由は 2 つあります。1. 一時停止コンテナはポッド全体のコンテナが正常かどうかを判断するために使用され、2. 一時停止コンテナはネットワークを共有してマウントするために使用されます。

ポッドの分類

自律ポッド

  • この種の Pod 自体は修復できません。Pod が作成されると (ユーザーが直接作成したのか、別のコントローラーによって作成されたのかに関係なく)、Pod プロセスが終了して削除されるまで、kubernetes によってクラスターのノードにスケジュールされます。不足しているポッドの一部は、リソースが削除されるかノードに障害が発生するまで、そのノード上に残ります。
  • ポッド自体は回復しません。 Pod が実行されている Node に障害が発生したり、スケジューラ自体に障害が発生した場合、Pod は削除され、同様に、Pod が配置されている Node にリソースが不足していたり​​、Pod がメンテナンス状態にある場合にも、Pod は削除されます。

コントローラーによって管理されるポッド

  • Kubernetes は、コントローラーと呼ばれる高レベルの抽象化レイヤーを使用して Pod インスタンスを管理します。コントローラーは複数の Pod を作成および管理でき、コピー管理、ローリング アップグレード、クラスター レベルの自己修復機能を提供します。
  • たとえば、ノードに障害が発生した場合、コントローラーはノード上のポッドを他の正常なノードに自動的にスケジュールできます。ポッドを直接使用することもできますが、コントローラーは通常、Kubernetes でポッドを管理するために使用されます。

ポッドコンテナの分類

インフラストラクチャコンテナ

  • Pod ネットワーク全体とストレージ スペースを維持する
  • ノードノードでの操作
  • コンテナを起動すると、k8s は自動的に基本コンテナを起動します。

コンテナの初期化(initコンテナ)

init コンテナはアプリケーション コンテナが開始する前に完了するまで実行する必要があり、アプリケーション コンテナは並行して実行されるため、init コンテナはアプリケーション コンテナの起動をブロックまたは遅延する簡単な方法を提供します。 Init コンテナは、次の 2 つの点を除いて、通常のコンテナと非常に似ています。

  • Init コンテナは正常に完了するまで常に実行されます
  • 各 Init コンテナは、次の Init コンテナが起動する前に、起動を正常に完了して終了する必要があります。

Pod の Init コンテナが失敗した場合、k8s は Init コンテナが成功するまで継続的に Pod を再起動します。ただし、Pod の対応する再起動ポリシー (restartPolicy) が Never の場合、再起動されません。

#init容器的作用
因为 init 容器具有与应用容器分离的单独镜像,其启动相关代码具有如下优势

1、Init 容器可以包含一些安装过程中应用容器中不存在的实用工具或个性化代码。例如,没有必要仅为了在安装过程中使用类似 sed、 awk、python 或 dig 这样的工具而去 FROM 一个镜像来生成一个新的镜像。

2、Init 容器可以安全地运行这些工具,避免这些工具导致应用镜像的安全性降低。

3、应用镜像的创建者和部署者可以各自独立工作,而没有必要联合构建一个单独的应用镜像。

4、Init 容器能以不同于 Pod 内应用容器的文件系统视图运行。因此,Init 容器可具有访问 Secrets的权限,而应用容器不能够访问。

5、由于 Init 容器必须在应用容器启动之前运行完成,因此 Init容器提供了一种机制来阻塞或延迟应用容器的启动,直到满足了一组先决条件。一旦前置条件满足,Pod 内的所有的应用容器会并行启动。

塗布容器(本体容器)

  • initコンテナが完了して終了した後に並行して開始します

2. ポッド定義(リソースリスト)

apiVersion: v1     #必选,版本号,例如v1
kind: Pod         #必选,资源类型,例如 Pod
metadata:         #必选,元数据
  name: string     #必选,Pod名称
  namespace: string  #Pod所属的命名空间,默认为"default"
  labels:           #自定义标签列表
    - name: string                 
spec:  #必选,Pod中容器的详细定义
  containers:  #必选,Pod中容器列表
  - name: string   #必选,容器名称
    image: string  #必选,容器的镜像名称
    imagePullPolicy: [ Always|Never|IfNotPresent ]  #获取镜像的策略 
    command: [string]   #容器的启动命令列表,如不指定,使用打包时使用的启动命令
    args: [string]      #容器的启动命令参数列表
    workingDir: string  #容器的工作目录
    volumeMounts:       #挂载到容器内部的存储卷配置
    - name: string      #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
      mountPath: string #存储卷在容器内mount的绝对路径,应少于512字符
      readOnly: boolean #是否为只读模式
    ports: #需要暴露的端口库号列表
    - name: string        #端口的名称
      containerPort: int  #容器需要监听的端口号
      hostPort: int       #容器所在主机需要监听的端口号,默认与Container相同
      protocol: string    #端口协议,支持TCP和UDP,默认TCP
    env:   #容器运行前需设置的环境变量列表
    - name: string  #环境变量名称
      value: string #环境变量的值
    resources: #资源限制和请求的设置
      limits:  #资源限制的设置
        cpu: string     #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
        memory: string  #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
      requests: #资源请求的设置
        cpu: string    #Cpu请求,容器启动的初始可用数量
        memory: string #内存请求,容器启动的初始可用数量
    lifecycle: #生命周期钩子
        postStart: #容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
        preStop: #容器终止前执行此钩子,无论结果如何,容器都会终止
    livenessProbe:  #对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器
      exec:         #对Pod容器内检查方式设置为exec方式
        command: [string]  #exec方式需要制定的命令或脚本
      httpGet:       #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
        path: string
        port: number
        host: string
        scheme: string
        HttpHeaders:
        - name: string
          value: string
      tcpSocket:     #对Pod内个容器健康检查方式设置为tcpSocket方式
         port: number
       initialDelaySeconds: 0       #容器启动完成后首次探测的时间,单位为秒
       timeoutSeconds: 0          #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
       periodSeconds: 0           #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
       successThreshold: 0
       failureThreshold: 0
       securityContext:
         privileged: false
  restartPolicy: [Always | Never | OnFailure]  #Pod的重启策略
  nodeName: <string> #设置NodeName表示将该Pod调度到指定到名称的node节点上
  nodeSelector: obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上
  imagePullSecrets: #Pull镜像时使用的secret名称,以key:secretkey格式指定
  - name: string
  hostNetwork: false   #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
  volumes:   #在该pod上定义共享存储卷列表
  - name: string    #共享存储卷名称 (volumes类型有很多种)
    emptyDir: {}       #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
    hostPath: string   #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
      path: string                #Pod所在宿主机的目录,将被用于同期中mount的目录
    secret:          #类型为secret的存储卷,挂载集群与定义的secret对象到容器内部
      scretname: string  
      items:     
      - key: string
        path: string
    configMap:         #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
      name: string
      items:
      - key: string
        path: string

Kubernetes のすべてのリソースの第 1 レベルの属性は同じであり、主に 5 つの部分で構成されます。

  • apiVersion バージョン: は kubernetes によって内部的に定義されており、バージョン番号は kubectl api-versions を使用して照会する必要があります
  • kind type: は kubernetes によって内部的に定義されており、バージョン番号は kubectl api-resources を使用してクエリできる必要があります
  • メタデータ メタデータ: 主にリソースの識別と説明。一般的に使用されるものには、名前、名前空間、ラベルなどが含まれます。
  • 仕様の説明: これは構成の最も重要な部分であり、さまざまなリソース構成の詳細な説明が含まれています。
  • ステータス ステータス情報: 内部のコンテンツは定義する必要がなく、kubernetes によって自動的に生成されます。

上記の属性のうち、スペックが次の研究の焦点です。引き続き、その共通のサブ属性を見てみましょう。

  • コンテナ <[]オブジェクト> コンテナのリスト: 特定のコンテナの詳細
  • nodeName: nodeName の値に従って、指定された Node ノードにポッドをスケジュールします
  • nodeSelector <map[]> : NodeSelrctor で定義された情報に基づいて、これらのラベルを含むノードへのポッドを選択し、スケジュールします。
  • hostNetwork ホスト ネットワーク モードを使用するかどうか。デフォルトは false です。true に設定すると、ホスト ネットワークを使用することを意味します
  • ボリューム <[]Object> ストレージ ボリューム: ポッドにハングするストレージ情報を定義するために使用されます
  • restartPolicy 再起動ポリシー: ポッドで障害が発生したときの処理戦略を示します

2. ポッド関連の例

公式 Web サイトの例: https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/init-containers/

1.コンテナの初期化(initコンテナ)

次の例では、2 つの Init コンテナを持つ単純な Pod を定義します。最初のものは myservice が開始するのを待ち、2 つ目は mydb が開始するのを待ちます。両方の Init コンテナが開始されると、Pod は仕様内のアプリケーション コンテナを開始します。

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox:1.28
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox:1.28
    command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
  - name: init-mydb
    image: busybox:1.28
    command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']

#查看pod的详细信息
kubectl describe pod myapp-pod

#查看具体的日志信息
kubectl logs myapp-pod -c init-myservice

#配置myservice的yaml文件
vim myservice.yaml
apiVersion: v1
kind: Service
metadata:
  name: myservice
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 9376
	
kubectl create -f myservice.yaml

kubectl get svc

kubectl get pods -n kube-system

kubectl get pods

特記事項:

  • ポッドの起動プロセス中、ネットワークとデータ ボリュームが初期化された後、Init コンテナが順番に起動されます。次のコンテナを開始するには、各コンテナが正常に終了する必要があります。
  • 実行時または障害によりコンテナが終了し、コンテナの起動に失敗した場合、ポッドの restartPolicy で指定されたポリシーに従って再試行されます。ただし、ポッドの restartPolicy が Always に設定されている場合、Init コンテナが失敗したときに RestartPolicy ポリシーが使用されます。
  • すべての Init コンテナが成功するまで、Pod は Ready になりません。 Init コンテナのポートは Service に集約されません。初期化中のポッドは保留状態ですが、初期化状態を true に設定する必要があります。
  • ポッドが再起動された場合は、すべての Init コンテナを再実行する必要があります。
  • Init コンテナ仕様への変更はコンテナ イメージ フィールドに限定されており、他のフィールドへの変更は有効になりません。 Init コンテナの image フィールドを変更することは、Pod を再起動することと同じです。
  • Init コンテナにはアプリケーション コンテナのすべてのフィールドが含まれます。 ReadinessProbe を除きます。Init コンテナは完了以外の準備完了以外の状態を定義できないためです。これは検証プロセス中に強制されます。
  • ポッド内の各アプリと初期コンテナには一意の名前が必要です。他のコンテナと同じ名前を共有すると、検証中にエラーがスローされます。

2. イメージプルポリシー

Pod の核心はコンテナを実行することです. Docker などのコンテナ エンジンを指定する必要があります. コンテナを起動するときに, イメージをプルする必要があります. k8s のイメージ プル戦略はユーザーが指定できます:

  • IfNotPresent (最新ではない): 既存のローカル ウェアハウスを優先し、ローカル ウェアハウスがない場合はウェアハウス ミラーからプルします。
  • 常に (最新のデフォルト): イメージが既にローカルに存在するかどうかに関係なく、常にウェアハウスからイメージをプルします。
  • しない: ウェアハウスからイメージをプルしないでください。ローカル イメージのみを使用します。

注:「:latest」というラベルが付いた画像ファイルの場合、デフォルトの画像取得ポリシーは「Always」です。他のラベルが付いた画像の場合、デフォルトのポリシーは「IfNotPresent」です。 」。

Pod リソースを作成するとき、イメージのバージョン リソースが lastest に設定されているため、デフォルトのイメージ プル戦略は Always です。

イメージ バージョン リソースを 1.14 に設定します。

ポッド リソースを再作成し、イメージ バージョンを最新に変更してから、イメージ ポリシーを IfNotPresent に設定します。これは、設定された順序で実行されます。

3. ポッドコンテナ再起動ポリシー (restartPolicy)

ポッド内のコンテナが終了したら、ノード上の kubelet 経由でコンテナを再起動します。ポッド内のすべてのコンテナに適用されます。

1、いつも

コンテナが終了して終了すると、常にコンテナを再起動する、デフォルトのポリシー

コンテナー出口は、戻りステータス コード、デフォルトの Pod コンテナーの再始動戦略に関係なく、常にコンテナーを再始動します。

2、失敗時

コンテナが異常終了した場合 (終了ステータス コードが 0 以外の場合)、コンテナを再起動します。正常に終了した場合、コンテナは再起動されません。

コンテナが異常終了し、戻りコードが 0 以外の場合にのみ、コンテナは再起動されます。

3、決してしないでください

コンテナーが終了したら終了し、コンテナーを再起動しないでください。

戻りステータス コードに関係なく、コンテナーの終了時にコンテナーを再起動しないでください。

#注意: K8S は Pod リソースの再起動をサポートせず、削除と再構築のみをサポートします。

作成された Pod リソースのデフォルトの再起動戦略は次のとおりです。 常に

Pod リソースを再作成し、デフォルトの再起動ポリシーを「Never」として追加します。 

3. ポッドの進化

1. リソースの制限

ポッドを定義するときに、各コンテナに必要なリソースの数をオプションで設定できます。最も一般的な構成可能なリソースは、数あるリソースの中でも特に CPU とメモリのサイズです。

このメカニズムは主にリソース オプションを通じて実装されます。リソース オプションには 2 つのサブオプションがあります。

  • requests: は、予約されたリソースを設定するために使用されます。リクエスト リソースが指定されると、スケジューラはこの情報を使用して、Pod をどのノードにスケジュールするかを決定します。
  • limits: は、実行時にコンテナが占有する最大リソースを制限するために使用されます。コンテナが占有するリソースが制限を超えると、コンテナは終了して再起動されます。

ポッドが実行されているノードに十分な利用可能なリソースがある場合、コンテナは要求された量を超えるリソースを使用できます。ただし、コンテナーは設定された制限を超えるリソースを使用できません。

コンテナーにメモリ制限値が設定されているが、メモリ リクエスト値が設定されていない場合、Kubernetes はメモリ制限に一致するリクエスト値を自動的に設定します。​ 

公式 Web サイトの例:
https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/

CPUリソース単位:

  • CPU リソースの要求と制限は cpu にあります。 Kubernetes の 1 つの CPU は 1 vCPU (1 つのハイパースレッド) に相当します。
  • Kubernetes は、フラクショナル CPU を使用したリクエストもサポートします。 spec.containers[].resources.requests.cpu が 0.5 であるコンテナは、CPU の CPU リソースの半分を取得できます (Cgroup の CPU リソースのタイム スライシングと同様)。式 0.1 は式 100m (ミリコア) と同等です。これは、コンテナーが 1000 ミリ秒ごとに使用できる CPU 時間の合計が 0.1*1000 ミリ秒であることを意味します。
  • Kubernetes では、1m 未満の精度で CPU リソースを設定することはできません。​ 

メモリリソースユニット:

  • メモリ要求とメモリ制限はバイト単位です。これは、整数として、または 10 進数の指数単位 (E、P、T、G、M、K)、または 2 進数の指数単位 (Ei、Pi、Ti、Gi、Mi、Ki) で表すことができます。代表する。
  • 例: 1KB=10^3=1000、1MB=10^6=1000000=1000KB、1GB=10^9=1000000000=1000MB、1KiB=2^10=1024、1MiB=2^20=1048576=1024KiB

場合:

vim pod1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: web
    image: nginx
    env:
    - name: WEB_ROOT_PASSWORD
      value: "password"
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"
  - name: db
    image: mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "abc123"
    resources:
      requests:
        memory: "512Mi"  
        cpu: "0.5"
      limits:
        memory: "1Gi"    
        cpu: "1"

kubectl apply -f pod-resources.yaml

kubectl describe pod frontend
#查看详细信息

kubectl get pods -o wide

kubectl describe nodes node02				
#由于当前虚拟机有2个CPU,所以Pod的CPU Limits一共占用了75%

2. ヘルスチェック:プローブ(Probe)とも呼ばれます

プローブは、kubelet によってコンテナー上で実行される定期的な診断です。

プローブに関する 3 つのルール:

  • livenessProbe (ライブネス プローブ):コンテナが実行されているかどうかを確認します。プローブが失敗した場合、kubelet はコンテナーを強制終了し、コンテナーは restartPolicy に従ってポッドの状態を設定します。コンテナーが liveness プローブを提供しない場合、デフォルトの状態は成功です。
  • readinessProbe (readiness Probe): コンテナがリクエストを受け入れる準備ができているかどうかを判断します。検出に失敗した場合、エンドポイント コントローラーは、ポッドに一致するすべてのサービス アドレス エンドポイントからポッドの IP アドレスを削除します。初期遅延前の準備完了状態はデフォルトで失敗になります。コンテナーが Readiness プローブを提供しない場合、デフォルトのステータスは成功です。
  • startupProbe (起動プローブ): コンテナ内のアプリケーションが起動したかどうかを判断します。主に、特定の起動時間を判断できないアプリケーションを対象とします。 startupProbe プローブが設定されている場合、startupProbe ステータスが Success になるまで他のすべてのプローブは非アクティブになり、成功するまで他のプローブは有効になりません。 startProbe が失敗した場合、kubelet はコンテナを強制終了し、コンテナは restartPolicy に従って再起動されます。コンテナーにstartupProbeが構成されていない場合、デフォルトのステータスは成功です。

プローブは 3 つの検査方法をサポートしています。

  • exec:コンテナ内で指定されたコマンドを実行します。コマンド終了時のリターンコードが 0 であれば、診断は成功したとみなされます。
  • tcpSocket: 指定されたポート上のコンテナの IP アドレスに対して TCP チェック (3 ウェイ ハンドシェイク) を実行します。ポートが開いていれば、診断は成功したとみなされます。
  • httpGet:指定されたポートとパス上のコンテナの IP アドレスに対して HTTPGet リクエストを実行します。応答のステータス コードが 200 以上 400 未満の場合、診断は成功したとみなされます

各プローブには、次の 3 つの結果のいずれかが表示されます。

●成功: コンテナは診断に合格しました。
●失敗: コンテナは診断に失敗しました。
●不明: 診断が失敗したため、アクションは実行されません

公式 Web サイトの例:
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/

2.1 livenessProbe (ライブネスプローブ)

例 1: 実行モード

vim exec.yaml
apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec
  namespace: default
spec:
  containers:
  - name: liveness-exec-container
    image: busybox
    imagePullPolicy: IfNotPresent
    command: ["/bin/sh","-c","touch /tmp/live ; sleep 30; rm -rf /tmp/live; sleep 3600"]
    livenessProbe:
      exec:
        command: ["test","-e","/tmp/live"]
      initialDelaySeconds: 1
      periodSeconds: 3

Pod 内にコンテナーが 1 つだけあることがわかります。 kubelet は最初のプローブを実行する前に 2 秒待つ必要があります。kubelet は 3 秒ごとに生存プローブを実行します。 kubelet はコンテナ内でコマンド cat /tmp/healthy を実行して検出します。コマンドが正常に実行され、戻り値が 0 の場合、kubelet はコンテナーが正常で生きているとみなします。 31 秒に達すると、このコマンドはゼロ以外の値を返し、kubelet はコンテナーを強制終了して再起動します。

検出戦略:

  • initialDelaySeconds: は、最初の検出を実行する前に kubelet が 1 秒待機することを指定します。つまり、最初の検出はコンテナーの起動から 2 秒後に実行されます。デフォルトは 0 秒、最小値は 0 です。
  • periodSeconds: は、kubelet が 3 秒ごとに liveness プローブを実行することを指定します。デフォルトは 10 秒です。最小値は 1 です。
  • failureThreshold: プローブが失敗した場合、Kubernetes が中止するまでに再試行する回数。生存検出の場合の中止は、コンテナの再起動を意味します。準備完了の検出中に放棄されたポッドには、準備ができていないというラベルが付けられます。デフォルト値は 3 です。最小値は 1 です。
  • timeoutSeconds: プローブがタイムアウトになった後に待機する秒数。デフォルト値は 1 秒です。最小値は 1 です。 (Kubernetes 1.20 より前では、exec プローブは timeoutSeconds を無視し、結果が返されるまで、プローブは無期限に実行され続け、場合によっては設定された期限を超えても実行され続けました。)
#创建资源
kubectl create -f exec.yaml
#查看资源的详细信息
kubectl describe pods liveness-exec
#查看资源实时状态
kubectl get pods -w

例 2: httpGet メソッド

vim httpget.yaml
apiVersion: v1
kind: Pod
metadata:
  name: liveness-httpget
  namespace: default
spec:
  containers:
  - name: liveness-httpget-container
    image: nginx
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    livenessProbe:
      httpGet:
        port: http
        path: /index.html
      initialDelaySeconds: 1
      periodSeconds: 3
      timeoutSeconds: 10

この設定ファイルでは、Pod にもコンテナーが 1 つだけあることがわかります。 InitialDelaySeconds フィールドは、最初のプローブを実行する前に 1 秒待機する必要があることを kubelet に指示します。 periodSeconds フィールドは、kubelet が 3 秒ごとに liveness プローブを実行することを指定します。 kubelet は、コンテナ内で実行されているサービスに HTTP GET リクエストを送信し (サービスはポート 80 でリッスンします)、検出を実行します。サーバー上の /index.html パスにあるハンドラーが成功コードを返した場合、kubelet はコンテナーが正常で生きているとみなします。ハンドラーが失敗コードを返した場合、kubelet はコンテナーを強制終了して再起動します。

200 以上 400 未満の戻りコードは成功を示し、その他の戻りコードは失敗を示します。

#创建pod资源
kubectl create -f httpget.yaml

#测试:将容器内检测的文件删除
kubectl exec -it liveness-httpget -- rm -rf /usr/share/nginx/html/index.html

例 3: tcpSocket メソッド

apiVersion: v1
kind: Pod
metadata:
  name: goproxy
  labels:
    app: goproxy
spec:
  containers:
  - name: goproxy
    image: k8s.gcr.io/goproxy:0.1
    ports:
    - containerPort: 8080
    readinessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20

上記の例では、readinessProbe プローブと livenessProbe プローブの両方を使用しています。 kubelet は、コンテナーの開始から 5 秒後に最初の readinessProbe プローブを送信します。これにより、goproxy コンテナーのポート 8080 への接続が試行されます。プローブが成功すると、kubelet は 10 秒ごとにプローブを実行し続けます。この構成には、readinessProbe プローブに加えて、livenessProbe プローブが含まれています。 kubelet は、コンテナーの開始から 15 秒後に最初の livenessProbe プローブを実行します。 readinessProbe プローブと同様に、goproxy コンテナーのポート 8080 への接続を試行します。 livenessProbe プローブが失敗すると、コンテナーが再起動されます。

vim tcpsocket.yaml
apiVersion: v1
kind: Pod
metadata:
  name: probe-tcp
spec:
  containers:
  - name: nginx
    image: nginx:1.13
    livenessProbe:
      initialDelaySeconds: 5
      timeoutSeconds: 1
      tcpSocket:
        port: 8080
      periodSeconds: 10
      failureThreshold: 2

2.2 readinessProbe (レディネスプローブ)

例 1:

vim readiness-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
  name: readiness-httpget
  namespace: default
spec:
  containers:
  - name: readiness-httpget-container
    image: soscscs/myapp:v1
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    readinessProbe:
      httpGet:
        port: 80
        path: /index1.html
      initialDelaySeconds: 1
      periodSeconds: 3
    livenessProbe:
      httpGet:
        port: http
        path: /index.html
      initialDelaySeconds: 1
      periodSeconds: 3
      timeoutSeconds: 10

#创建pod资源
kubectl create -f readiness-httpget.yaml

kubectl get pods 

例 2: Readiness 検出の検証が失敗し、Pod が READY 状態に移行できず、エンドポイント コントローラーが Pod の IP アドレスをエンドポイントから削除します。

vim readiness-myapp.yaml
apiVersion: v1
kind: Pod
metadata:
  name: myapp1
  labels:
     app: myapp
spec:
  containers:
  - name: myapp
    image: soscscs/myapp:v1
    ports:
    - name: http
      containerPort: 80
    readinessProbe:
      httpGet:
        port: 80
        path: /index.html
      initialDelaySeconds: 5
      periodSeconds: 5
      timeoutSeconds: 10 
---
apiVersion: v1
kind: Pod
metadata:
  name: myapp2
  labels:
     app: myapp
spec:
  containers:
  - name: myapp
    image: soscscs/myapp:v1
    ports:
    - name: http
      containerPort: 80
    readinessProbe:
      httpGet:
        port: 80
        path: /index.html
      initialDelaySeconds: 5
      periodSeconds: 5
      timeoutSeconds: 10 
---
apiVersion: v1
kind: Pod
metadata:
  name: myapp3
  labels:
     app: myapp
spec:
  containers:
  - name: myapp
    image: soscscs/myapp:v1
    ports:
    - name: http
      containerPort: 80
    readinessProbe:
      httpGet:
        port: 80
        path: /index.html
      initialDelaySeconds: 5
      periodSeconds: 5
      timeoutSeconds: 10 
---
apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
  type: ClusterIP
  ports:
  - name: http
    port: 80
    targetPort: 80

2.3 アクションの開始と終了

vim post.yaml
apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-demo
spec:
  containers:
  - name: lifecycle-demo-container
    image: soscscs/myapp:v1
    lifecycle:   #此为关键字段
      postStart:
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the postStart handler >> /var/log/nginx/message"]      
      preStop:
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the poststop handler >> /var/log/nginx/message"]
    volumeMounts:
    - name: message-log
      mountPath: /var/log/nginx/
      readOnly: false
  initContainers:
  - name: init-myservice
    image: soscscs/myapp:v1
    command: ["/bin/sh", "-c", "echo 'Hello initContainers'   >> /var/log/nginx/message"]
    volumeMounts:
    - name: message-log
      mountPath: /var/log/nginx/
      readOnly: false
  volumes:
  - name: message-log
    hostPath:
      path: /data/volumes/nginx/log/
      type: DirectoryOrCreate

上記のことから、最初に init Container が実行され、次にメイン コンテナが開始されると、Kubernetes が即座に postStart イベントを送信することがわかります。

上記からわかるように、Kubernetes はコンテナーが終了する前に preStop イベントを送信します。

3. ポッドのステータス

  • 保留中:ポッドはシステムによって認識されましたが、内部コンテナはまだ作成されていません。これには、ノードにスケジュールされた時間と、短期間続くイメージをダウンロードする時間が含まれます。
  • 実行中:ポッドはノードにバインドされており (スケジュールは成功しています)、ポッド内のすべてのコンテナが作成されており、少なくとも 1 つのコンテナが実行されています。コンテナのプロセスが開始または再起動中です。 -- ここで、ポッドはすでに実行されていますが、内部コンテナーが完全には利用できない可能性があることに注意してください。したがって、コンテナの状態をさらに検出する必要がある。
  • 成功:このステータスはめったに発生せず、ポッド内のすべてのコンテナが正常に終了し、再度プルアップされないことを示します。
  • 失敗:ポッド内のすべてのコンテナが終了し、少なくとも 1 つのコンテナが異常終了しました。 (終了時にゼロ以外の値が返されたか、システムによって直接終了されました)
  • unknown:何らかの理由でポッドのステータスを取得できません。通信の問題が原因である可能性があります。一般に、最も一般的なポッドの状態は最初の 2 つの状態です。実行中は、 コンテナのステータスにさらに注意を払う必要があります
     

4. ポッドのスケジューリング

デフォルトでは、Pod が実行される Node ノードは、対応するアルゴリズムを使用して Scheduler コンポーネントによって計算されます。このプロセスは手動制御の対象ではありません。しかし、実際に使用する場合、これはニーズを満たしません。多くの場合、特定のノードに到達するように特定の Pod を制御したい場合、どうすればよいでしょうか?これには、ポッドに対する kubernetes のスケジューリング ルールを理解する必要があります。Kubernetes では、次の 4 つの主要なタイプのスケジューリング方法が提供されます。

  • 自動スケジュール: 実行されるノードは、一連のアルゴリズムを通じてスケジューラによって完全に計算されます
  • 指示されたスケジューリング: NodeName (ノード名)、NodeSelector (ラベル セレクター)
  • アフィニティ スケジュール: NodeAffinity (ノード アフィニティ)、PodAffinity (ポッド アフィニティ)、PodAntiAffinity (ポッド非アフィニティ)
  • 汚染 (許容) スケジュール: 汚染、許容

1. 自動スケジュール設定

1.1 リストウォッチ監視メカニズム

各コンポーネントの連携についての紹介

Kubernets は List-Watch メカニズムを使用して各コンポーネントと連携してデータの同期を維持し、各コンポーネント間の設計により分離が実現されます。

  • ユーザーは設定ファイルに従ってkubelet経由でAPIServerに名前を送り、Nodeノード上にポッドやコンテナを作成します。

  • APIServer は、API 呼び出し、権限制御、リソースの呼び出し、リソースの保存のプロセスを経ています。実際には、アプリケーションのデプロイはまだ開始されていません。デプロイ プロセス全体を完了するには、コントローラー マネージャー、スケジューラ、および kubelet の支援が必要です。 。

  • kubernetes では、すべてのデプロイ情報は etcd に書き込まれて保存されます。実際、etcd がデプロイ情報を保存すると、Create イベントが APIServer に送信され、APIServer は etcd をリッスン (監視) します。

ポッドは通常の作成プロセスを開始します

(1) ここには 3 つの List-Watch があります。つまり、Controller Manager (マスター上で実行)、Scheduler (マスター上で実行)、および kubelet (ノード上で実行) です。 プロセスの開始時に APIServer によって送信されるイベントをリッスン (監視) します。

(2) ユーザーは、kubectl または他の API クライアントを通じて APIServer にリクエストを送信し、Pod オブジェクトのコピーを作成します。

(3) APIServer は Pod オブジェクトの関連メタ情報を etcd に保存しようとします。書き込み操作が完了すると、APIServer は確認情報をクライアントに返します。

(4) etcd は Pod 作成情報を受け取ると、Create イベントを APIServer に送信します。

(5) コントローラー マネージャーが APIServer 内のイベントをリッスン (https の 6443 ポート経由で監視) しているため。この時点で、APIServer は Create イベントを受信し、それをコントローラー マネージャーに送信します。

(6) Create イベントを受信した後、コントローラー マネージャーはレプリケーション コントローラーを呼び出し、ノード上に作成する必要があるコピーの数を確認します。レプリカの数が RC で定義された数よりも少なくなると、RC は自動的にレプリカを作成します。要するにコピー数を保証するController(PS:伸縮を担当)です。

(7) Controller Manager が Pod のコピーを作成した後、APIServer は Pod の詳細情報を etcd に記録します。たとえば、ポッドのコピーの数やコンテナの内容などです。

(8) 同じ etcd がイベントを通じて APIServer に Pod 作成情報を送信します。

(9) Scheduler は APIServer を監視 (Watching) しており、システム内で「前と下を繋ぐ」役割を果たしているため、「繋ぐ」とは作成された Pod を受け取る役割を担っていることを意味します。イベントとそのノードの配置; " 「開始」は、配置作業が完了した後、ノード上の kubelet プロセスが後続の作業を引き継ぎ、ポッドのライフサイクルの「後半」を担当することを意味します。つまり、スケジューラの役割は、スケジューリング アルゴリズムとポリシーに従って、スケジュールされるポッドをクラスタ内のノードにバインドすることです。

(10) スケジューラはスケジューリング完了後に Pod 情報を更新しますが、このときの情報はより豊富になります。ポッドのレプリカの数に加えて、レプリカの内容もわかります。また、どのノードにデプロイするかもわかります。そして上記のPod情報をAPI Serverに更新し、APIServerからetcdに更新して保存します。

(11) etcd は更新成功イベントを APIServer に送信し、APIServer もこの Pod オブジェクトのスケジューリング結果の反映を開始します。

(12) Kubelet は Node 上で実行されるプロセスであり、APIServer によって送信された Pod 更新イベントを List-Watch (Watch、https のポート 6443 経由) を通じてリッスンします。 kubelet は、現在のノードで Docker を呼び出してコンテナを起動しようとし、結果として得られるポッドとコンテナのステータスを APIServer に送り返します。

(13) APIServerはPodのステータス情報をetcdに保存します。 etcd が書き込み操作が正常に完了したことを確認した後、APIServer はイベントが受け入れられる関連する kubelet に確認情報を送信します。
 

#注意:在创建 Pod 的工作就已经完成了后,

#为什么 kubelet 还要一直监听呢?

原因很简单,假设这个时候 kubectl 发命令,要扩充 Pod 副本数量,那么上面的流程又会触发一遍,kubelet 会根据最新的 Pod 的部署情况调整 Node 的资源。又或者 Pod 副本数量没有发生变化,但是其中的镜像文件升级了,kubelet 也会自动获取最新的镜像文件并且加载。

1.2 スケジューリングプロセス

スケジューラーは kubernetes のスケジューラーであり、その主なタスクは、定義されたポッドをクラスターのノードに割り当てることです。その主な考慮事項は次のとおりです。

  • 公平性: 各ノードにリソースが確実に割り当てられるようにする方法
  • リソースの効率的な利用: クラスター内のすべてのリソースが最大限に使用されます。
  • 効率: スケジューリングのパフォーマンスは良好である必要があり、ポッドの大規模なバッチのスケジューリング作業はできるだけ早く完了する必要があります。
  • 柔軟性: ユーザーがニーズに応じてスケジュール ロジックを制御できるようにします。

スケジュールはいくつかの部分に分かれています: まず、条件を満たさないノードを除外します。このプロセスは予算戦略 (述語) と呼ばれます。その後、通過したノードは優先順位に従って並べ替えられます。これは優先戦略 (優先順位) であり、最終的に最も高い優先順位を持つノードが選択されます。中間ステップのいずれかでエラーがあった場合、エラーが直接返されます。

述語には、使用できる一連の共通アルゴリズムがあります。

  • PodFitsResources: ノード上の残りのリソースがポッドによって要求されたリソースより大きいかどうか。
  • PodFitsHost: ポッドで NodeName が指定されている場合は、ノード名が NodeName と一致するかどうかを確認します。
  • PodFitsHostPorts: ノードですでに使用されているポートが、ポッドによって適用されたポートと競合するかどうか。
  • PodSelectorMatches: ポッドで指定されたラベルに一致しないノードをフィルターで除外します。
  • NoDiskConflict: マウントされたボリュームは、両方が読み取り専用でない限り、ポッドによって指定されたボリュームと競合しません。
如果在 predicate 过程中没有合适的节点,pod 会一直在 pending 状态,不断重试调度,直到有节点满足条件。

经过这个步骤,如果有多个节点满足条件,就继续 priorities 过程:按照优先级大小对节点排序。

priority は一連のキーと値のペアで構成されます。キーは優先項目の名前、値はその重み (項目の重要度) です。一般的な優先オプションには次のようなものがあります。

  • LeastRequestedPriority: CPU とメモリの使用量を計算して重みが決定され、使用量が低いほど重みが高くなります。言い換えれば、この優先順位インジケーターは、リソース使用率が低いノードを優先します。
  • BalancedResourceAllocation: ノード上の CPU とメモリの使用量が近いほど、重みは高くなります。これは通常、単独ではなく上記と組み合わせて使用​​されます。たとえば、node01 の CPU とメモリの使用量は 20:60、node02 の CPU とメモリの使用量は 50:50 です。node01 の合計使用量は、node02 よりも低いですが、node02 の CPU とメモリの使用量は近くなります。 、したがって、スケジューリング中は、node02 が優先されます。
  • ImageLocalityPriority: ミラーを使用したいノードがすでに存在する傾向があり、ミラーの合計サイズが大きくなるほど、重みが高くなります。

2. 方向性のあるスケジューリング

方向性スケジューリングとは、ポッド上でノード名またはノードセレクターを宣言して、ポッドを目的のノードにスケジュールすることを指します。 ここでのスケジューリングは必須であることに注意してください。つまり、スケジューリングのターゲット ノードが存在しない場合でも、上でスケジュールされますが、ポッドは実行に失敗します。

2.1 NodeName(ノード名)

NodeName は、指定された名前のノード ノードにポッドを強制的にスケジュールするために使用されます。この方法では、スケジューラのスケジューリング ロジックが直接スキップされ、ポッドは指定された名前のノードに直接スケジュールされます。

pod-nodename.yaml ファイルを作成する

apiVersion: v1
kind: Pod
metadata:
  name: pod-nodename
  namespace: dev
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  nodeName: node01        # 指定调度到node01节点上

kubectl apply -f myapp.yaml

kubectl get pods -o wide

##查看详细事件(发现未经过 scheduler 调度分配)
kubectl describe pod pod-nodename 

2.2 NodeSeletor(ノードタグ)

NodeSelector は、指定されたラベルが追加されたノード ノードにポッドをスケジュールするために使用されます。これは、kubernetes のラベル セレクター メカニズムを通じて実装されます。つまり、ポッドが作成される前に、スケジューラーは MatchNodeSelector スケジューリング戦略を使用してラベルの一致とターゲット ノードを見つけると、ポッドがターゲット ノードにスケジュールされます。一致ルールは必須の制約です。

ノードにラベルを追加する

pod-nodeselector.yaml ファイルを作成する

apiVersion: apps/v1
kind: Deployment  
metadata:
  name: myapp1
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp1
  template:
    metadata:
      labels:
        app: myapp1
    spec:
      nodeSelector:
	    kfc: a
      containers:
      - name: myapp1
        image: soscscs/myapp:v1
        ports:
        - containerPort: 80

kubectl apply -f pod-nodeselector.yaml

kubectl get pods pod-nodeselector -o wide

##此时调度到指定标签的节点上,如果在yaml文件中,将标签修改,它将会调度到标签所在的node,即使node不存在。

ラベル関連の設定:

#修改一个 label 的值,需要加上 --overwrite 参数
kubectl label nodes node02 kgc=a --overwrite

#删除一个 label,只需在命令行最后指定 label 的 key 名并与一个减号相连即可:
kubectl label nodes node02 kgc-

#指定标签查询 node 节点
kubectl get node -l kgc=a

3. アフィニティのスケジューリング

公式ドキュメント: https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node/

ディレクテッド スケジューリングは非常に使いやすいですが、特定の問題もあります。つまり、条件を満たすノードがない場合、クラスター内に使用可能なノード リストがあってもポッドは実行されず、ポッドの実行が制限されます。使用シーン

上記の問題点を踏まえ、kubernetesではNodeSelectorをベースに拡張されたアフィニティスケジューリング(Affinity)も提供しており、条件を満たすノードを優先してスケジューリングするように設定することができ、条件を満たさない場合は満たさないノードをスケジューリングすることも可能ですノードを追加し、スケジュールをより柔軟にします。

アフィニティは主に 3 つのカテゴリに分類されます。

  • nodeAffinity (ノード アフィニティ): ポッドがどのノードをスケジュールできるかの問題を解決するターゲット ノード。
  • podAffinity (ポッド アフィニティ): ポッドをターゲットとして、そのポッドを同じトポロジ ドメインにデプロイできる既存のポッドの問題を解決します。
  • podAntiAffinity (ポッド アンチアフィニティ): ポッドを既存のポッドと同じトポロジ ドメインにデプロイできない問題を解決するためにポッドをターゲットにします。
#关于亲和性(反亲和性)使用场景的说明
//亲和性:
如果两个应用频繁交互,那就有必要利用亲和性让两个应用的竟可能靠近,这样可以减少因网络通信而带来的性能损耗。

//反亲和性:
 当应用的采用多副本部署时,有必要采用反亲和性让各个应用实例打散分布在各个node上,这样可以提高服务的高可用性。

3.1 NodeAffinity(ノードアフィニティ)

kubectl explain pod.spec.affinity.nodeAffinity  #查看解释资源

----------------------------------硬限制----------------------------------------------------
  requiredDuringSchedulingIgnoredDuringExecution  #Node节点必须满足指定的所有规则才可以,相当于硬限制
    nodeSelectorTerms  #节点选择列表
      matchFields   #按节点字段列出的节点选择器要求列表
      matchExpressions   #按节点标签列出的节点选择器要求列表(推荐)
        key      #键
        values   #值
        operator  #关系符:支持Exists, DoesNotExist, In, NotIn, Gt, Lt

----------------------------------软限制----------------------------------------------------        
  preferredDuringSchedulingIgnoredDuringExecution #优先调度到满足指定的规则的Node,相当于软限制 (倾向)
    preference   #一个节点选择器项,与相应的权重相关联
      matchFields   #按节点字段列出的节点选择器要求列表
      matchExpressions  #按节点标签列出的节点选择器要求列表(推荐)
        key    #键
        values #值
        operator #关系符:支持In, NotIn, Exists, DoesNotExist, Gt, Lt
	weight    #倾向权重,在范围1-100。
#键值运算关系

●In:label 的值在某个列表中  pending

●NotIn:label 的值不在某个列表中

●Gt:label 的值大于某个值

●Lt:label 的值小于某个值

●Exists:某个 label 存在

●DoesNotExist:某个 label 不存在

关系符的使用说明:

- matchExpressions:
  - key: nodeenv              # 匹配存在标签的key为nodeenv的节点
    operator: Exists
    
  - key: nodeenv              # 匹配标签的key为nodeenv,且value是"xxx"或"yyy"的节点
    operator: In
    values: ["xxx","yyy"]
   
  - key: nodeenv              # 匹配标签的key为nodeenv,且value大于"xxx"的节点(大于小于的是资源的大小。)
    operator: Gt
    values: "xxx"

ハードリミットケース

  • これは方向性スケジューリングに似ており、満たす必要があります。満たさない場合、スケジューリングは失敗し、保留中ステータスが表示されます。
apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: soscscs/myapp:v1
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: kubernetes.io/hostname   #指定node的标签
            operator: NotIn     #设置Pod安装到kubernetes.io/hostname的标签值不在values列表中的node上
            values::
            - node02

ソフトリミットケース

  • ソフトリミットは設定した条件に従って一致しますが、一致しない場合は独自にノードをスケジュールします。
apiVersion: v1
kind: Pod
metadata:
  name: affinity
  labels:
    app: node-affinity-pod
spec:
  containers:
  - name: with-node-affinity
    image: soscscs/myapp:v1
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1   #如果有多个软策略选项的话,权重越大,优先级越高
        preference:
          matchExpressions:
          - key: kubernetes.io/hostname
            operator: In
            values:
            - node03

ハード戦略とソフト戦略を併用する

ハード戦略とソフト戦略を併用する場合、まずハード戦略を満たさなければならず、その後、ソフト戦略を満たすことができます。

NodeAffinityルールを設定する際の注意事項

1、如果同时定义了nodeSelector和nodeAffinity,那么必须两个条件都得到满足,Pod才能运行在指定的Node上。

2、如果nodeAffinity指定了多个nodeSelectorTerms,那么只需要其中一个能够匹配成功即可

3、如果一个nodeSelectorTerms中有多个matchExpressions ,则一个节点必须满足所有的才能匹配成功

4、如果一个pod所在的Node在Pod运行期间其标签发生了改变,不再符合该Pod的节点亲和性需求,则系统将忽略此变化

3.2 PodAffinity(ポッドアフィニティ)

---------------------------------------硬限制-----------------------------------------------

kubectl explain pod.spec.affinity.podAffinity  #查看pod亲和度的解释

  requiredDuringSchedulingIgnoredDuringExecution  #硬限制
    namespaces       #指定参照pod的namespace
    topologyKey      #指定调度作用域
    labelSelector    #标签选择器
      matchExpressions  #按节点标签列出的节点选择器要求列表(推荐)
        key    #键
        values #值
        operator 关系符 #支持In, NotIn, Exists, DoesNotExist.
      matchLabels    #指多个matchExpressions映射的内容
---------------------------------------软限制----------------------------------------------- 
     
  preferredDuringSchedulingIgnoredDuringExecution #软限制
    podAffinityTerm  #选项
      namespaces      
      topologyKey
      labelSelector
        matchExpressions  
          key    键
          values 值
          operator
        matchLabels 
    weight 倾向权重,在范围1-100
#topologyKey 是节点标签的键

1、如果两个节点使用此键标记并且具有相同的标签值,则调度器会将这两个节点视为处于同一拓扑域中;
2、调度器试图在每个拓扑域中放置数量均衡的 Pod;
3、如果 kgc 对应的值不一样就是不同的拓扑域。
#例如:
比如 Pod1 在 kgc=a 的 Node 上,Pod2 在 kgc=b 的 Node 上,Pod3 在 kgc=a 的 Node 上,则 Pod2 和 Pod1、Pod3 不在同一个拓扑域,而Pod1 和 Pod3在同一个拓扑域。

ハードリミットケース

app=myapp01 というラベルのポッドを作成します。

apiVersion: v1
kind: Pod
metadata:
  name: myapp01
  labels:
    app: myapp01
spec:
  containers:
  - name: with-node-affinity
    image: soscscs/myapp:v1

pod02.yamlを作成する

apiVersion: v1
kind: Pod
metadata:
  name: mypod02
  labels:
    app: myapp02
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:  #亲和性设置
    podAffinity: #设置pod亲和性
      requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
      - labelSelector:
          matchExpressions: 
          - key: app
            operator: In
            values: 
            - myapp001
        topologyKey: kubernetes.io/hostname

----------------------------------------------------------------
# 上面配置表达的意思是: 新Pod必须要和拥有标签app: myapp001 的pod在同一node上,显然现在没有这样的pod。

可将亲和度的标签修改如下:
spec:
  containers:
  - name: nginx
    image: nginx:1.17.1
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - myapp01    ##更改为存在的node节点的标签
        topologyKey: kubernetes.io/hostname

ソフトリミットケース

  • ソフト リミットのケースはハード リミットと似ています。

3.3 PodAntiAffinity (ポッドアンチアフィニティ)

PodAntiAffinity は主に、実行中の Pod を参照として使用し、新しく作成された Pod が参照 Pod と同じ領域に存在しないようにする機能を実装します。

例 1:

pod3.yamlを作成し、

apiVersion: v1
kind: Pod
metadata:
  name: myapp03
  labels:
    app: myapp03
spec:
  containers:
  - name: myapp03
    image: soscscs/myapp:v1
  affinity:
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - myapp01
          topologyKey: kubernetes.io/hostname

例 2:

pod4.yamlを作成し、

apiVersion: v1
kind: Pod
metadata:
  name: myapp04
  labels:
    app: myapp04
spec:
  containers:
  - name: myapp04
    image: soscscs/myapp:v1
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - myapp01
        topologyKey: kfc

上記の問題: 指定されたポッドが配置されているノード node01 ノードにはキー kfc とラベル値 a のラベルがあるため、node02 にもラベル kfc=a があります。アンチアフィニティでは、新しい Pod と指定された Pod が同じトポロジ ドメイン内にないことが必要であるため、新しい Pod には使用可能なノードがない (保留状態)。

4. ポッドの汚染

これまでのスケジューリング方法はすべて、ポッドに属性を追加して、ポッドを指定されたノードにスケジュールするかどうかを決定するという、ポッドの観点からのものでした。実際、テイント属性を追加することで、ノードの観点から立つこともできます。 Node. に送信し、Pod のスケジューリングを許可するかどうかを決定します。

ノードが汚染されるように設定されると、そのノードはポッドと相互排他的な関係を持つようになり、そのためポッドのスケジュールを拒否したり、既存のポッドを追放したりすることさえあります。

ステインの形式は: key=value:effect です。key と value はステインのタグです。effect はステインの役割を説明し、次の 3 つのオプションをサポートします。

  • PreferNoSchedule: Kubernetes は、他にスケジュールするノードがない場合を除き、このテイントのあるノード上のポッドのスケジュールを回避しようとします。
  • NoSchedule: Kubernetes は、このテイントを持つノードにポッドをスケジュールしませんが、現在のノードにすでに存在するポッドには影響しません
  • NoExecute: Kubernetes は、このステインのあるノードにポッドをスケジュールせず、ノード上の既存のポッドも削除します。
#注意!!!
//在我们kubernetes集群中,目前有三个节点,两个node一个master,那为什么schedule不把pod调度到master节点上呢?

//因为master节点就设置了最高级的污点,也就是NoEcxecute。pod无法运行。

kubectl を使用してテイントをセットアップおよび削除するコマンド

kubectl taint nodes node01 key=value:NoExecute
#设置污点

kubectl taint nodes node01 key:NoExecute-
#去除污点

kubectl describe node node-name  
#节点说明中,查找 Taints 字段

kubectl taint node node02 check=mycheck:NoExecute

#查看 Pod 状态,会发现 node02 上的 Pod 已经被全部驱逐(注:如果是 Deployment 或者 StatefulSet 资源类型,为了维持副本数量则会在别的 Node 上再创建新的 Pod)
kubectl get pods -o wide

4.1 NoExecute实例

kubectl taint node node02 check=mycheck:NoExecute

注: Deployment または StatefulSet リソース タイプの場合、コピー数を維持するために、新しい Pod が他のノードに作成されます。

4.2 スケジュールなしの例

##清除污点命令
kubectl uncordon <node name>

5. ポッドトレランス(Toleration)

テイントの機能は上で紹介しました。ノードにテイントを追加してポッドのスケジューリングを拒否することができます。しかし、テイントされたノードにポッドをスケジュールしたいだけの場合、この時点で何をすべきでしょうか?これには許容範囲を使用する必要があります。

#污点就是拒绝,容忍就是忽略,Node通过污点拒绝Pod调度上去,Pod通过容忍忽略拒绝

#查看容忍的详细配置
kubectl explain pod.spec.tolerations
....
FIELDS:
   key       //对应着要容忍的污点的键,空意味着匹配所有的键
   value     //对应着要容忍的污点的值
   operator  //key-value的运算符,支持Equal和Exists(默认)
   effect    //对应污点的effect,空意味着匹配所有影响
   tolerationSeconds   //容忍时间, 当effect为NoExecute时生效,表示pod在Node上的停留时间

例 1: NoSchedule テイントの設定

両方のノードに NoSchedule ステインを設定します。

Pod Tolerance を使用してポッドを作成する

apiVersion: v1
kind: Pod
metadata:
  name: myapp01
  labels:
    app: myapp01
spec:
  containers:
  - name: with-node-affinity
    image: soscscs/myapp:v1
  tolerations:
  - key: "ket2"
    operator: "Equal"
    value: "check"
    effect: "NoSchedule"

#其中的 key、vaule、effect 都要与 Node 上设置的 taint 保持一致
#operator 的值为 Exists 将会忽略 value 值,即存在即可
#tolerationSeconds 用于描述当 Pod 需要被驱逐时可以在 Node 上继续保留运行的时间

    tolerationSeconds: 3600

例 2: NoExecute テイントの設定

 Pod Tolerance を使用してポッドを作成する

apiVersion: v1
kind: Pod
metadata:
  name: myapp02
  labels:
    app: myapp02
spec:
  containers:
  - name: with-node-affinity
    image: soscscs/myapp:v1
  tolerations:
  - key: "key1"
    operator: "Equal"
    value: "check"
    effect: "NoExecute"
    tolerationSeconds: 180

#其中的 key、vaule、effect 都要与 Node 上设置的 taint 保持一致
#operator 的值为 Exists 将会忽略 value 值,即存在即可
#tolerationSeconds 用于描述当 Pod 需要被驱逐时可以在 Node 上继续保留运行的时间

#其它注意事项
(1)当不指定 key 值时,表示容忍所有的污点 key
  tolerations:
  - operator: "Exists"
  
(2)当不指定 effect 值时,表示容忍所有的污点作用
  tolerations:
  - key: "key"
    operator: "Exists"

(3)有多个 Master 存在时,防止资源浪费,可以如下设置
kubectl taint node Master-Name node-role.kubernetes.io/master=:PreferNoSchedule
1、如果某个 Node 更新升级系统组件,为了防止业务长时间中断,可以先在该 Node 设置 NoExecute 污点,把该 Node 上的 Pod 都驱逐出去
kubectl taint node node01 check=mycheck:NoExecute

2、此时如果别的 Node 资源不够用,可临时给 Master 设置 PreferNoSchedule 污点,让 Pod 可在 Master 上临时创建
kubectl taint node master node-role.kubernetes.io/master=:PreferNoSchedule

3、待所有 Node 的更新操作都完成后,再去除污点
kubectl taint node node01 check=mycheck:NoExecute-
维护操作
#cordon 和 drain
##对节点执行维护操作:
kubectl get nodes

#将 Node 标记为不可调度的状态,这样就不会让新创建的 Pod 在此 Node 上运行
kubectl cordon <NODE_NAME> 		 #该node将会变为SchedulingDisabled状态

#kubectl drain 可以让 Node 节点开始释放所有 pod,并且不接收新的 pod 进程。drain 本意排水,意思是将出问题的 Node 下的 Pod 转移到其它 Node 下运行
kubectl drain <NODE_NAME> --ignore-daemonsets --delete-local-data --force

--ignore-daemonsets:无视 DaemonSet 管理下的 Pod。
--delete-local-data:如果有 mount local volume 的 pod,会强制杀掉该 pod。
--force:强制释放不是控制器管理的 Pod,例如 kube-proxy。

注:执行 drain 命令,会自动做了两件事情:
(1)设定此 node 为不可调度状态(cordon)
(2)evict(驱逐)了 Pod

#kubectl uncordon 将 Node 标记为可调度的状态
kubectl uncordon <NODE_NAME>
#Pod启动阶段(相位 phase)
Pod 创建完之后,一直到持久运行起来,中间有很多步骤,也就有很多出错的可能,因此会有很多不同的状态。
一般来说,pod 这个过程包含以下几个步骤:
(1)调度到某台 node 上。kubernetes 根据一定的优先级算法选择一台 node 节点将其作为 Pod 运行的 node
(2)拉取镜像
(3)挂载存储配置等
(4)运行起来。如果有健康检查,会根据检查的结果来设置其状态。

フェーズの考えられる状態は次のとおりです。
●保留中: APIServer がポッド リソース オブジェクトを作成して etcd に保存したが、スケジュールされていないことを示します (たとえば、まだノードにスケジュールされていない)、またはまだウェアハウスからイメージをダウンロード中です。

●実行中: ポッドは特定のノードにスケジュールされており、ポッド内のすべてのコンテナは kubelet によって作成されています。少なくとも 1 つのコンテナーが実行中であるか、開始または再起動中です (つまり、Running 状態の Pod には正常にアクセスできない可能性があります)。

●成功: ジョブや cronjob など、一部のポッドは長時間実行されず、一定時間が経過すると、ポッド内のすべてのコンテナが正常に終了し、再起動されません。タスクの実行結果についてのフィードバックが必要です。

●失敗: ポッド内のすべてのコンテナが終了し、少なくとも 1 つのコンテナが失敗により終了しました。つまり、コンテナがゼロ以外のステータスで終了するか、コマンドの書き込みに問題があるなど、システムによって終了されます。

●不明: 通常、kube-controller-manager がポッドと通信できないため、ポッドのステータスを読み取ることができないことを示します。

##故障排除步骤:
//查看Pod事件
kubectl describe TYPE NAME_PREFIX  

//查看Pod日志(Failed状态下)
kubectl logs <POD_NAME> [-c Container_NAME]

//进入Pod(状态为running,但是服务没有提供)
kubectl exec –it <POD_NAME> bash

//查看集群信息
kubectl get nodes

//发现集群状态正常
kubectl cluster-info

//查看kubelet日志发现
journalctl -xefu kubelet

おすすめ

転載: blog.csdn.net/weixin_46254171/article/details/134125262