Kubernetes サービスの検出についてお話ししましょう。したがって、まず前提として、ホスト内通信とホスト間通信の両方が正常であること、つまり、同じ Kubernetes クラスター内のすべての Pod が相互運用可能であることが求められます。これは、docker0/CNI ブリッジ、Flannel vxlan/host-gw モードなどの低レベルのソリューションによって実現されますが、この記事では説明しません。
すべての Pod が相互接続されているという前提の下では、podIP にアクセスすることで Pod 上のリソースを呼び出すことができますが、サービス検出までどのくらいかかるのでしょうか?まず、Pod IP は固定ではありません。一方、Pod インスタンスのグループにアクセスする場合は、負荷分散が必要になることがよくあります。このような問題を解決するために、Service オブジェクトが使用されます。 クラスター内通信エンドポイントサービスはまず、クラスター内の通信の必要性を解決します。まず、一般的なデプロイメントを記述します。
このアプリケーションは、アクセス時に独自のホスト名を返すもので、各 Pod にはホスト名として APP というラベルが付けられます。 次に、これらのポッドに共通の Service を記述します。
サービスがセレクターを通じて対応するラベルを持つポッドを選択し、選択されたこれらのポッドがエンドポイントになることがわかります。試してみましょう:
Pod に問題がある場合、実行状態でない場合、または readinessProbe に失敗した場合、その Pod はエンドポイント リストから削除されます。 クラスターIP上記にはサービスとエンドポイントがあり、作成されるサービスのデフォルト タイプは ClusterIP タイプです。先ほど作成したサービスを見てみましょう。
ClusterIP は 10.212.8.127 であることがわかります。これで、Kubernetes クラスターのこのアドレスを介してエンドポイント リスト内の任意の Pod にアクセスできるようになります。
ClusterIP アドレスに 3 回アクセスし、3 つの異なるホスト名を返した後、ClusterIP モード サービスが要求に対してラウンドロビン負荷分散を自動的に実行していることがわかりました。 現時点での ClusterIP モード サービスには、ClusterIP アドレスを指す service-name.namespace-name.svc.cluster.local の A レコードがあります。
もちろん、この A レコードを介してアクセスすることでも同じ効果が得られます。
では、Pod の A レコードとは何でしょうか?見てみましょう:
ヘッドレスサービスデフォルトでは、サービスの CluserIP は Kubernetes によって自動的に割り当てられますが、自分で設定することもできます。 CluserIP を None に設定すると、ヘッドレス サービスになります。 ヘッドレス サービスは通常、StatefulSet とともに使用されます。 StatefulSet は、ステートフル アプリケーション向けのコンテナ オーケストレーション メソッドです。基本的な考え方は、Pod に特定の番号名を付けて、Pod が不変の一意のネットワーク識別コードを持つようにすることです。この場合、仮想 VIP ではなく特定の識別子を介して Pod 自体に直接アクセスする必要があるため、CluserIP ロード バランシングを使用して Pod にアクセスする方法は明らかに実行可能ではありません。 この時点で、実際に DNS を使用できます。各 Pod には、podIP を指す A レコード pod-name.service-name.namespace-name.svc.cluster.local が存在します。この A レコードを通じて Pod に直接アクセスできます。 対応する StatefulSet と Service を記述して確認してみましょう。
上記のように、StatefulSet は、spec.serviceName という追加フィールドを除いて、デプロイメントと変わりません。このフィールドの機能は、StatefulSet コントローラーに、ロジック処理中にホスト名サービスを使用して Pod の一意の解決可能性を確保するように指示することです。 Apply を実行すると、しばらくすると対応する Pod が生成されることがわかります。
予想どおり、Pod 名は重複することなく増分番号が付けられ、これらの Pod の作成プロセスも番号に従って連続して実行されます。デプロイメントを使用してデプロイされた Pod の名前には、レプリカセット名と乱数が追加され、再起動後も変更され続けることがわかります。 StatefulSet を使用してデプロイされた Pod の場合、podIP は変更されますが、名前は変更されません。これに基づいて、固定の DNS A レコードを介して各ポッドにアクセスできます。 それでは、Pod の A レコードを見てみましょう。
前の推論と一致して、pod-name.service-name.namespace-name.svc.cluster.local の A レコードを通じて podIP にアクセスできます。同じ名前空間では、pod-name.service-name に簡略化できます。 現時点でのサービスのAレコードとは何ですか?
これはエンドポイント リスト内の podIP のセットであることが判明しており、A レコード service-name.namespace-name.svc.cluster.local を介して負荷分散された方法でバックエンド Pod にアクセスできることを意味します。 iptablesKubernetes のサービスが kube-proxy と iptables に基づいて動作することは、多かれ少なかれわかっています。サービスが作成されると、kube-proxy によって認識され、ホスト上に対応する iptables ルールが作成されます。 CluserIP モードのサービスを例にとると、最初にエントリとして KUBE-SERVICES ルールが作成されます。
このレコードは、CluserIP 10.212.8.127 のすべての宛先アドレスが処理のために KUBE-SVC iptables チェーンにリダイレクトされることを意味します。 それでは、KUBE-SVC チェーンとは何かを見てみましょう。
このルールセットは、実際には負荷分散に使用されます。確率はそれぞれ 1/3、1/2、1 であることがわかります。 iptables ルールは上から下に照合されるため、これらの値を設定すると、各チェーンが同じ確率で一致するようになります。負荷分散ロジックを処理した後、リクエストは他の 3 つのルールに転送されます。見てみましょう:
KUBE-SEP チェーンは 3 つの DNAT ルールで構成されており、DNAT の前に 0x00004000 のフラグが設定されていることがわかります。 DNAT ルールは、PREROUTING の前、つまりルーティングの前に、リクエストの宛先アドレスとポートを --to-destination で指定された podIP とポートに変更することです。このようにして、CluserIP 10.212.8.127 にアクセスするための最初のリクエストは、各 Pod に負荷分散されます。 では、Pod が再起動され、podIP が変更された場合はどうなるでしょうか?当然のことながら、kube-proxy は Pod の変更を監視し、iptables ルールを更新および維持する役割を担います。 ヘッドレス サービスの場合、固定の A レコードを介して Pod に直接アクセスするため、これらの iptables ルールは当然必要ありません。 iptables は比較的理解しやすいですが、パフォーマンスはあまり良くありません。ご想像のとおり、Pod が多数ある場合、何千もの iptables ルールが作成され、絶えず更新されるため、ホスト マシン上の CPU リソースが大量に占有されます。効果的な解決策は、IPVS モードに基づくサービスを使用することです。 IPVS では、各 Pod に iptables ルールを設定する必要はなく、これらのルールをカーネル状態に配置するため、これらのルールを維持するコストが大幅に削減されます。 クラスター間通信サービスへの外部アクセス上記では、主に kube-dns によって生成された DNS レコードと kube-proxy によって管理される iptables ルールに基づいて、Kubernetes クラスター内でリクエストがどのように通信されるかについて説明しました。この情報はすべてクラスター内で利用できるため、クラスターの外部から特定のサービスまたはポッドにアクセスすることはできません。 デフォルトの CluserIP モードに加えて、Service では、この問題を解決するために使用される nodePort モードなど、他の多くのモードも提供されます。
NodePort モードで Service を作成し、NodePort を 8477 に設定しました。つまり、任意のホスト マシンのポート 8477 を介してホスト名 Service にアクセスできます。
アクセスするノード アドレスをランダムに見つけ、同じ戻り値を取得しました。 では、現時点で iptables ルールはどのように機能するのでしょうか。
kube-proxy は各ホストで上記の iptables ルールを生成し、--dport を通じてポートを指定します。ポートへのアクセス要求は KUBE-SVC チェーンにジャンプします。 KUBE-SVC チェーンには、以前の CluserIP サービスと同じレシピがあります。残りは CluserIP サービスにアクセスする場合と変わりません。 ただし、リクエストが現在のホストから別のノードに送信されると、そのノードに対して SNAT 操作が実行されることに注意してください。
このポストルーティング ルールは、ホストから送信されようとしている要求に対して SNAT を実行していることがわかります。判定条件は前回の DNAT でのフラグである 0x4000 フラグを持っていることです。通常のリクエストではなく、サービスから転送されたリクエストであると判断されます。 SNAT の理由は非常に単純です。まず、これは Kubernetes によって処理されない外部リクエストです。ノード 1 にアクセスすると、ノード 1 の負荷分散によってノード 2 の Pod に転送されます。これは大丈夫です。処理後、Pod はそれを外部クライアントに直接返します。この場合、外部クライアントは明らかに node1 にアクセスしているものの、返される応答は実際には node2 であるため、混乱します。このとき、エラーが報告されることが多いです。 SNAT の機能は DNAT の反対です。リクエストがノード 1 からノード 2 に送信されると、送信元アドレスはノード 1 のアドレスに変更されます。その後、node2 の Pod が戻ると、node1 に戻され、その後 node1 がクライアントに戻ります。
サービスには、外部からアクセスするための他の 2 つの方法があります。パブリック クラウドに適用可能な LoadBalancer モード サービスの場合、パブリック クラウド Kubernetes は CloudProvider を呼び出してパブリック クラウド上に負荷分散サービスを作成し、プロキシされた Pod の IP アドレスをバックエンドとして負荷分散サービスに構成します。もう 1 つは ExternalName モードで、spec.externalName で必要な外部アクセス ドメイン名 (hostnames.example.com など) を指定できます。その後、このドメイン名にアクセスすることは、service-name.namespace-name.svc.cluser.local にアクセスするのと同じになります。この時点で、kube-dns によって CNAME レコードが実際に追加されたことがわかります。 イングレスLoadBalancer という種類のサービスがありますが、各サービスに負荷分散サービスを構成すると、コストがかかり、無駄が多くなります。一般的に言えば、異なる URL へのアクセスを異なるサービスに転送するグローバル ロード バランサーが必要になります。これは、Service of Service とも言える Ingress の機能です。 Ingress は、実際にはリバース プロキシの抽象化です。皆さんもすでに、これが Nginx と非常に似ていると感じていると思います。実際、Ingress は抽象レイヤーであり、その実装レイヤーの 1 つは Nginx をサポートしています。 nginx イングレス コントローラーをデプロイできます。
Mandatory.yaml は、公式に管理されている Ingress コントローラーです。見てみましょう:
一般的に、nginx-ingress-controller イメージに基づいて Pod を定義しました。この Pod 自体は、Ingress オブジェクトとそのプロキシ バックエンド サービスの変更を監視するコントローラーです。 Ingress オブジェクトが作成されると、nginx-ingress-controller は Ingress オブジェクトの内容に基づいて Nginx 構成ファイル (nginx.conf) を生成し、それに応じて Nginx サービスを開始します。 Ingress オブジェクトが更新されると、nginx-ingress-controller はこの構成ファイルを更新します。 nginx-ingress-controller は、Nginx Lua ソリューションを通じて nginx アップストリームの動的な構成も実装します。 外部からこの Nginx にアクセスできるようにするには、Nginx を公開するサービスを作成する必要があります。
ここでのコンテンツは、NodePort タイプのサービスについて説明します。
このサービスは Nginx Pod の 80/443 ポートのみを公開していることがわかります。その後、ホスト IP と NodePort を介して Nginx にアクセスできるようになります。 次に、Ingress オブジェクトが一般的にどのように記述されるかを見てみましょう。例を挙げてみましょう。
この Ingress は、全体的なドメイン名が cafe.example.com であり、cafe.example.com/tea を介して tea-svc サービスにアクセスし、cafe.example.com/coffee を介して coffee-svc サービスにアクセスしたいことを示しています。ここでは、キー フィールド spec.rules を使用して転送ルールを記述します。 Ingress オブジェクトの詳細情報を表示できます。
先ほど、NodePort を介して nginx-ingress を公開したことを述べましたが、Ingress 構成では、cafe.example.com を介してバックエンド Pod にアクセスしたいと考えています。したがって、まず cafe.example.com ドメイン名が任意のホスト マシンの IP:nodePort を指す必要があり、リクエストが nginx-ingress に到達した後、各バックエンド サービスに転送されます。もちろん、NodePort 以外にも LoadBalancer、hostNetwork など、nginx-ingress を公開する方法はたくさんあります。 最後にもう一度リクエストを試してみましょう:
Nginx Ingress コントローラーがリクエストを対応するバックエンド サービスに正常に転送したことがわかります。リクエストがどのイングレス ルールにも一致しない場合は、当然 404 が返されます。 これまで、Kubernetes のコンテナ ネットワークがサービス検出を実装する方法について説明しました。サービス検出は、マイクロサービス アーキテクチャにおける中心的な問題です。この問題が解決されれば、Kubernetes を使用してマイクロサービス アーキテクチャを実装することが半分達成されたことになります。 |
<<: マイクロサービス CI/CD 実践 - GitOps の完全な設計と実装
>>: PythonでSaga分散トランザクションを簡単に完了する
最適化担当者が最も関心を持っているのは、検索エンジンのテクノロジーと動向であり、検索エンジンのランキ...
なぜ一部のウェブサイトにはBaidu Knowsページを含むBaidu関連のドメインがあるのに、Ba...
2015年のCCTV 315 Galaで、CCTVは無料WiFiの危険性を暴露しました。ユーザーが携...
月給5,000~50,000のこれらのプロジェクトはあなたの将来です熊張豪は、百度が2017年末に開...
通常、SEO 最適化とは、ウェブサイトのランキングを上げ、ユーザーの検索を満足させることだと考えられ...
ショートビデオ、セルフメディア、インフルエンサーのためのワンストップサービス高品質なウェブサイトを構...
Baidu ウェイトは、Aizhan.com や Webmaster Tools などのサードパーテ...
クラウド ネイティブは、企業がクラウド テクノロジーを採用してデジタル変革を推進するための重要な原則...
諺にあるように、世の中に生きていれば、必ず傷つくことになります。著者は 2 年間の最適化経験を持って...
ウェブサイトの最適化担当者にとって、Baidu の新しい状況最適化にはいくつかの犠牲が伴います。 2...
インターネットの台頭とともに、SEO 業界が静かに誕生しました。多くの人は、SEO は比較的複雑な業...
arkecxはどうですか? arkecxクラウドサーバーはどうですか?今回は、英国ロンドンにあるar...
毎年恒例の天猫ダブルイレブンがもうすぐやってきます。諺にあるように、素人にはその興奮はわかるかもしれ...
過去6か月間、オーディオおよびショートビデオアプリケーションは熱い勢いを維持し、ツールアプリケーショ...
Baidu が Spark プロジェクトを立ち上げ、オリジナル コンテンツを積極的にサポートして以来...