6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

HUITAdvent Calendar 2023

Day 14

IstioのEnvoyへの中継方法を理解したい

Posted at

Istioのiptablesを理解したい

HUIT Advent Calendar 2023の14日目の記事です。
Istioを触ってて気になったことを書き残していきます。

初めに

IstioのEnvoyをサイドカーとして挿入する構造はわかりやすいですが、 目的地のアドレスを入力するだけで自動的にEnvoyを通す仕組みが気になり調べてみました。

Version

Istio: 1.20.1

Istioとは

雑に説明すると、Kubernetesで扱えるサービスメッシュ実装の1つ。
ここら辺はわかりやすい記事が沢山あるので貼っておきます。

新卒でもわかる!Istioとは? | SIOS Tech. Lab

Istioの構造

大まかにコントロールプレーンとデータプレーンの2つに分かれています。
コントロールプレーンではポリシーやプロキシ設定の管理を。
データプレーンでは各PodにEnvoyをプロキシーとして配置、サービス間の通信を制御する構成です。

Istio Image

全ての通信をEnvoyに通すために

アプリケーションからはProxyの存在を意識することなく、目的地のアドレスを指定して通信することができます。
ここで、その状態でProxyを通すにはどうしているのか気になりました。

調べてみると、Istioではサービスからの通信を、iptablesを用いて制御しているらしいです。
これはPod毎に指定されており、INPUT, OUTPUTそれぞれにおいてEnvoyに一度リダイレクトするように指定されています。

iptablesの設定を確認する

iptablesの設定を見ていきたいです。
手元のkindで簡単なnginxサーバーを構築してIstioをインストールしてみました。

Pod内のコンテナはネットワーク名前空間を共有しているので、iptablesやport,deviceなどは共有されているみたいです。(初めはコンテナが2つあるので、iptablesが別々に設定されるものかと思ってた)

下の実行結果から、nginxとenvoyのプロセスが同一のネットワーク名前空間に属していることがわかります。

network namespace
# docker execでノード内に入り、lsnsコマンドで確認 (4026533805は名前空間のid)

$ lsns 4026533805
  PID  PPID USER  COMMAND
 1122  1102 65535 /pause
 1252  1102 root  nginx: master process nginx -g daemon off;
 1297  1252 _rpc  |-nginx: worker process
 1298  1252 _rpc  |-nginx: worker process
 1299  1252 _rpc  |-nginx: worker process
 1300  1252 _rpc  |-nginx: worker process
 1301  1252 _rpc  |-nginx: worker process
 1302  1252 _rpc  |-nginx: worker process
 1304  1252 _rpc  |-nginx: worker process
 1305  1252 _rpc  `-nginx: worker process
 1314  1102 1337  /usr/local/bin/pilot-agent proxy sidecar --domain default.svc.cluster.local --proxyLogLevel=warning --proxyComponentLogLevel=misc:error --log_output_level=default:info
 1338  1314 1337  `-/usr/local/bin/envoy -c etc/istio/proxy/envoy-rev.json

それでnginxのコンテナに入り、iptablesコマンドで確認したものは以下になります。

iptables
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         
ISTIO_INBOUND  tcp  --  anywhere             anywhere            

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
ISTIO_OUTPUT  tcp  --  anywhere             anywhere            

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain ISTIO_INBOUND (1 references)
target     prot opt source               destination         
RETURN     tcp  --  anywhere             anywhere             tcp dpt:15008
RETURN     tcp  --  anywhere             anywhere             tcp dpt:15090
RETURN     tcp  --  anywhere             anywhere             tcp dpt:15021
RETURN     tcp  --  anywhere             anywhere             tcp dpt:15020
ISTIO_IN_REDIRECT  tcp  --  anywhere             anywhere            

Chain ISTIO_IN_REDIRECT (3 references)
target     prot opt source               destination         
REDIRECT   tcp  --  anywhere             anywhere             redir ports 15006

Chain ISTIO_OUTPUT (1 references)
target     prot opt source               destination         
RETURN     all  --  127.0.0.6            anywhere            
ISTIO_IN_REDIRECT  tcp  --  anywhere            !localhost            tcp dpt:!15008 owner UID match 1337
RETURN     all  --  anywhere             anywhere             ! owner UID match 1337
RETURN     all  --  anywhere             anywhere             owner UID match 1337
ISTIO_IN_REDIRECT  tcp  --  anywhere            !localhost            tcp dpt:!15008 owner GID match 1337
RETURN     all  --  anywhere             anywhere             ! owner GID match 1337
RETURN     all  --  anywhere             anywhere             owner GID match 1337
RETURN     all  --  anywhere             localhost           
ISTIO_REDIRECT  all  --  anywhere             anywhere            

Chain ISTIO_REDIRECT (1 references)
target     prot opt source               destination         
REDIRECT   tcp  --  anywhere             anywhere             redir ports 15001
  • UIDの1337はEnovyを実行しているユーザー
  • Envoyの重要なポート番号
    • 15001: Envoy outbound
    • 15006: Envoy inbound

他のポート番号は公式ドキュメントを参照
https://istio.io/latest/docs/ops/deployment/requirements/

これだけでは理解が難しいので、入力と出力の2種類を分けて詳しくみていきます。

Outbound

アプリケーションからの出力では、Servcie -> EnvoyEnvoy -> Serviceの2通りに分けて考えることができます。

Service -> Envoy

IstioOutboundToEnvoy.png

このルートの目的は、アプリケーションからのリクエストをEnvoyの15001ポートにリダイレクトすることになります。

ルーティングテーブルを追うと、
OUTPUT -> ISTIO_OUTPUT -> ISTIO_REDIRECT -> REDIRECT(15001)
となっていました。

基本的な全てのリクエストはISTIO_OUTPUTの一番下のルールに引っ掛かり、ISTIO_REDIRECTチェーンでport:15001にリダイレクトしています。

ここでNATでパケットを書き換えることなく、リダイレクトすることで目的地のIPアドレスをそのままにするのがポイントになっていそう。

Envoy -> Service

IstioOutboundEnvoyToService.png

このルートの目的は、Envoyから目的地にリクエストを投げることです。
ルーティングテーブルを追うと、
OUTPUT ->ISTIO_OUTPUT -> RETURN -> POSTROUTING
となっています。
UIDがEnvoyの1337からのリクエストなので、ISTIO_OUTPUTの上から4番目のルールにヒットしRETURNされます。
この仕組みでリクエストがループすることを防いでいます。

Inbound

外部ネットワークからの入力でも同様に、Servcie -> EnvoyEnvoy -> Serviceの2通りに分けて考えることができます。

Service -> Envoy

IstioInboundToEnvoy.png
このルートの目的は、外部からの通信をEnvoyの15006ポートにリダイレクトすることです。
PREROUTING -> ISTIO_INBOUND -> ISTIO_IN_REDIRECT -> REDIRECT(15006)
Istioの管理用ポートが予約されており、それは150~となります。それ以外のポートはISTIO_INBOUNDチェーン一番下のISTIO_IN_REDIRECTにヒットするので、15006にリダイレクトされるようです。

Envoy -> Service

IstioEnvoyToPod.png
このルートの目的は、Envoyから目的地にリクエストを投げることです。
ルーティングテーブルを追うと、
OUTPUT ->ISTIO_OUTPUT -> RETURN -> POSTROUTING
inboundの時はEnvoyが送信元IPアドレスを127.0.0.6に書き換えるので、一番上のルールに引っ掛かりRETURNされます。

最後に

コンテナの通信をあれこれ調べるの楽しい!
初心者が頑張って調べた程度なので、間違ってる箇所があれば教えてください〜。

参考

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?