k8s ヘルスチェックによって引き起こされた問題を覚えておいてください

問題の背景

携帯電話に警告テキスト メッセージが届きました。オンライン環境のインターフェースが異常です。! ! アラーム内容は、ある外部サービスAPIのステータスコードが異常で、ステータスコードが500というものです。善良な人が PaaS プラットフォーム (KuberSphere) に行って最初の反応を確認したところ、サービスのポッドが再起動中であることがわかり、再起動後も再起動を続けていました。このとき、別のアラーム復旧メッセージを受信し(アラーム メッセージから約 1 分後)、ステータス コードは 200 でした。. . この記事では、この問題について説明します。

k8s ヘルスチェック

k8s プローブ

k8s プローブは、コンテナーでkubeletによって実行される定期的な診断です。診断を実行するために、kubelet はコンテナによって実装されたHandlerを呼び出します。ハンドラーには次の 3 つのタイプがあります。

  • ExecAction : コンテナ内で指定されたコマンドを実行します。コマンドが戻りコード 0 で終了した場合、診断は成功したと見なされます。
  • CPSocketAction : 指定されたポートでコンテナーの IP アドレスに対して TCP チェックを実行します。ポートが開いている場合、診断は成功したと見なされます。
  • HTTPGetAction : 指定されたポートとパス上のコンテナーの IP アドレスに対して HTTP Get 要求を実行します。応答のステータス コードが 200 以上 400 未満の場合、診断は成功したと見なされます。

k8s ヘルスチェックプローブ

  • livenessProbe (survival probe) : It is used to determine whether the container is alive (Running state). livenessProbe プローブがコンテナーが異常であることを検出した場合、kubelet はコンテナーを「kill」し、コンテナーの再起動戦略に従って対応する処理を行います。 . コンテナーに livenessProbe プローブが含まれていない場合、kubelet は、コンテナーの livenessProbe プローブによって返される値が常に Success であると見なします。
  • readinessProbe (readiness プローブ) : コンテナー サービスが利用可能 (Ready 状態) であるかどうか、および Ready 状態に達した Pod がリクエストを受信できるかどうかを判断するために使用されます。Service によって管理される Pod の場合、Service と PodEndpoint の間の関係も、Pod が Ready であるかどうかに基づいて設定されます。実行中のプロセス中に Ready ステータスが False になると、システムはそれを Service のバックエンド エンドポイント リストから自動的に分離し、Ready 状態に復元された Pod をバックエンド エンドポイント リストに追加します。
  • startupProbe (スタートアップ プローブ) : startupProbe が構成されている場合、他のプローブは成功するまで禁止され、成功後にそれ以上のプローブは実行されません。コンテナーの起動時間が長いシナリオに適しています。kubernetes バージョン v1.18 以降が必要です。

問題を特定する

構成するヘルスチェックは次のとおりです。

livenessProbe:
  httpGet:
    path: /actuator/health
    port: 8080
    scheme: HTTP
  initialDelaySeconds: 90
  timeoutSeconds: 3
  periodSeconds: 10
  successThreshold: 1
  failureThreshold: 3
readinessProbe:
  httpGet:
    path: /actuator/health
    port: 8080
    scheme: HTTP
  initialDelaySeconds: 90
  timeoutSeconds: 3
  periodSeconds: 10
  successThreshold: 1
  failureThreshold: 3
复制代码

以下に、いくつかの構成の意味を示します。

構成 意味
httpGet.path リクエストパスを取得
httpGet.port リクエストポートを取得
httpGet.scheme リクエストプロトコルを取得
initialDelaySeconds 初期遅延 (秒単位)。コンテナーが開始してからヘルスをチェックするまでに待機する時間。
タイムアウト秒 タイムアウト (秒単位)、プローブが完了するまでの待機時間。この時間を超えると、プローブは失敗したと見なされます。デフォルトは 1 秒です。最小値は 1 です。
期間秒 プローブの実行頻度 (秒)、プローブを実行する頻度 (秒単位)。デフォルトは 10 秒です。最小値は 1 です。
成功のしきい値 正常性しきい値。検出が失敗した後、最小連続成功検出が成功します。デフォルト値は 1 です。最小値は 1 です。liveness プローブおよび start プローブでは 1 でなければなりません。
障害しきい値 不健全なしきい値。プローブが失敗状態になるために必要な連続したプローブ失敗の最小数。

同社提供の設定資料には起動プローブの設定が記載されておらず、デプロイされているk8sのバージョンが起動プローブをサポートしていないことが推測されます。

問題の背景から、いくつかの重要な

  1. ポッドが再起動しています。
  2. ポッドの再起動が完了すると、再起動が続行されます。
  3. 告警短信大概一分钟后告警恢复。

到这里可以联想到,存活探针发送get请求获取到的响应的状态码不在 200 和 400之间或者直接超时,所以容器重启直接影响服务,告警通知;但是配置的初始延迟为90秒太短导致一直重启;就在这时就绪探针判断 Ready 状态变为False,则系统自动将其从 Service 的后端 Endpoint 列表中隔离出去,故障 pod 排除掉之后,告警恢复。

是什么原因导致正在运行的容器,PaaS平台是有事件日志的,当时忘记截图了(盘的时候查不到了)... 记得当时有http超时事件,也有状态码为503的事件。超时可能是网络波动或者大概率是初始延迟设置过短。那么这个503状态码到底是为什么呢?

Actuator

Actuator是Springboot的一个模块,模块提供了Spring Boot的所有生产就绪功能。

Endpoints

Actuator 端点允许您监视应用程序并与之交互。 Spring Boot 包括许多内置端点,并允许您添加自己的端点。 例如,提供基本的应用程序运行状况信息的 health 端点。

Actuator的health端点

我们配置健康检查用的接口就是Actuator提供的 health 端点接口。像我们引入DB依赖,Nacos依赖啥的,这些依赖实现了Actuator的health策略接口HealthIndicator,请求health端点的时候就会调用策略实现类检查健康状况。

health端点的返回会返回一个status,可以通过配置management.endpoint.health.show-details=always设置返回详细信息。

下边是一个详细信息的返回值。

{
    "components":{
        "db":{
            "components":{
                "dataSource":{
                    "details":{
                        "database":"MySQL",
                        "result":1,
                        "validationQuery":"/* ping */ SELECT 1"
                    },
                    "status":{
                        "code":"UP",
                        "description":""
                    }
                },
                "dataSource2":{
                    "details":{
                        "database":"MySQL",
                        "result":1,
                        "validationQuery":"/* ping */ SELECT 1"
                    },
                    "status":{
                        "code":"UP",
                        "description":""
                    }
                }
            },
            "status":{
                "code":"UP",
                "description":""
            }
        },
        "discoveryComposite":{
            "components":{
                "discoveryClient":{
                    "details":{
                        "services":[
                            "***",
                            "***",
                            "***-gateway"
                        ]
                    },
                    "status":{
                        "code":"UP",
                        "description":""
                    }
                }
            },
            "status":{
                "code":"UP",
                "description":""
            }
        },
        "diskSpace":{
            "details":{
                "total":"528309530624",
                "free":"463192977408",
                "threshold":10485760
            },
            "status":{
                "code":"UP",
                "description":""
            }
        },
        "mail":{
            "details":{
                "location":"10.************:25"
            },
            "status":{
                "code":"UP",
                "description":""
            }
        },
        "ping":{
            "details":{

            },
            "status":{
                "code":"UP",
                "description":""
            }
        },
        "refreshScope":{
            "details":{

            },
            "status":{
                "code":"UP",
                "description":""
            }
        }
    },
    "groups":[

    ],
    "status":{
        "code":"UP",
        "description":""
    }
}
复制代码

返回的Status的code编码有四种。

/**
 * 指示组件或子系统处于未知状态。
 */
public static final Status UNKNOWN = new Status("UNKNOWN");

/**
 * 指示组件或子系统按预期运行。
 */
public static final Status UP = new Status("UP");

/**
 * 指示组件或子系统发生了意外故障。
 */
public static final Status DOWN = new Status("DOWN");

/**
 * 指示组件或子系统已从服务中取出,不应再使用。
 */
public static final Status OUT_OF_SERVICE = new Status("OUT_OF_SERVICE");
复制代码

翻看源码看到了这四个编码与http状态码的关系,即 DOWN 和 OUT_OF_SERVICE 会返回http状态码 503,其他返回200状态码。

health端点如果异常,即可以通过详细信息定位到异常的组件!

おすすめ

転載: juejin.im/post/7215253602204418104