小さなステップと迅速な反復の開発モデルがますます多くのインターネット企業で認識され、採用されるにつれて、アプリケーションの変更とアップグレードの頻度はますます高くなっています。さまざまなアップグレード ニーズに対応し、アップグレード プロセスがスムーズに進むようにするために、一連の導入およびリリース モデルが誕生しました。
リリースの停止 - アプリケーション インスタンスの古いバージョンを完全に停止してから、新しいバージョンをリリースします。このリリース モデルは主に、新バージョンと旧バージョンの非互換性と共存できない問題を解決することを目的としていますが、一定期間サービスが完全に利用できなくなるという欠点があります。
Blue-green リリース - 同数の新旧バージョンのアプリケーション インスタンスを同時にオンラインでデプロイします。新しいバージョンがテストに合格すると、トラフィックはすぐに新しいサービス インスタンスに切り替えられます。この公開モデルは、ダウンタイム公開でサービスが完全に利用できないという問題を解決しますが、比較的大量のリソースを消費します。
ローリング リリース - アプリケーション インスタンスをバッチで段階的に置き換えます。このリリース モードでは、サービスが中断されず、追加のリソースが過剰に消費されることはありませんが、新バージョンと旧バージョンのインスタンスが同時にオンラインになるため、同じクライアントからのリクエストが新旧バージョン間で切り替わる可能性があります。互換性の問題を引き起こします。
Canary リリース - トラフィックを古いバージョンから新しいバージョンに段階的に切り替えます。一定期間監視して問題がなければ、新バージョンのトラフィックをさらに拡大し、旧バージョンのトラフィックを削減します。
A/B テスト - 2 つ以上のバージョンを同時に起動し、これらのバージョンに関するユーザーのフィードバックを収集し、正式採用に最適なバージョンを分析および評価します。
k8s では、ポッドはデプロイメントとアップグレードの基本単位です。一般に、ポッドはアプリケーション インスタンスを表し、ポッドは Deployment、StatefulSet、DaemonSet、Job などの形式でデプロイおよび実行されます。以下では、これらのデプロイ形式でのポッドのアップグレード方法について説明します。
デプロイメントはポッドの最も一般的なデプロイメント形式であり、ここでは例として Spring Boot に基づく Java アプリケーションを取り上げます。このアプリケーションは、実際のアプリケーションから抽象化された単純なバージョンであり、非常に代表的であり、次のような特徴があります。この間、内部ではサービスを外部に提供できません。
アプリケーションが起動できるからといって、正常にサービスを提供できるわけではありません。
アプリケーションは、サービスを提供できない場合、自動的に終了しないことがあります。
アップグレード プロセス中は、オフラインになろうとしているアプリケーション インスタンスが新しいリクエストを受信せず、現在のリクエストを処理するのに十分な時間を確保する必要があります。
パラメータ構成
kind: Deployment ... spec: replicas: 8 strategy: type: RollingUpdate rollingUpdate: maxSurge: 3 maxUnavailable: 2 minReadySeconds: 120 ... template: ... spec: containers: - name: spring-boot-probes image: registry.cn-hangzhou.aliyuncs.com/log-service/spring-boot-probes:1.0.0 ports: - containerPort: 8080 terminationGracePeriodSeconds: 60 readinessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 30 periodSeconds: 10 successThreshold: 1 failureThreshold: 1 livenessProbe: httpGet: path: /actuator/health port: 8080 initialDelaySeconds: 40 periodSeconds: 20 successThreshold: 1 failureThreshold: 3 ...
戦略を通じてポッド交換戦略を構成できます。主なパラメーターは次のとおりです。
.spec.strategy.typeローリングアップデート - K8 はバッチでポッドを徐々に置き換え、サービスのホット アップグレードを実装するために使用できます。
maxSurge と maxUnavailable を調整することで、さまざまなシナリオでのアップグレードのニーズを満たすことができます。
システムの可用性と安定性を確保しながらできるだけ早くアップグレードしたい場合は、maxUnavailable を 0 に設定し、maxSurge に大きな値を指定します。
システム リソースが不足していてポッドの負荷が低い場合、アップグレードを高速化するために、maxSurge を 0 に設定し、maxUnavailable に大きな値を指定できます。 maxSurge が 0 で maxUnavailable が望ましい場合、サービス全体が利用できなくなる可能性があることに注意してください。この時点では、RollingUpdate はシャットダウン リリースに低下します。
サンプルでは妥協の解決策を選択し、maxSurge を 3 に設定し、maxUnavailable を 2 に設定します。これにより、安定性、リソース消費、アップグレード速度のバランスがとれます。
K8s は、次の 2 種類のプローブを提供します。
ReadinessProbe - デフォルトでは、ポッド内のすべてのコンテナが開始されると、k8s はポッドが準備完了状態にあると見なし、ポッドにトラフィックを送信します。ただし、一部のアプリケーションは起動後、外部サービスを提供する前にデータや設定ファイルのロードを完了する必要があるため、コンテナが起動したかどうかによってコンテナの準備ができているかどうかを判断することは厳密ではありません。コンテナーの readiness プローブを構成することにより、k8s はコンテナーの準備ができているかどうかをより正確に判断できるため、より堅牢なアプリケーションを構築できます。 K8s は、ポッド内のすべてのコンテナーが準備完了の検出に合格した場合にのみ、サービスがポッドにトラフィックを送信できるようにします。準備完了の検出が失敗すると、k8s はポッドへのトラフィックの送信を停止します。
LivenessProbe - デフォルトでは、k8s は実行中のコンテナが利用可能であるとみなします。ただし、何か問題が発生したり異常な状態になったりした場合 (たとえば、深刻なデッドロックが発生した場合)、アプリケーションが自動的に終了できない場合、この判断には問題が生じる可能性があります。コンテナーの liveness プローブを構成することにより、k8s はコンテナーが正常に実行されているかどうかをより正確に判断できます。コンテナーが活性検出に失敗した場合、kubelet はコンテナーを停止し、再起動ポリシーに基づいて次のアクションを決定します。
プローブの構成は非常に柔軟で、ユーザーはプローブの検出頻度、検出成功のしきい値、検出失敗のしきい値などを指定できます。各パラメータの意味と設定方法については、「Liveness プローブと Readiness プローブの設定」のドキュメントを参照してください。
このサンプルでは、ターゲット コンテナーの readiness プローブと liveness プローブを構成します。
アプリケーションは平均を取得するため、readiness プローブのInitialDelaySeconds は 30 に設定されます。初期化作業が完了するまでの時間は 30 秒です。
liveness プローブを構成するときは、コンテナーが準備完了状態に達するのに十分な時間を確保する必要があります。パラメータのinitialDelaySeconds、periodSeconds、failureThresholdの設定が小さすぎると、コンテナが準備完了前に再起動され、準備完了状態に到達できなくなる可能性があります。この例の構成では、コンテナーが起動後 80 秒以内に準備ができた場合は再起動されないことが保証されており、これは平均初期化時間の 30 秒と比較すると十分なバッファーです。
readiness Probe の periodSeconds は 10 に設定され、failureThreshold は 1 に設定されます。このようにして、コンテナに異常がある場合、約 10 秒後にはトラフィックが送信されなくなります。
アクティビティ プローブの periodSeconds は 20 に設定され、failureThreshold は 3 に設定されます。これにより、コンテナに異常が発生した場合、約60秒経過すると再起動されなくなります。
デフォルトでは、新しく作成されたポッドの準備が整うと、k8s はそのポッドが利用可能であるとみなし、古いポッドを削除します。ただし、新しいポッドが実際にユーザーのリクエストを処理しているときに問題が露呈する場合があるため、より堅牢なアプローチは、古いポッドを削除する前に、新しいポッドを一定期間観察することです。
パラメータ minReadySeconds は、ポッドが準備完了状態にあるときの観察時間を制御できます。この期間中にポッド内のコンテナが正常に実行できる場合、k8s は新しいポッドが利用可能であるとみなして古いポッドを削除します。このパラメータを設定する場合は、小さすぎると十分な観測が行われない可能性があり、大きすぎるとアップグレードの進行が遅くなる可能性があるため、慎重に設定する必要があります。この例では、minReadySeconds を 120 秒に設定します。これにより、準備完了状態のポッドが完全な活性検出サイクルを通過できるようになります。
k8s がポッドを削除する準備ができると、ポッド内のコンテナに TERM シグナルを送信し、同時にサービスのエンドポイント リストからポッドを削除します。指定された時間 (デフォルトは 30 秒) 内にコンテナが終了できない場合、k8s はコンテナに SIGKILL シグナルを送信してプロセスを強制終了します。ポッド終了の詳細なプロセスについては、ドキュメント「ポッドの終了」を参照してください。
アプリケーションはリクエストの処理に最大 40 秒かかるため、シャットダウンする前にサーバーに到着したリクエストを処理できるように、サンプルでは正常なシャットダウン時間を 60 秒に設定しています。さまざまなアプリケーションに対して、実際の条件に応じて terminationGracePeriodSeconds の値を調整できます。
上記の構成により、ターゲット アプリケーションのスムーズなアップグレードが保証されます。 Deployment で PodTemplateSpec のフィールドを変更することでポッドのアップグレードをトリガーし、コマンド kubectl get rs -w
を実行してアップグレードの動作を観察できます。ここで観察される古いバージョンと新しいバージョンのポッド コピーの数の変化は次のとおりです。
maxSurge 新しいポッドを作成します。この時点で、ポッドの総数は許容される上限、つまり DESIRED maxSurge に達します。
新しいポッドの準備が整うか使用可能になるのを待たずに、maxUnavailable の古いポッドの削除プロセスを直ちに開始します。現時点では、使用可能なポッドの数は [望ましい] - maxUnavailable です。
古いポッドが完全に削除されると、新しいポッドがすぐに追加されます。
新しいポッドが準備完了の検出を通過して準備完了になると、k8s はポッドにトラフィックを送信します。ただし、指定された観察時間に達していないため、ポッドは使用可能とみなされません。
準備完了ポッドが観察期間中に正常に実行されている場合、そのポッドは使用可能であるとみなされ、この時点で、古いポッドの削除プロセスを再度開始できます。
古いポッドがすべて削除され、使用可能な新しいポッドがレプリカの目標数に達するまで、手順 3、4、5 を繰り返します。
应用的升级并不总会一帆风顺,在升级过程中或升级完成后都有可能遇到新版本行为不符合预期需要回滚到稳定版本的情况。K8s 会将 PodTemplateSpec 的每一次变更(如果更新模板标签或容器镜像)都记录下来。这样,如果新版本出现问题,就可以根据版本号方便地回滚到稳定版本。回滚 Deployment 的详细操作步骤可参考文档 Rolling Back a Deployment。
StatefulSet 是针对有状态 pod 常用的部署形式。针对这类 pod,k8s 同样提供了许多参数用于灵活地控制它们的升级行为。好消息是这些参数大部分都和升级 Deployment 中的 pod 相同。这里重点介绍两者存在差异的地方。
在 k8s 1.7 及之后的版本中,StatefulSet 支持 OnDelete 和 RollingUpdate 两种策略类型。
OnDelete - 当更新了 StatefulSet 中的 PodTemplateSpec 后,只有手动删除旧的 pod 后才会创建新版本 pod。这是默认的更新策略,一方面是为了兼容 k8s 1.6 及之前的版本,另一方面也是为了支持升级过程中新老版本 pod 互不兼容、无法共存的场景。
RollingUpdate - K8s 会将 StatefulSet 管理的 pod 分批次逐步替换掉。它与 Deployment 中 RollingUpdate 的区别在于 pod 的替换是有序的。例如一个 StatefulSet 中包含 N 个 pod,在部署的时候这些 pod 被分配了从 0 开始单调递增的序号,而在滚动更新时,它们会按逆序依次被替换。
可以通过参数.spec.updateStrategy.rollingUpdate.partition
实现只升级部分 pod 的目的。在配置了 partition 后,只有序号大于或等于 partition 的 pod 才会进行滚动升级,其余 pod 将保持不变。
Partition 的另一个应用是可以通过不断减少 partition 的取值实现金丝雀升级。具体操作方法可参考文档 Rolling Out a Canary。
DaemonSet 保证在全部(或者一些)k8s 工作节点上运行一个 pod 的副本,常用来运行监控或日志收集程序。对于 DaemonSet 中的 pod,用于控制它们升级行为的参数与 Deployment 几乎一致,只是在策略类型方面略有差异。DaemonSet 支持 OnDelete 和 RollingUpdate 两种策略类型。
OnDelete - 当更新了 DaemonSet 中的 PodTemplateSpec 后,只有手动删除旧的 pod 后才会创建新版本 pod。这是默认的更新策略,一方面是为了兼容 k8s 1.5 及之前的版本,另一方面也是为了支持升级过程中新老版本 pod 互不兼容、无法共存的场景。
RollingUpdate - 其含义和可配参数与 Deployment 的 RollingUpdate 一致。
滚动更新 DaemonSet 的具体操作步骤可参考文档 Perform a Rolling Update on a DaemonSet。
Deployment、StatefulSet、DaemonSet 一般用于部署运行常驻进程,而 Job 中的 pod 在执行完特定任务后就会退出,因此不存在滚动更新的概念。当您更改了一个 Job 中的 PodTemplateSpec 后,需要手动删掉老的 Job 和 pod,并以新的配置重新运行该 job。
K8s 提供的功能可以让大部分应用实现零宕机时间和无生产中断的升级,但也存在一些没有解决的问题,主要包括以下几点:
目前 k8s 原生仅支持停机发布、滚动发布两类部署升级策略。如果应用有蓝绿发布、金丝雀发布、A/B 测试等需求,需要进行二次开发或使用一些第三方工具。
K8s 虽然提供了回滚功能,但回滚操作必须手动完成,无法根据条件自动回滚。
有些应用在扩容或缩容时同样需要分批逐步执行,k8s 还未提供类似的功能。
实例配置:
livenessProbe: failureThreshold: 3 httpGet: path: /user/service/test port: 8080 scheme: HTTP initialDelaySeconds: 40 periodSeconds: 20 successThreshold: 1 timeoutSeconds: 1 name: dataline-dev ports: - containerPort: 8080 protocol: TCP readinessProbe: failureThreshold: 1 httpGet: path: /user/service/test port: 8080 scheme: HTTP initialDelaySeconds: 30 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 1
经测试 , 再对sprintboot 应用进行更新时, 访问不再出现502的报错。
以上がk8s サービス springboot プロジェクト アプリケーションをアップグレードする際の 502 エラーを解決する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。