私たちは愛する伝統、つまり私たちが収集し、コースの一部として研究するユーティリティの配布に戻ります。 本日、 DevOpsコースとそのツールの1つであるKubernetesがアジェンダにあります。
最近、コンテナオーケストレーション用の新しいエキサイティングなプラットフォームであるKubernetesに基づく分散cronジョブプランニングシステムを作成しました。 Kubernetesはますます人気が高まっており、多くの約束があります。たとえば、エンジニアがアプリケーションを実行しているデバイスを心配する必要はありません。
分散システムはそれ自体が複雑であり、分散システムでのサービスの管理は、管理チームが直面する最も困難な問題の1つです。 新しいソフトウェアの生産への導入と、信頼性の高い管理のトレーニングを非常に真剣に受け止めています。 Kubernetesを管理することの重要性の例(およびなぜそれが非常に複雑なのか!)として、Kubernetesのバグによって引き起こされる事後の優れた1時間ごとの停止を確認してください。
この投稿では、Kubernetesが選ばれた理由を説明します。 既存のインフラストラクチャへの統合プロセス、Kubernetesクラスターの信頼性の構築(および改善)方法、およびKubernetesに基づいて作成された抽象化について検討します。
Kubernetesとは何ですか?
Kubernetesは、クラスターで実行するプログラムを計画するための分散システムです。 Kubernetesにプログラムの5つのコピーを実行するように指示すると、作業ノードでそれらを動的にスケジュールします。 コンテナは使用率を高め、それによりコストを削減し、強力な展開プリミティブにより新しいコードを徐々に展開できます。 セキュリティコンテキストとネットワークポリシーにより、マルチテナントワークロードを安全に実行できます。
Kubernetesには、さまざまなスケジューリングオプションが組み込まれています。 長時間実行されるHTTPサービス、クラスター内のすべてのマシンで実行されるデーモンセット 、1時間ごとに実行されるタスクなどをスケジュールできます。 Kubernetesはさらに優れています。 知りたい場合は、Kelsey Hightowerの優れたパフォーマンスを確認してください。 システム管理者とhealthz 向けのKubernetesから始めることができます。 Slackの良いコミュニティを忘れないでください。
Kubernetesを選ぶ理由
各インフラストラクチャプロジェクト(願っています!)はビジネスのニーズから始まります。私たちのタスクは、既存のcronジョブプランニングシステムの信頼性とセキュリティを改善することです。 要件は次のとおりです。
- 実装とプロジェクト管理は比較的小さなチームで可能です(このプロジェクトにフルタイムで取り組んでいるのは2人だけです)。
- 20台のマシンで約500の異なるタスクを計画できます。
そして、Kubernetesを選んだ理由はいくつかあります。
- 既存のオープンソースプロジェクトに基づいて作成したい。
- Kubernetesには分散タスクスケジューラが含まれているため、独自に作成する必要はありません。
- Kubernetesは、参加できる積極的な開発プロジェクトです。
- KubernetesはGoで記述されており、簡単に習得できます。 Kubernetesのバグ修正のほとんどすべては、Goの経験がなかったプログラマーによって作成されました。
- Kubernetesを管理できれば、将来的にはKubernetesに基づいて既に作成できるようになります(たとえば、現在、Kubernetesに基づいて機械学習モデルをトレーニングするシステムに取り組んでいます)。
以前は、タスクスケジューラとしてCronosを使用していましたが、信頼性の要件を満たすのをやめ、現在ほとんどサポートされていません(過去9か月で1コミット、2016年3月にプルリクエストが最後に追加されたとき)。 したがって、既存のクラスターの改善に投資することはもう決めませんでした。
Kubernetesを検討している場合は、他の会社がKubernetesを使用しているという理由だけでKubernetesを使用しないでください。 信頼性の高いクラスターを作成するには、膨大な時間が必要であり、ビジネスでの使用方法は必ずしも明らかではありません。 時間を賢く投資してください。
信頼性とはどういう意味ですか?
サービス管理に関しては、「信頼できる」という言葉自体は意味がありません。 信頼性について話すには、最初にSLO(サービスレベル目標、つまりサービスの目標レベル)をインストールする必要があります。
3つの主なタスクがありました。
- タスクの99.99%を計画し、計画時間の20分以内に実行する必要があります。 20分というのはかなり長い時間ですが、社内のクライアントにインタビューしたので、これ以上正確性を要求する人はいませんでした。
- 割り当ては、ケースの99.99%で完了する必要があります(中断することなく)。
- Kubernetesへの移行により、クライアント側のインシデントが発生することはありません。
これにはいくつかの意味があります。
- Kubernetes APIの短いダウンタイムは許容されます(10分落ちた場合-5分以内に回復できる場合は重要ではありません)。
- バグの計画(既に実行中のタスクがクラッシュするか、まったく開始できない場合)は受け入れられません。 バグ計画レポートを非常に真剣に受け止めました。
- タスクが頻繁に中断されないように、囲炉裏の削除とインスタンスの破棄に注意する必要があります。
- 良い移動計画が必要です。
Kubernetesクラスターの作成
最初のKubernetesクラスターを作成する基本的なアプローチは、 kubeadmやkopsなどのツールを使用せずにクラスターをゼロから作成することでした 。 標準の構成管理ツールであるPuppetを使用して構成を作成しました。 ゼロから作成することには2つの理由があります。Kubernetesをアーキテクチャに深く統合できることと、その内部構造に関する幅広い知識を得たことです。
最初から構築することで、Kubernetesを既存のインフラストラクチャに統合できました。 ロギング、証明書管理、シークレット、ネットワークセキュリティ、モニタリング、AWSインスタンス管理、デプロイ、プロキシデータベース、内部DNSサーバー、構成管理など、既存のシステムとのシームレスな統合を望んでいました。 これらすべてのシステムの統合には創造的なアプローチが必要な場合がありましたが、一般に、kubeadm / kopsに必要な処理を強制する試みよりも簡単であることが判明しました。
私たちはすでに既存のシステムを管理する方法を信頼し、知っているので、新しいKubernetesクラスターでそれらを引き続き使用したいと考えました。 たとえば、信頼できる証明書管理は非常に難しい問題ですが、既に解決する方法があります。 有能な統合により、Kubernetes用の新しいCAの作成を回避できました。
Kubernetesのインストールにどのような設定が影響するかを正確に理解する必要がありました。 たとえば、証明書/ CA認証を構成するために12個以上のパラメーターが使用されました。 これらのオプションをすべて理解することで、認証の問題が見つかったときにインストールをデバッグしやすくなりました。
Kubernetesの信頼を築く
Kubernetesの使用開始当初、チーム内の誰も使用していません(ホームプロジェクトのみ)。 「私たちは誰もKubernetesを使用したことがありません」から「本番環境でKubernetesを使用することに自信があります」からどのように来るのでしょうか?
戦略0:他の会社と話す
Kubernetesでの経験について他の企業の何人かに尋ねました。 彼らはすべて、さまざまな方法でさまざまな環境でそれを使用しました(HTTPサービスの開始、ベアメタル、 Google Kubernetes Engineなど)。
Kubernetesのような大規模で複雑なシステムに関しては、アプリケーションのケースについて考え、実験し、環境に自信を持ち、自分で決定することが特に重要です。 たとえば、この投稿を読んだ後は、「KubernetesはStripeで正常に使用されているので、できます!」と決めてはいけません。
Kubernetesのさまざまなクラスター管理会社との会話から学んだことは次のとおりです。
- etcdクラスターの信頼性に優先順位を付けます(Kubernetesクラスターの状態はetcdに保存されます)。
- Kubernetesの一部の機能は他の機能よりも安定しているため、アルファ機能に注意してください。 一部の企業は、安定性が複数のリリースで連続して確認された後、安定したアルファ関数を使用します(つまり、関数が1.8で安定した場合、1.9または1.10を待ってから使用します)。
- GKE / AKS / EKSなどのKubernetesがホストするシステムを詳しく見てみましょう。 自分でフェールセーフKubernetesシステムをゼロからインストールするのは難しい作業です。 このプロジェクトの間、AWSにはKubernetes管理サービスがなかったため、考慮しませんでした。
- オーバーレイネットワーク/ソフトウェアネットワークに起因する余分なネットワーク遅延に注意してください。
もちろん、他の企業との会話では、Kubernetesが私たちに適しているかどうかについて明確な答えを出していませんでしたが、質問や懸念を提供してくれました。
戦略1:コードを読む
Kubernetesの1つのコンポーネントであるcronジョブコントローラーに大きく依存することを計画しました。 その時、彼はアルファであり、興奮の少しの原因でした。 テストクラスタでテストしましたが、運用環境で適切かどうかを確認するにはどうすればよいでしょうか。 幸いなことに、すべてのコントローラー機能コードは400行で構成されています。 ソースコードをすばやく読むと、次のことがわかりました。
- コントローラーはステートレスサービスです(etcdを除く他のKubernetesコンポーネントと同様)。
- 10秒ごとに、このコントローラーはsyncAll関数を呼び出します:go wait.Until(jm.syncAll、10 * time.Second、stopCh);
- syncAll関数は、Kybernetes APIからすべてのタスクを返し、このリストを調べて、次に開始するタスクを決定してから開始します。
基本的なロジックは簡単に理解できました。 さらに重要なことは、コントローラーでバグが検出された場合、おそらく自分で修正できることです。
戦略2:ストレステストを実行する
クラスターの構築を開始する前に、負荷テストを実施しました。 Kubernetesクラスターが処理できるノードの数については心配していませんでした(約20ノードを展開する予定でした)。Kubernetesが必要な数のタスクに耐えられることを確認することが重要でした(1分あたり約20)。
3日間のクラスターでテストを実施し、1000のcronジョブが作成され、それぞれが1分間に1回起動されました。 すべてのタスクはbash -c 'echo hello world'を実行しただけです。 単純なタスクを選択したのは、全体的なコンピューティング能力ではなく、クラスター計画とオーケストレーションの機能をテストしたかったからです。
テストクラスターは、毎分1000タスクに耐えることができませんでした。 各ノードは1秒あたり最大1つを起動し、クラスターは問題なく1分あたり200タスクを実行できることがわかりました。 1分間に約50のタスクが必要であることを考えると、そのような制限は私たちをブロックしないと判断されました(そして、必要に応じて後で解決できます)。 どうぞ!
戦略3:フェールオーバーetcdクラスターの作成とテストの優先順位付け
Kubernetesを設定する場合、etcdを正しく実行することが非常に重要です。 EtcdはKubernetesクラスターの中心であり、クラスターに関するすべてのデータが保存されます。 etcdを除くすべてに状態はありません。 etcdが実行されていない場合、Kubernetesクラスターに変更を加えることはできません(ただし、既存のサービスは引き続き機能します!)。
起動時に、2つの重要な点に留意する必要があります。
- ノードが失われたときにクラスターが停止しないようにレプリケーションをセットアップします。 現在、etcdのコピーが3つあります。
- 十分なI / O帯域幅があることを確認してください。 etcdのこのバージョンでは、1つのノードでfsync遅延が大きくなると、リーダーの選択が長くなり、クラスターにアクセスできなくなるという問題がありました。 ノードのI / O帯域幅がetcdによって作成されたレコードの数よりも高くなるようにすることで、これを修正しました。
レプリケーションの構成-タスクは「忘れられた」カテゴリーではありません。 etcdノードが失われても、クラスターは引き続き正常に復元されることを慎重にテストしました。
etcdクラスターを構成するために実行したタスクの一部を以下に示します。
- レプリケーションを構成する
- クラスターetcdの可用性を確認します(etcdが落ちた場合、すぐにこれを認識しておく必要があります)。
- 新しいetcdノードを簡単に作成してクラスターに追加する簡単なツールを作成します。
- 実稼働環境で複数のetsdクラスターを実行できるように、etcd Consul統合を追加します。
- バックアップetcdからのリカバリのテスト。
- ダウンタイムなしでクラスターを完全に再構築する機能をテストします。
早めにテストしていただき、大変うれしく思います。 ある金曜日の朝、etcdノードの1つが実稼働クラスターでpingを停止しました。 これに関する警告を受け、ノードを破壊し、新しいノードを作成し、クラスターに追加しました。この間、Kubernetesは中断することなく動作を続けました。 すごい
戦略4:タスクをKubernetesに徐々に転送する
私たちの主な目標の1つは、混乱を引き起こすことなくタスクをKubernetesに転送することでした。 生産移管を成功させる秘secretは、エラーのないプロセス(これは不可能です)ではなく、エラーによる害を減らすような方法でプロセスを設計することにあります。
私たちは新しいクラスターへの移行を必要とする多種多様なタスクの幸せな所有者だったので、その中には影響力の低いものがありました-それらを転送する際のいくつかのエラーは許容できました。
移行を開始する前に、古いシステムと新しいシステム間で5分以内にタスクを移動できる使いやすいツールを作成しました。 このツールはエラーによるダメージを軽減しました-計画していない依存関係を持つタスクを転送した場合、問題ではありません! 単純に元に戻し、問題を修正して再試行できます。
この移行戦略を順守しました。
- 重要度に応じてタスクを大まかに分散します。
- 複数のタスクをKubernetesに繰り返し転送します。 新しい問題領域が見つかった場合は、すぐにロールバックし、問題を修正して再試行してください。
戦略5:Kubernetesのバグを調査する(および修正する)
プロジェクトの最初に、ルールを設定します。Kubernetesが予期しないことをした場合、理由を理解して修正を提案する必要があります。
各バグの解析には時間がかかりますが、非常に重要です。 Kubernetesの奇妙な動作を単純に却下し、分散システムの複雑さが原因であると判断した場合、新しいバグが発生するたびに、それは私たちのせいだと思われます。
このアプローチをとった後、Kubernetesにいくつかのバグが見つかりました(そして修正されました!)。
これらのテスト中に見つかった問題の一部を次に示します。
- 52文字を超える名前を持つCronjobは、静かにタスクのスケジュールに失敗します ( ここで修正済み)。
- ポッドは、保留状態( こことここで修正済み)で永久にフリーズできます。
- スケジューラは3時間ごとにクラッシュします( ここで修正済み)。
- Flannel hostgwバックエンドは、廃止されたルート値を置き換えていません( ここで修正済み)。
これらのバグを修正することで、プロジェクトでのKubernetesの使用との関連性が高まりました。十分に機能するだけでなく、パッチも受け入れられ、優れたPRレビュープロセスが行われました。
Kubernetesには、他のソフトウェアと同様にバグがたくさんあります。 たとえば、スケジューラは頻繁に使用します(タスクは常に新しいポッドを作成するため)。また、スケジューラのキャッシュの使用は、バグ、リグレッション、クラッシュに変わることがあります。 キャッシングは難しいです! しかし、コードベースはアクセス可能であり、遭遇したすべてのバグに対処することができました。
もう1つの注目すべき問題は、Kubernetesの炉床転送ロジックです。 Kubernetesには、ノードコントローラーと呼ばれるコンポーネントがあります。このコンポーネントは、ハースを削除し、応答がない場合に他のノードにハースを移動します。 すべてのノードからの応答がない場合(ネットワークおよび構成の問題など)、Kubernetesはクラスター内のすべてのポッドを破棄できる場合があります。 テストの開始時にこれに直面しました。
大規模なKubernetesクラスターを起動する場合は、ノードコントローラーのドキュメントを注意深く読み、構成を検討し、ハードテストを行います。 ネットワーク制限を作成することにより、この設定の構成(--pod-eviction-timeoutなど)の変更をテストするたびに、驚くべきことが起こりました。 実稼働時の午前3時にではなく、テストからそのような驚きについて学ぶことをお勧めします。
戦略6:Kubernetsクラスターに意図的に問題を作成する
Stripeでのゲーミングデイエクササイズの開始については既に説明しましたが、現在も継続しています。 アイデアは、本番環境で発生する可能性のある状況(たとえば、Kubernetes APIサーバーの損失)を考え出し、それを具体的に作成して(営業日中に警告を表示)、それらを修正できることを確認することです。
クラスターでいくつかの演習を行うと、ギャップの監視や構成エラーなどの問題が明らかになりました。 6か月後の偶然ではなく、事前に管理された環境でこれらの問題を発見できたことを非常に喜んでいます。
私たちが実施したいくつかのゲーム演習:
- 単一のKubernetes APIサーバーをシャットダウンします。
- すべてのKubernetes APIサーバーをシャットダウンして引き上げます(驚くことに、すべてが正常に機能しました)。
- etcdノードをシャットダウンします。
- APIサーバーからのKubernetesクラスター内の作業ノードの中断(通信機能を失うため)。 その結果、これらのノードからのすべてのポッドは他のノードに転送されました。
Kubernetesが故障に十分耐えられたことを非常に嬉しく思います。 Kubernetesはエラーに耐えるように設計されています-すべての状態を保存するetcdクラスター、データベース用のシンプルなRESTインターフェイスであるAPIサーバー、およびクラスター管理を調整するステートレスコントローラーのセットがあります。
Kubernetesのルートコンポーネント(APIサーバー、コントローラー管理、スケジューラー)のいずれかが中断されて再起動された場合、回復後すぐにetcdから状態を読み取り、動作を継続します。 これは理論的に引き付けられたものの1つであり、実際にはそれ以上に悪化することはありませんでした。
テスト中に見つかった問題の一部を次に示します。
- 「奇妙なことに、私はこれについて知らされていませんでした。 ここで観測を修正する必要があります '';
- 「サーバーAPIインスタンスを破棄して元に戻すと、人間の介入が必要になりました。 より良い修正 '';
- 「ときどき、etcdのフォールトトレランスをチェックすると、APIサーバーは再起動するまでリクエストをタイムアウトします。」
これらのテストを開始した後、見つかった問題を修正しました。監視の改善、見つかった構成設定の修正、Kubernetesのバグの文書化です。
cronジョブを使いやすくします。
Kubernetesベースのシステムをどのように使いやすくしたかについて簡単に説明します。
最初の目標は、チームが自信を持って管理できるタスクを実行するシステムを設計することでした。 Kubernetesに自信を持つようになったとき、エンジニアが新しいcronジョブを簡単に構成して追加することが必要になりました。 ユーザーがシステムを使用するためにKubernetesの内部構造を理解する必要がないように、構成YAML形式を開発しました。 形式は次のとおりです。
name: job-name-here kubernetes: schedule: '15 */2 * * *' command: - ruby - "/path/to/script.rb" resources: requests: cpu: 0.1 memory: 128M limits: memory: 1024M
複雑なことはありません-この形式を取り、 cronジョブKubernetes構成に変換するプログラムを作成しました。これをkubectlで使用します。
また、長さ(Kubernetesタスク名は52文字を超えることはできません)およびタスク名の一意性をチェックするためのテストスイートも作成しました。 現在、ほとんどのタスクでcgroupを使用してメモリ量を制限していませんが、これは将来の計画に含まれています。
この形式は使いやすく、Chronos cronジョブとKubernetes cronジョブの両方を自動的に生成したため、2つのシステム間でタスクを移動するのは簡単でした。 これは、段階的移行の優れた作業における重要な要素でした。 Kubernetesへのタスクの転送でエラーが発生した場合、10分以内に簡単な3行の構成変更を行うだけで、タスクを転送できます。
Kubernetesの監視
Kubernetesクラスターの内部状態を監視することは楽しいことが実証されています。 監視にkube -state-metricsパッケージを使用し、 veneur-prometheusと呼ばれる小さなGoプログラムを使用して、 kube -state-metricsが発行するPrometheusメトリックを収集し、監視システムでstatsdメトリックとして公開します。
これは、たとえば、過去1時間のクラスター内の保留中の炉床の数のグラフです。 保留は、作業ノードへの割り当てが開始されるのを待っていることを意味します。 多くのタスクは1時間の0分から始まるため、午前11時にピーク値を確認できます。
さらに、Pending状態で停止しているポッドがないことを確認します。各ポッドが5分間動作ノードで起動することを確認します。そうでない場合は警告が表示されます。
Kubernetesの今後の計画
Kubernetesを構成し、本番コードを起動してcronジョブを新しいクラスターに移行する準備が整うまでに、3人のフルタイムプログラマーで5か月間で3か月かかりました。 Kubernetesの学習に投資した重要な理由の1つは、ストライプでKubernetesをより広く使用することを期待していることです。
Kubernetes(およびその他の複雑な分散システム)を管理するためのガイドラインを次に示します。
- Kubernetesプロジェクト(およびすべてのインフラストラクチャプロジェクト)の明確なビジネス上の理由を定義します。 ケースとユーザーのニーズを理解すると、プロジェクトが大幅に簡素化されました。
- ボリュームを積極的に減らします。 クラスターを簡素化するためにKubernetesのコア機能の多くを使用しないことにしました。 これにより、プロジェクトを迅速に開始できます。たとえば、Pod-to-Podネットワークがプロジェクトに必須ではないという事実を考えると、ノード間のすべてのネットワーク接続を制限し、Kubernetesのネットワークセキュリティについての考え方を将来のプロジェクトに延期することができました。
- Kubernetesクラスターを適切に管理する方法を学ぶのに多くの時間を費やしてください。 鋭利なケースを慎重にテストします。 分散システムは非常に複雑であるため、多くの問題が発生する可能性があります。 前述の例を考えてみましょう。ノードコントローラーは、構成に応じて、APIサーバーとの接続が失われた場合、クラスター内のすべての炉床を強制終了できます。 各構成変更後のKubernetesの動作の調査には、時間と注意が必要です。
これらの原則に重点を置いて、Kubernetesを本番環境で自信を持って使用できます。 Kubernetesの使用は、成長と進化を続けます。たとえば、AWS EKSのリリースを興味を持って見ています。 別の機械学習モデルトレーニングシステムの作業を完了し、一部のHTTPサービスをKubernetesに移行するオプションも検討しています。 また、本番環境でKubernetesを使用する過程で、オープンソースプロジェクトに貢献する予定です。
終わり
いつものように、私たちはあなたのコメント、質問をここで、または私たちの公開日に待っています。