つまり、私たちは1年間Istioを使用しています。 彼はその後去った。 Kubernetesクラスターのパフォーマンスが大幅に低下しました。分散トレースが必要なため、IstioにJaegerを実行させて理解しました。 サービスメッシュはインフラストラクチャに非常によく適合しているため、このツールに投資することにしました。
私は苦しむ必要がありましたが、私たちはそれを広く研究しました。 これはシリーズの最初の投稿で、IstioがKubernetesとどのように統合されるか、およびその作業について学んだことを説明します。 時には技術的な荒野にさまよいますが、それほど遠くはありません。 さらに、より多くの投稿があります。
Istioとは何ですか?
Istioは、サービスメッシュ構成ツールです。 Kubernetesクラスターの状態を読み取り、Kubernetesポッドにサイドカーとして実装されているL7プロキシ(HTTPおよびgRPC)を更新します。 これらのサイドカーは、Istio Pilot API(およびgRPCサービス)から構成を読み取り、トラフィックをルーティングするEnvoyコンテナーです。 強力なL7プロキシを内部で使用することで、メトリック、トレース、再試行ロジック、サーキットブレーカー、負荷分散、カナリア展開を使用できます。
最初から始めましょう:Kubernetes
Kubernetesでは、deployまたはStatefulSetを使用してunderを作成します。 または、高レベルのコントローラーなしで単に「バニラ」になることもあります。 その後、Kubernetesは、目的の状態を維持するために最善を尽くします。ノード上のクラスターにポッドを作成し、それらの起動と再起動を確認します。 アンダーが作成されると、KubernetesはAPIライフサイクルを実行し、各ステップが成功することを確認してから、最終的にクラスター上にアンダーを作成します。
APIライフサイクルステージ:
手順の1つは、入場Webhookを変更することです。 これはKubernetesのライフサイクルの別の部分であり、Kubernetes構成の真実のソースであるetcdリポジトリにコミットする前にリソースがカスタマイズされます。 そして、ここでイスティオは彼の魔法をかけます。
入場ウェブフックの変更
サブルーチンが( kubectl
またはDeployment
を介して)作成されると、このライフサイクルを経て、Webhookを変更するアクセスが大きな世界にリリースする前にそれを変更します。
Istioのインストール中に、webhookを変更するための構成リソースとしてistio-sidecar-injectorが追加されます。
$ kubectl get mutatingwebhookconfiguration NAME AGE istio-sidecar-injector 87d
そして構成:
apiVersion: admissionregistration.k8s.io/v1beta1 kind: MutatingWebhookConfiguration metadata: labels: app: istio-sidecar-injector chart: sidecarInjectorWebhook-1.0.4 heritage: Tiller name: istio-sidecar-injector webhooks: - clientConfig: caBundle: redacted service: name: istio-sidecar-injector namespace: istio-system path: /inject failurePolicy: Fail name: sidecar-injector.istio.io namespaceSelector: matchLabels: istio-injection: enabled rules: - apiGroups: - "" apiVersions: - v1 operations: - CREATE resources: - pods
名前空間にistio-injection=enabled
がある場合、Kubernetesはすべての炉床作成イベントをistio-system
名前空間のistio-system
istio-sidecar-injector
に送信する必要があると述べています。 インジェクターには、PodSpecにさらに2つのコンテナーが含まれます。1つはプロキシルールの設定用、もう1つはそれ自体のプロキシ用です。 サイドカーインジェクターは、 istio-sidecar-injector
構成マップのテンプレートに従ってこれらのコンテナーを挿入します。 このプロセスは、サイドケアとも呼ばれます。
サイドカーポッド
サイドカーは私たちの魔術師イスティオのトリックです。 Istioはすべてを非常に巧妙にクランキングするので、詳細がわからなければ外部からは魔法にすぎません。 また、ネットワーク要求を突然デバッグする必要がある場合は、それらを知っていると役立ちます。
初期化コンテナとプロキシコンテナ
Kubernetesには、メインのコンテナの前に実行できる一時的な一時コンテナがあります。 リソースをプールしたり、データベースを移行したり、Istioの場合のようにネットワークルールを構成したりします。
IstioはEnvoyを使用して、目的のルートに沿ってすべてのリクエストを送信します。 これを行うために、Istioはiptables
ルールを作成し、着信および発信トラフィックをEnvoyに直接送信し、トラフィックを宛先に適切にプロキシします。 トラフィックは少し迂回しますが、トレース、クエリメトリック、およびポリシーの適用は分散されています。 このファイルでは、Istioリポジトリから、Istioがiptablesルールを作成する方法を確認できます。
@jimmysongioは、iptablesルールとEnvoyプロキシの間の優れた接続図を描きました。
Envoyはすべての着信および発信トラフィックを受信するため、図のように、すべてのトラフィックは通常Envoy内を移動します。 Istioプロキシは、Istioサイドカーインジェクターによって変更されるすべてのポッドに追加される別のコンテナーです。 このコンテナで、Envoyプロセスが開始され、ハースからのすべてのトラフィックを受信します(Kubernetesクラスターからのトラフィックなど、いくつかの例外があります)。
Envoyプロセスは、Istioを実装するEnvoy v2 APIを介してすべてのルートを検出します。
特使
Envoy自体には、クラスター内のポッドとサービスを検出するロジックがありません。 これはデータプレーンであり、ガイドするにはコントロールプレーンが必要です。 Envoy構成パラメーターは、gRPC APIを介してこの構成を取得するためにホストまたはサービスポートを要求します。 Istioは、パイロットサービスを通じて、gRPC APIの要件を満たしています。 Envoyは、変更するWebhookによって実装されたサイドカー設定に基づいてこのAPIに接続します。 APIには、Envoyがクラスターを検出してルーティングするために必要なすべてのトラフィックルールがあります。 これがサービスメッシュです。
パイロットはKubernetesクラスターに接続し、クラスターステータスを読み取り、更新を待ちます。 Kubernetesクラスター内のポッド、サービス、およびエンドポイントを監視し、パイロットに接続されているすべてのEnvoyサイドカーに適切な構成を提供します。 これはKubernetesとEnvoyの間の橋です。
ポッド、サービス、またはエンドポイントがKubernetesで作成または更新されると、Pilotはそれについて学習し、接続されているすべてのEnvoyインスタンスに必要な構成を送信します。
どの構成が送信されていますか?
EnvoyはIstio Pilotからどのような構成を取得しますか?
デフォルトでは、Kubernetesはendpoint
を管理するサービス(サービス)でネットワークの問題を解決しendpoint
。 エンドポイントのリストは次のコマンドで開くことができます:
kubectl get endpoints
これは、クラスター内のすべてのIPおよびポートとそのアドレスのリストです(通常、これらはデプロイメントから作成されたポッドです)。 Istioは、ルートデータをセットアップしてEnvoyに送信するために知っておくことが重要です。
サービス、リスナー、およびルート
Kubernetesクラスターでサービスを作成するとき、適切なすべてのポッドを選択するショートカットを含めます。 サービスのIPにトラフィックを送信すると、Kubernetesはこのトラフィックのトラフィックを選択します。 たとえば、コマンド
curl my-service.default.svc.cluster.local:3000
最初に、 default
ネームスペースでmy-service
に割り当てられた仮想IPを見つけ、このIPはサービスラベルに一致するサブにトラフィックを転送します。
IstioとEnvoyは、この論理をわずかに変更します。 IstioはKubernetesクラスターのサービスとエンドポイントに基づいてEnvoyを構成し、Envoyのスマートルーティングおよび負荷分散機能を使用してKubernetesサービスをバイパスします。 1つのIPを介してプロキシする代わりに、EnvoyはIP囲炉裏に直接接続します。 これを行うために、IstioはKubernetes構成をEnvoy構成にマップします 。
Kubernetes、Istio、Envoyという用語はわずかに異なっており、彼らが何を食べているのかすぐにはわかりません。
サービス
Kubernetesのサービスは、Envoyのクラスターにマップします 。 Envoyクラスターには、 エンドポイントのリスト、つまりリクエストを処理するためのインスタンスのIP(またはホスト名)が含まれています。 Istioサイドカーで構成されているクラスターのリストを表示するには、 istioctl proxy-config cluster < >
ます。 このコマンドは、囲炉裏に関して現状を表示します。 以下に、環境の1つの例を示します。
$ istioctl proxy-config cluster taxparams-6777cf899c-wwhr7 -n applications SERVICE FQDN PORT SUBSET DIRECTION TYPE BlackHoleCluster - - - STATIC accounts-grpc-gw.applications.svc.cluster.local 80 - outbound EDS accounts-grpc-public.applications.svc.cluster.local 50051 - outbound EDS addressvalidator.applications.svc.cluster.local 50051 - outbound EDS
すべての同じサービスがこの名前空間にあります。
$ kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) accounts-grpc-gw ClusterIP 10.3.0.91 <none> 80/TCP accounts-grpc-public ClusterIP 10.3.0.202 <none> 50051/TCP addressvalidator ClusterIP 10.3.0.56 <none> 50051/TCP
Istioはどのプロトコルがサービスを使用しているかをどのように知るのですか? ポートエントリのname
フィールドによってサービスマニフェストのプロトコルを構成します。
$ kubectl get service accounts-grpc-public -o yaml apiVersion: v1 kind: Service metadata: name: accounts-grpc-public spec: ports: - name: grpc port: 50051 protocol: TCP targetPort: 50051
grpc
またはgrpc-
プレフィックスがある場合、IstioはサービスのHTTP2プロトコルを構成します。 httpまたはgrpcプレフィックスを指定しなかったためにプロキシ設定が破損した場合、Istioがポート名をどのように使用するかを苦い経験から学びました...
Envoyでkubectlと管理ポート転送ページを使用すると、account-grpc-publicエンドポイントがHTTP2プロトコルを使用するEnvoyのクラスターとしてPilotによって実装されていることがわかります。 これにより、前提が確認されます。
$ kubectl -n applications port-forward otherpod-dc56885ff-dqc6t 15000:15000 & $ curl http://localhost:15000/config_dump | yq r - ... - cluster: circuit_breakers: thresholds: - {} connect_timeout: 1s eds_cluster_config: eds_config: ads: {} service_name: outbound|50051||accounts-grpc-public.applications.svc.cluster.local http2_protocol_options: max_concurrent_streams: 1073741824 name: outbound|50051||accounts-grpc-public.applications.svc.cluster.local type: EDS ...
ポート15000は、すべてのサイドカーで使用できるEnvoy管理ページです。
リスナー
リスナーはKubernetesエンドポイントを認識して、トラフィックを炉床に渡します。 アドレス検証サービスには、次のエンドポイントが1つあります。
$ kubectl get ep addressvalidator -o yaml apiVersion: v1 kind: Endpoints metadata: name: addressvalidator subsets: - addresses: - ip: 10.2.26.243 nodeName: ip-10-205-35-230.ec2.internal targetRef: kind: Pod name: addressvalidator-64885ccb76-87l4d namespace: applications ports: - name: grpc port: 50051 protocol: TCP
したがって、アドレス検証ハースのポート50051には1人のリスナーがいます。
$ kubectl -n applications port-forward addressvalidator-64885ccb76-87l4d 15000:15000 & $ curl http://localhost:15000/config_dump | yq r - ... dynamic_active_listeners: - version_info: 2019-01-13T18:39:43Z/651 listener: name: 10.2.26.243_50051 address: socket_address: address: 10.2.26.243 port_value: 50051 filter_chains: - filter_chain_match: transport_protocol: raw_buffer ...
ルート
Istioでは、標準のKubernetes Ingressオブジェクトの代わりに、より抽象的で効率的なカスタムリソース、 VirtualService
が使用VirtualService
ます。 VirtualServiceは、ルートをゲートウェイにバインドすることにより、ルートをアップストリームクラスターにマップします。 これは、イングレスコントローラーでKubernetes Ingressを使用する方法です。
つまり、すべての内部GRPCトラフィックにIstio Ingress-Gatewayを使用します。
apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: grpc-gateway spec: selector: istio: ingressgateway servers: - hosts: - '*' port: name: http2 number: 80 protocol: HTTP2 --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: grpc-gateway spec: gateways: - grpc-gateway hosts: - '*' http: - match: - uri: prefix: /namely.address_validator.AddressValidator retries: attempts: 3 perTryTimeout: 2s route: - destination: host: addressvalidator port: number: 50051
一見すると、この例では何も理解できません。 ここには表示されませんが、Istio-IngressGatewayデプロイメントは、 istio: ingressgateway
基づいてどのエンドポイントが必要かを記録します。 この例では、IngressGatewayはHTTP2を介してポート80を介してすべてのドメインのトラフィックをルーティングします。 VirtualServiceは、このゲートウェイのルートを実装し、 /namely.address_validator.AddressValidator
プレフィックスと一致し、2秒後にリトライルールを使用addressvalidator
、アドレス検証機能をポート50051経由でアップストリームサービスに渡します。
Istio-IngressGatewayポッドポートをリダイレクトし、Envoyの構成を確認すると、VirtualServiceの機能がわかります。
$ kubectl -n istio-system port-forward istio-ingressgateway-7477597868-rldb5 15000 ... - match: prefix: /namely.address_validator.AddressValidator route: cluster: outbound|50051||addressvalidator.applications.svc.cluster.local timeout: 0s retry_policy: retry_on: 5xx,connect-failure,refused-stream num_retries: 3 per_try_timeout: 2s max_grpc_timeout: 0s decorator: operation: addressvalidator.applications.svc.cluster.local:50051/namely.address_validator.AddressValidator* ...
Istioで掘りながらグーグルで調べたもの
エラー503または404が発生します
理由は異なりますが、通常は次のとおりです。
- サイドカーアプリケーションはPilotに接続できません(Pilotが実行されていることを確認してください)。
- Kubernetesサービスマニフェストに無効なプロトコルが含まれています。
- VirtualService / Envoy構成は、ルートを誤ったアップストリームクラスターに書き込みます。 着信トラフィックが予想されるエッジサービスから開始し、Envoyログを調べます。 または、Jaegerなどを使用してエラーを見つけます。
IstioプロキシログでのNR / UH / UFの意味
- NR-ルートなし。
- UH-アップストリーム異常(アップストリームが動作不能)。
- UF-アップストリーム障害(アップストリーム障害)。
Istioの高可用性について
- NodeAffinityをIstioコンポーネントに追加して、異なるアベイラビリティゾーンにハースを均等に分散し、レプリカの最小数を増やします。
- 水平ポッドの自動スケーリング機能を備えたKubernetesの新しいバージョンを起動します。 最も重要な炉床は、負荷に基づいて拡張されます。
cronジョブが終了しないのはなぜですか?
メインのワークロードが完了すると、サイドカーコンテナーは動作し続けます。 この問題を回避するには、 sidecar.istio.io/inject: “false”
という注釈を追加して、cronジョブでサイドカーを無効にします。
Istioのインストール方法は?
展開にはSpinnakerを使用しますが、通常は最新のHelmチャートを取得し、それらをkubectl apply -f -
せ、 helm template -f values.yml
を使用し、Githubでファイルをコミットして、変更を確認してからkubectl apply -f -
。 これは、異なるバージョンのCRDまたはAPIを誤って変更しないようにするためです。
この投稿の執筆を手伝ってくれたBobby TablesとMichael Hamrahに感謝します。