Istio@サービスメッシュ系ミドルウェア¶
はじめに¶
本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。
01. Istioの仕組み¶
01-02 サイドカーモード¶
Istioのサイドカーモードとは¶
サイドカーモードは、サイドカープロキシ型のサービスメッシュを実装したものである。
各PodにサイドカーとしてEnvoyを稼働させ、これが各マイクロサービスのインフラ領域の責務をに担う。
01-03. アンビエントモード (サイドカーレスパターン)¶
アンビエントモードとは¶
アンビエントモードは、サイドカーレスパターンのサービスメッシュを実装したものである。
各Node上にエージェントとしてEnvoyを稼働させ、これが各マイクロサービスのインフラ領域の責務をに担う。
01-04. パターンの比較¶
項目 | サイドカーモード | アンビエントモード |
---|---|---|
Nodeのハードウェアリソース消費量 | × | ⭕️ |
Nodeのストレージ使用量 | ⭕️ | △ |
Envoyの冗長性 | ⭕️️ | △ |
アプリごとのEnvoyの設定カスタマイズ | ⭕️ | △ |
単純性 | × | ⭕️ |
Istioのアップグレード | インプレースアップグレード、カナリアアップグレード | DaemonSetのローリングアップデート |
02. トラフィック管理¶
パケット処理の仕組み¶
istio-proxy
コンテナにて、リスナーでリクエストを受信する。- EnvoyFilterがあれば、これをリスナーフィルターとしてEnvoyに適用する。
- ルートでリクエストを受け取る。
- クラスターでリクエストを受け取る。
- クラスター配下のエンドポイントにリクエストをプロキシする。
サービスメッシュ内ではkube-proxyは不要¶
実は、サービスメッシュ内のPod間通信では、kube-proxyは使用しない。
istio-init
コンテナは、istio-iptables
コマンドを実行し、iptablesのルールを書き換える。
これにより、送信元Podから宛先Podに直接通信できるようになる。
02-02. サービスメッシュ外へのリクエスト送信¶
安全な通信方式¶
▼ 任意の外部システムに送信できるようにする¶
サービスメッシュ内のマイクロサービスから、istio-proxy
コンテナ (マイクロサービスのサイドカーとIstio EgressGatewayの両方) を経由して、任意の外部システムにリクエストを送信できるようにする。
外部システムは識別できない。
▼ 登録した外部システムに送信できるようにする¶
サービスメッシュ内のマイクロサービスから、istio-proxy
コンテナ (マイクロサービスのサイドカーとIstio EgressGatewayの両方) を経由して、ServiceEntryで登録した外部システムにリクエストを送信できるようにする。
外部システムを識別できる。
安全ではない通信方式¶
▼ 登録した外部システムに送信できるようにする¶
サービスメッシュ内のマイクロサービスから、istio-proxy
コンテナ (マイクロサービスのサイドカーのみ) を経由して、任意の外部システムにリクエストを送信できるようにする。
外部システムは識別できない。
▼ istio-proxy
コンテナを経由せずに送信できるようにする¶
サービスメッシュ内のマイクロサービスから、istio-proxy
コンテナを経由せずに、外部システムにリクエストを送信できるようにする。
外部システムの種類¶
▼ PassthroughCluster
¶
IPアドレスを指定した送信できる宛先のこと。
Istio v1.3
以降で、デフォルトで全てのサービスメッシュ外へのリクエストのポリシーがALLOW_ANY
となり、PassthroughCluster
として扱うようになった。
サービスメッシュ外にDBを配置する場合、メッシュ内のアプリからDBへ通信ではDBのエンドポイントを指定することになる。
そのため、サービスメッシュ外へのリクエストはPassthroughCluster
に属する。
注意点として、REGISTRY_ONLY
モードを有効化すると、ServiceEntryで登録された宛先以外へのサービスメッシュ外への全通信がBlackHoleCluster
になってしまう
▼ BlackHoleCluster
¶
IPアドレスを指定して送信できない宛先のこと。
基本的に、サービスメッシュ外へのリクエストは失敗し、502
ステータスになる (502 Bad Gateway
)。
03. 復旧性の管理¶
フォールトインジェクション¶
▼ フォールトインジェクションとは¶
ランダムな障害を意図的にインジェクションし、サービスメッシュの動作を検証する。
▼ テストの種類¶
テスト名 | 内容 |
---|---|
Delayインジェクション | アプリコンテナに対するインバウンド通信にて、意図的に通信の遅延を発生させる。 ・https://istio.io/latest/docs/tasks/traffic-management/fault-injection/#injecting-an-http-delay-fault |
Abortインジェクション | アプリコンテナに対するインバウンド通信にて、意図的に通信の中止を発生させる。 ・https://istio.io/latest/docs/tasks/traffic-management/fault-injection/#injecting-an-http-abort-fault |
サーキットブレイカー¶
istio-proxyコンテナでサーキットブレイカーを実現する。
なお、アプリケーションで同様の実装をしても良い。
04. 通信の認証/認可¶
通信の認証¶
▼ 仕組み¶
Pod間通信時に、正しい送信元Envoyの通信であることを認証する。
▼ 相互TLS認証¶
相互TLS認証を実施し、送信元のPodの通信を認証する。
▼ JWTによるBearer認証 (IDプロバイダーに認証フェーズを委譲)¶
JWTによるBearer認証を実施し、送信元のPodの通信を認証する。
この場合、認証フェーズをIDプロバイダー (例:Auth0、GitHub、Keycloak、Zitadel、AWS Cognito、Google Cloud Auth) に委譲することになる。
JWTの取得方法として、例えば以下の方法がある。
- 送信元のPodがIDプロバイダーからJWTを直接取得する。
- 送信元/宛先の間に認証プロキシ (例:OAuth2 Proxy、Dexなど) を配置し、認証プロキシでIDプロバイダーからJWTを取得する。
▼ アプリの認証について¶
アプリ側の認証については、Istioの管理外である。
通信の認可¶
▼ 仕組み¶
Pod間通信時に、AuthorizationPolicyを使用して、スコープに含まれる認証済みEnvoyの通信のみを認可する。
▼ 通信の認可の委譲¶
AuthorizationPolicyでIDプロバイダー (例:Auth0、GitHub、Keycloak、Zitadel、AWS Cognito、Google Cloud Auth) を指定し、認可フェーズを委譲できる。
▼ アプリの認可について¶
アプリ側の認可については、Istioの管理外である。
05. アプリケーションデータの暗号化¶
相互TLS認証¶
▼ 相互TLS認証とは¶
相互TLS認証を実施し、L7
のアプリケーションデータを暗号化/復号化する。
暗号スイート¶
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_AES_128_GCM_SHA256
▼ TLSタイムアウト¶
アウトバウンド時、istio-proxy
コンテナは宛先にHTTPSリクエストを送信する。
この時、実際はタイムアウトであっても、TLS handshake timeout
というエラーなってしまう。
クライアント証明書 / SSL証明書発行¶
▼ Istiodコントロールプレーン (discovery
コンテナ) をルート認証局として使用する場合¶
デフォルトでは、Istiodコントロールプレーンがルート認証局として働く。
クライアント証明書 / SSL証明書を提供しつつ、これを定期的に自動更新する。
- Istiodコントロールプレーンは、
istio-ca-secret
(Secret) を自己署名する。 - Istiodコントロールプレーンは、
istio-proxy
コンテナから送信された秘密鍵と証明書署名要求で署名されたクライアント証明書 / SSL証明書を作成する。特に設定しなければ、istio-proxy
コンテナのpilot-agentプロセスが、秘密鍵と証明書署名要求を自動で作成してくれる。 istio-proxy
コンテナからのリクエストに応じて、IstiodのSDS-APIがクライアント証明書 / SSL証明書をistio-proxy
コンテナに配布する。- Istiodコントロールプレーンは、CA証明書を持つ
istio-ca-root-cert
(ConfigMap) を自動的に作成する。これは、istio-proxy
コンテナにマウントされ、証明書を検証するために使用する。 istio-proxy
コンテナ間で相互TLS認証できるようになる。- 証明書が失効すると、
istio-proxy
コンテナの証明書が自動的に差し代わる。Podの再起動は不要である。
- https://istio.io/latest/docs/concepts/security/#pki
- https://developers.redhat.com/articles/2023/08/24/integrate-openshift-service-mesh-cert-manager-and-vault#default_and_pluggable_ca_scenario
- https://www.reddit.com/r/istio/comments/x1l1sm/if_istio_caroot_certificate_expires_do_you_need/
- https://zufardhiyaulhaq.com/Replacing-Istio-CA-certificate/
- https://training.linuxfoundation.cn/news/407
▼ 外部ツールをルート認証局として使用する場合¶
Istiodコントロールプレーン (discovery
コンテナ) を中間認証局として使用し、ルート認証局をIstio以外 (例:HashiCorp Vaultなど) に委譲できる。
外部のルート認証局は、istio-proxy
コンテナから送信された秘密鍵と証明書署名要求で署名されたSSL証明書を作成する。
06. テレメトリーの作成¶
他のOSSとの連携¶
Istio上のEnvoyは、テレメトリーを作成する。
各監視ツールは、プル型 (ツールがIstiodから収集) やプッシュ型 (Istiodがツールに送信) でこのテレメトリーを収集する。
06-02. メトリクス¶
メトリクスの作成と送信¶
Istio上のEnvoyはメトリクスを作成し、Istiodコントロールプレーン (discovery
コンテナ) に送信する。
Prometheusは、discovery
コンテナの/stats/prometheus
エンドポイント (15090
番ポート) からメトリクスのデータポイントを収集する。
なお、istio-proxy
コンテナにも/stats/prometheus
エンドポイントはある。
セットアップ¶
▼ Prometheusの設定ファイル¶
Prometheusの設定ファイルとして定義することもできる。
scrape_configs:
# Istiodの監視
- job_name: istiod
kubernetes_sd_configs:
- role: endpoints
namespaces:
names:
- istio-system
relabel_configs:
- source_labels:
- __meta_kubernetes_service_name
- __meta_kubernetes_endpoint_port_name
action: keep
regex: istiod;http-monitoring
# istio-proxyの監視
- job_name: istio-proxy
metrics_path: /stats/prometheus
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels:
- __meta_kubernetes_pod_container_port_name
action: keep
regex: .*-envoy-prom
▼ カスタムリソースの場合¶
Prometheusがdiscovery
コンテナからデータポイントを取得するためには、discovery
コンテナのPodを監視するためのServiceMonitorが必要である。
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: istiod-service-monitor
namespace: istio-system
spec:
jobLabel: istio
targetLabels:
- app
selector:
matchExpressions:
- key: istio
operator: In
values:
- pilot
namespaceSelector:
matchNames:
- istio-system
endpoints:
- port: http-monitoring
interval: 15s
また、istio-proxy
コンテナの監視には、PodMonitorが必要である。
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: istio-proxy-service-monitor
namespace: istio-system
spec:
selector:
matchExpressions:
- key: istio-prometheus-ignore
operator: DoesNotExist
namespaceSelector:
# istio-proxyをインジェクションしているNamespaceを網羅できるようにする
any: true
jobLabel: envoy-stats
podMetricsEndpoints:
# istio-proxyコンテナが公開しているメトリクス収集用のエンドポイントを指定する
- path: /stats/prometheus
interval: 15s
relabelings:
- action: keep
sourceLabels:
- __meta_kubernetes_pod_container_name
regex: "istio-proxy"
- action: keep
sourceLabels:
- __meta_kubernetes_pod_annotationpresent_prometheus_io_scrape
- action: replace
regex: (\d+);(([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})
replacement: "[$2]:$1"
sourceLabels:
- __meta_kubernetes_pod_annotation_prometheus_io_port
- __meta_kubernetes_pod_ip
targetLabel: __address__
- action: replace
regex: (\d+);((([0-9]+?)(\.|$)){4})
replacement: $2:$1
sourceLabels:
- __meta_kubernetes_pod_annotation_prometheus_io_port
- __meta_kubernetes_pod_ip
targetLabel: __address__
- action: labeldrop
regex: "__meta_kubernetes_pod_label_(.+)"
- sourceLabels:
- __meta_kubernetes_namespace
action: replace
targetLabel: namespace
- sourceLabels:
- __meta_kubernetes_pod_name
action: replace
targetLabel: pod_name
- https://github.com/istio/istio/blob/1.19.3/samples/addons/extras/prometheus-operator.yaml
- https://discuss.istio.io/t/scraping-istio-metrics-from-prometheus-operator-e-g-using-servicemonitor/10632
- https://speakerdeck.com/ido_kara_deru/constructing-and-operating-the-observability-platform-using-istio?slide=23
メトリクスの種類¶
▼ Istiod全体に関するメトリクス¶
メトリクス名 | 単位 | 説明 |
---|---|---|
istio_build |
カウント | Istioの各コンポーネントの情報を表す。istio_build{component="pilot"} とすることで、Istiodコントロールプレーンの情報を取得できる。 |
▼ istio-proxy
コンテナに関するメトリクス¶
Prometheus上でメトリクスをクエリすると、Istiodコントロールプレーン (discovery
コンテナ) から収集したデータポイントを取得できる。
メトリクス名 | 単位 | 説明 |
---|---|---|
istio_requests_total |
カウント | istio-proxy コンテナが受信した総リクエスト数を表す。メトリクスの名前空間に対してさまざまなディメンションを設定できる。・https://blog.christianposta.com/understanding-istio-telemetry-v2/ |
istio_request_duration_milliseconds |
カウント | istio-proxy コンテナが受信したリクエストに関して、処理の所要時間を表す。 |
istio_request_messages_total |
カウント | istio-proxy コンテナが受信したgRPCによる総HTTPリクエスト数を表す。 |
istio_response_messages_total |
カウント | istio-proxy コンテナが受信した総gRPCレスポンス数を表す。 |
envoy_cluster_upstream_rq_retry |
カウント | istio-proxy コンテナの他のPodへのリクエストに関する再試行数を表す。 |
envoy_cluster_upstream_rq_retry_success |
カウント | istio-proxy コンテナが他のPodへのリクエストに関する再試行成功数を表す。 |
▼ メトリクスのラベル¶
メトリクスをフィルタリングできるように、Istioでは任意のメトリクスにデフォルトでラベルがついている。
ラベル | 説明 | 例 |
---|---|---|
connection_security_policy |
Pod値の通信方法を表す。 | mutual_tls (相互TLS認証) |
destination_app |
リクエストの宛先のコンテナ名を表す。 | foo-container |
destination_cluster |
リクエストの宛先のKubernetes Cluster名を表す。 | Kubernetes |
destination_service |
リクエストの宛先のService名を表す。 | foo-service |
destination_workload |
リクエストの宛先のDeployment名を表す。 | `foo-deployment |
destination_workload_namespace |
送信元のNamespace名を表す。 | |
reporter |
メトリクスの収集者を表す。istio-proxy コンテナかIngressGatewayのいずれかである。 |
・destination (istio-proxy コンテナ)・ source (IngressGateway) |
response_flags |
Envoyの%RESPONSE_FLAGS% 変数を表す。 |
- (値なし) |
response_code |
istio-proxy コンテナが返信したレスポンスコードの値を表す。 |
200 、404 、0 (クライアントが切断した場合) |
source_app |
送信元のコンテナ名を表す。 | foo-container |
source_cluster |
送信元のKubernetes Cluster名を表す。 | Kubernetes |
source_workload |
送信元のDeployment名を表す。 | foo-deployment |
06-03. ログ (アクセスログのみ)¶
ログの監視¶
▼ ログの出力¶
Istio上のEnvoyは、アプリコンテナへのアクセスログ (インバウンド通信とアウトバウンド通信の両方) を作成し、標準出力に出力する。
アクセスログにデフォルトで役立つ値が出力される。
ログ収集ツール (例:FluentBit、Fluentdなど) をDaemonSetパターンやサイドカーモードで配置し、NodeやPod内コンテナの標準出力に出力されたログを監視バックエンドに送信できるようにする必要がある。
# istio-proxyコンテナのアクセスログ
{
# 相互TLSの場合の宛先コンテナ名
"authority": "foo-downstream:<ポート番号>",
"bytes_received": 158,
"bytes_sent": 224,
"connection_termination_details": null,
"downstream_local_address": "*.*.*.*:50010",
"downstream_remote_address": "*.*.*.*:50011",
# ダウンストリームからアップストリームへリクエストをプロキシし、レスポンスを処理し終えるまでにかかった時間
# ダウンストリーム側で設定したタイムアウトになった場合は、Envoyはその時間の直前にプロキシをやめるため、Durationはタイムアウトとおおよそ同じになる
"duration": 12,
"method": null,
"path": null,
"protocol": null,
"request_id": null,
"requested_server_name": null,
# アップストリームからのレスポンスのステータスコード
"response_code": 200,
"response_code_details": null,
# ステータスコードの補足情報
"response_flags": "-",
"route_name": null,
"start_time": "2023-04-12T06:11:46.996Z",
"upstream_cluster": "outbound|50000||foo-pod.foo-namespace.svc.cluster.local",
"upstream_host": "*.*.*.*:50000",
"upstream_local_address": "*.*.*.*:50001",
"upstream_service_time": null,
"upstream_transport_failure_reason": null,
"user_agent": null,
"x_forwarded_for": null,
}
▼ ログの送信¶
Istio上のEnvoyは、アクセスログをログ収集ツール (例:OpenTelemetry Collector) に送信する。
06-04. 分散トレース¶
分散トレースの監視¶
▼ スパンの作成¶
Istio上のEnvoyは、スパンを作成する。
スパンの作成場所としては、いくつか種類がある。
istio-proxy |
アプリ |
---|---|
✅ | |
✅ | ✅ |
✅ |
スパンの作成場所が多いほど、各コンテナの処理時間が細分化された分散トレースを収集できる。
アプリコンテナ間でスパンが持つコンテキストを伝播しないため、コンテキストを伝播させる実装が必要になる。
▼ スパンの送信¶
Istio上のEnvoyは、スパンを分散トレース収集ツール (例:Jaeger Collector、OpenTelemetry Collectorなど) に送信する。
Envoyでは宛先としてサポートしていても、Istio上のEnvoyでは使用できない場合がある。(例:X-Rayデーモン)
- https://istio.io/latest/docs/tasks/observability/distributed-tracing/overview/
- https://github.com/istio/istio/blob/1.14.3/samples/bookinfo/src/productpage/productpage.py#L180-L237
- https://github.com/istio/istio/blob/1.14.3/samples/bookinfo/src/details/details.rb#L130-L187
- https://github.com/istio/istio/issues/36599