Kubernetes Pod を正常に再起動する方法

Kubernetes Pod を正常に再起動する方法

解決策1

さまざまな環境に多数の Pod があるため、手動で 1 つずつ再起動することは不可能です。これまでにも同様の操作を実行しました:

 kubectl delete --all pods --namespace=dev

この方法では、dev 名前空間内の Pod をワンクリックで削除でき、Kubernetes はこれらの Pod を自動的に再起動してアプリケーションの可用性を確保します。

しかし、大きな問題は、Kubernetes のスケジュールに大きな負担がかかることです。通常、名前空間の下には少なくとも数百の Pod が存在します。これらすべてを再スケジュールして起動する必要がある場合、 Kubernetesの負荷が非常に高くなり、注意しないと深刻な結果を招くことになります。

したがって、私の最初のバージョンのソリューションは、すべてのデプロイメントを反復処理し、ポッドを削除し、5 分間スリープしてから、次のポッドを削除するというものでした。疑似コードは次のとおりです。

 deployments, err := clientSet.AppsV1().Deployments(ns).List(ctx, metav1.ListOptions{}) if err != nil { return err } for _, deployment := range deployments.Items { podList, err := clientSet.CoreV1().Pods(ns).List(ctx, metav1.ListOptions{ LabelSelector: fmt.Sprintf("app=%s", deployment.Name), }) err = clientSet.CoreV1().Pods(pod.Namespace).Delete(ctx, pod.Name, metav1.DeleteOptions{}) if err != nil { return err } log.Printf(" Pod %s rebuild success.\n", pod.Name) time.Sleep(time.Minute * 5) }

問題点

この解決策は確かに単純かつ粗雑ですが、テスト中に問題が発見されました。

一部のサービスに Pod が 1 つしかない場合、サービスを提供する追加のコピーがないため、直接削除するとサービスは失敗します。

これは絶対に受け入れられません。

削除後に再起動に失敗したものもあります。

  • 長期間再起動しないと、イメージ キャッシュが失われたり、イメージが削除されたりして、正常に起動できなくなります。
  • 一部の Pod には起動時に何かを実行する Init-Container があり、それが失敗すると正常に起動できなくなります。つまり、Pod が正常に起動できず、オンライン運用上の問題に直接つながる状況は多くあるため、ソリューション 1 は絶対に実行可能ではありません。

解決策2

このため、私はプラン2を用意しました。

画像.png

  • まずレプリカの数を 1 増やします。これにより、新しい Pod が追加され、最新のサイドカー イメージが使用されます。
  • 新しく作成された Pod が正常に再起動するまで待ちます。
  • 再起動が成功したら、元の Pod を削除します。
  • その後、コピー数を以前の数に戻します。

これにより、元の Pod をスムーズに再起動できるようになります。新しい Pod の起動に失敗した場合、他の Deployment Pod は再起動されません。古い Pod も保持されますが、サービス自体には影響はありません。

問題点

問題はなさそうですが、実装が面倒で、手順が非常に煩雑です。ここにいくつかのコアコードを貼り付けます:

 func RebuildDeploymentV2(ctx context.Context, clientSet kubernetes.Interface, ns string) error { deployments, err := clientSet.AppsV1().Deployments(ns).List(ctx, metav1.ListOptions{}) if err != nil { return err } for _, deployment := range deployments.Items { // Print each Deployment log.Printf("Ready deployment: %s\n", deployment.Name) originPodList, err := clientSet.CoreV1().Pods(ns).List(ctx, metav1.ListOptions{ LabelSelector: fmt.Sprintf("app=%s", deployment.Name), }) if err != nil { return err } // Check if there are any Pods if len(originPodList.Items) == 0 { log.Printf(" No pod in %s\n", deployment.Name) continue } // Skip Pods that have already been upgraded updateSkip := false for _, container := range pod.Spec.Containers { if container.Name == "istio-proxy" && container.Image == "proxyv2:1.xx" { log.Printf(" Pod: %s Container: %s has already upgrade, skip\n", pod.Name, container.Name) updateSkip = true } } if updateSkip { continue } // Scale the Deployment, create a new pod. scale, err := clientSet.AppsV1().Deployments(ns).GetScale(ctx, deployment.Name, metav1.GetOptions{}) if err != nil { return err } scale.Spec.Replicas = scale.Spec.Replicas + 1 _, err = clientSet.AppsV1().Deployments(ns).UpdateScale(ctx, deployment.Name, scale, metav1.UpdateOptions{}) if err != nil { return err } // Wait for pods to be scaled for { podList, err := clientSet.CoreV1().Pods(ns).List(ctx, metav1.ListOptions{ LabelSelector: fmt.Sprintf("app=%s", deployment.Name), }) if err != nil { log.Fatal(err) } if len(podList.Items) != int(scale.Spec.Replicas) { time.Sleep(time.Second * 10) } else { break } } // Wait for pods to be running for { podList, err := clientSet.CoreV1().Pods(ns).List(ctx, metav1.ListOptions{ LabelSelector: fmt.Sprintf("app=%s", deployment.Name), }) if err != nil { log.Fatal(err) } isPending := false for _, item := range podList.Items { if item.Status.Phase != v1.PodRunning { log.Printf("Deployment: %s Pod: %s Not Running Status: %s\n", deployment.Name, item.Name, item.Status.Phase) isPending = true } } if isPending == true { time.Sleep(time.Second * 10) } else { break } } // Remove origin pod for _, pod := range originPodList.Items { err = clientSet.CoreV1().Pods(ns).Delete(context.Background(), pod.Name, metav1.DeleteOptions{}) if err != nil { return err } log.Printf(" Remove origin %s success.\n", pod.Name) } // Recover scale newScale, err := clientSet.AppsV1().Deployments(ns).GetScale(ctx, deployment.Name, metav1.GetOptions{}) if err != nil { return err } newScale.Spec.Replicas = newScale.Spec.Replicas - 1 newScale.ResourceVersion = "" newScale.UID = "" _, err = clientSet.AppsV1().Deployments(ns).UpdateScale(ctx, deployment.Name, newScale, metav1.UpdateOptions{}) if err != nil { return err } log.Printf(" Depoloyment %s rebuild success.\n", deployment.Name) log.Println() } return nil }

コードがさらに増えていることがわかります。

最終解決策

もっと簡単な方法はありますか?上記の解決策をリーダーに伝えると、彼は唖然としました。これは複雑すぎます。kubectl には直接ローリング再起動を行うコマンドがありませんか?

 ❯ k rollout -h Manage the rollout of one or many resources. Available Commands: history View rollout history pause Mark the provided resource as paused restart Restart a resource resume Resume a paused resource status Show the status of the rollout undo Undo a previous rollout

kubectl rollout restart deployment/abcこのコマンドは、デプロイメントabcに対してローリング アップデートを実行するために使用できます。この更新操作は Kubernetes サーバー上で実行されます。実行手順はソリューション 2 と似ていますが、Kubernetes の実装が私のものよりも厳密である点が異なります。

その後、Istio の公式アップグレード ガイドで次のコマンドも見かけました

したがって、公式ドキュメントを注意深く読む必要があります。

kubectlを統合する

準備が整ったので、このコマンドをスクリプトに統合し、名前空間の下のデプロイメントを走査するときにループで呼び出すことができます。

ただし、 Kubernetes client-go SDKにはこのロールアウト コマンドの API はありません

したがって、kubectl のソース コードを参照して、機能のこの部分をコピーするだけです。しかし幸いなことに、私のプロジェクトでは kubect に直接依存することができます。

 require ( k8s.io/api v0.28.2 k8s.io/apimachinery v0.28.2 k8s.io/cli-runtime v0.28.2 k8s.io/client-go v0.28.2 k8s.io/klog/v2 v2.100.1 k8s.io/kubectl v0.28.2 )

ソース コードで使用されている RestartOptions 構造は公開されているため、ソース コードに基づいて少し変更しました。

 func TestRollOutRestart(t *testing.T) { kubeConfigFlags := defaultConfigFlags() streams, _, _, _ := genericiooptions.NewTestIOStreams() ns := "dev" kubeConfigFlags.Namespace = &ns matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags) f := cmdutil.NewFactory(matchVersionKubeConfigFlags) deploymentName := "deployment/abc" r := &rollout.RestartOptions{ PrintFlags: genericclioptions.NewPrintFlags("restarted").WithTypeSetter(scheme.Scheme), Resources: []string{deploymentName}, IOStreams: streams, } err := r.Complete(f, nil, []string{deploymentName}) if err != nil { log.Fatal(err) } err = r.RunRestart() if err != nil { log.Fatal(err) } }

最後に、いくつかのデバッグ手順を経た後、実行できます。このロジックの部分をループに移動し、スリープを追加してPod を定期的に再起動します。

参考リンク:

  • https://istio.io/latest/docs/setup/upgrade/canary/#data-plane。
  • https://github.com/kubernetes/kubectl/blob/master/pkg/cmd/rollout/rollout_restart.go。

<<:  クラウド移行とは何ですか?クラウドへの移行に関する必須ガイド

>>:  IDC の評価アドバイス: ROI を最大化するには、ワークロードに最適なクラウドを選択してください

推薦する

クラウドコンピューティングが企業を変革し、モバイル化する方法

クラウドが世界をどのように変え、私たちがいかにしてこれほど迅速に仕事ができるようになったかについて、...

ウェブサイトのプロモーションは製品ではなくコンセプトに焦点を当てるべきである

わが国のインターネットの発展速度は日ごとに変化しています。不完全な統計によると、中国のインターネット...

Baiduがそれを含めない理由はいくつかあり、解決策もいくつかある。

ショートビデオ、セルフメディア、インフルエンサーのためのワンストップサービスウェブサイトのインクルー...

QingCloud Hyper-Converged Express Editionが新たにアップグレードされました: シンプルさから始めて、クラウドへの一歩を踏み出します

エンタープライズレベルのフルスタック クラウド ICT サービス プロバイダーである QingClo...

クラウドコンピューティングの発展の10年を詳しく見る

[51CTO.com オリジナル記事] 1. クラウド開発の10年人生にはそれほど多くの十年はありま...

周紅一氏はテンセントが小米に投資したという噂について「小米は2年以内に百度に勝つだろう」とコメントした。

周紅一氏はテンセントが小米に投資したという噂について「小米は2年以内に百度に勝つだろう」とコメントし...

飢餓マーケティングはユーザーエクスペリエンスの向上に役立ちますか?

空腹は人間の本能です。多くの場合、このような状況では、人々はおいしさに惹かれ、他の要素を無視する傾向...

クラウドネイティブ | K8s での VolumeMounts.subPath の賢い使い方

1. 概要場合によっては、単一の Pod 内で複数のパーティがボリュームを共有して使用すると便利なこ...

SEM 入札スキル: 競争入札と市場分析の実践例

昨日のブログ投稿では、競合分析の練習として、Baidu で旅行関連のキーワードを 2 つランダムに検...

friendhosting: 13周年、VPS 50%割引、世界10カ所のデータセンター、無制限のトラフィック、カスタムISO、年間16ユーロから

friendhosting は 13 年間運営されています。公式が 50% 割引コードをリリースしま...

リアルタイムのオーディオとビデオによるソーシャルインタラクションは、ゲーム業界の発展に新たな変数を生み出します。

近年、オンラインライブストリーミングの台頭により、リアルタイムのオーディオとビデオのソーシャルネット...

justhost.asia: 200M 無制限 11 元/月 KVM VPS を成功させる方法

justhost.asia は、暗号通貨 BTC LTC BCH 決済のサポートを公式に発表しました...

Yunzhiウェブサイト構築はBaidu Xiongzhangアカウントに接続し、新しいウェブサイトをローンチ当日に含めることができる

2018年最もホットなプロジェクト:テレマーケティングロボットがあなたの参加を待っています最近、あな...

製品価値とユーザーエクスペリエンス:どちらが重要か?どちらも欠かせない

[編集者注] この記事は、@SamaelRen Shuai の個人ブログに掲載されました。製品価値と...

ネットワーク + ストレージ + 仮想化: 新しいネットワークを構築するための 3 つの要素

現代のデータセンターのあらゆる部分は重要ですが、ネットワークはすべての通信の絶対的な基盤です。そのた...