📚

istio-proxyがどのように通信を仲介しているかを知る

2022/06/04に公開

目的

前回、書いた記事で素のKubernetesのネットワークについて少し理解できたのですが、Istioを入れた場合はEnvoyが通信を仲介するのでその仕組みを知りたく調べてみました
https://zenn.dev/tayusa/articles/c705cd65b6ee74

環境

  • OS: Arch Linux(5.17.9-arch1-1)
  • k8sの環境: kind

クラスタのセットアップ

kindでクラスタ作成

  • https://kind.sigs.k8s.io/docs/user/quick-start/#installation を参考にkindをインストールします
  • $ kind create cluster --name kind-iptables --config=kind-config.yaml
    • ワーカーを3台用意し、1台をIstio用で2台をアプリ用にしています
    • Istioを動かすノードは31039をポートフォワーディングしてます
kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
  kubeadmConfigPatches:
  - |
    kind: JoinConfiguration
    nodeRegistration:
      kubeletExtraArgs:
        node-labels: "istio=true"
  extraPortMappings:
  - containerPort: 31039
    hostPort: 31039
    protocol: TCP
- role: worker
  kubeadmConfigPatches:
  - |
    kind: JoinConfiguration
    nodeRegistration:
      kubeletExtraArgs:
        node-labels: "app=true"
- role: worker
  kubeadmConfigPatches:
  - |
    kind: JoinConfiguration
    nodeRegistration:
      kubeletExtraArgs:
        node-labels: "app=true"
$ docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED        STATUS       PORTS                       NAMES
4cbf60373417   kindest/node:v1.24.0   "/usr/local/bin/entr…"   26 hours ago   Up 2 hours                               kind-iptables-worker2
27ba7418c58f   kindest/node:v1.24.0   "/usr/local/bin/entr…"   26 hours ago   Up 2 hours   0.0.0.0:31039->31039/tcp    kind-iptables-worker
6ff6e1602678   kindest/node:v1.24.0   "/usr/local/bin/entr…"   26 hours ago   Up 2 hours   127.0.0.1:33099->6443/tcp   kind-iptables-control-plane
042b1d4a47f5   kindest/node:v1.24.0   "/usr/local/bin/entr…"   26 hours ago   Up 2 hours                               kind-iptables-worker3

Istioのインストール

$ asdf plugin add istioctl
$ asdf install istioctl 1.12.7
$ asdf global istioctl 1.12.7
  • 用意したクラスタにIstioをインストール
    • istio-operator.yamlにクラスタ作成で指定したポートやノードラベルを記述しています
    • 今回はログも見たいのでprofileをdemoにしておきます
$ istioctl x precheck
$ istioctl install -f istio-operator.yaml --dry-run
$ istioctl install -f istio-operator.yaml
$ istioctl verify-install -f istio-operator.yaml
$ istioctl tag set stable --revision 1-12-7
istio-operator.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  revision: 1-27-7
  profile: demo
  components:
    ingressGateways:
    - name: istio-ingressgateway
      enabled: true
      k8s:
        nodeSelector:
          istio: "true"
        service:
          type: NodePort
          ports:
          - name: http2
            port: 80
            targetPort: 8080
            nodePort: 31039
    pilot:
      k8s:
        nodeSelector:
          istio: "true"

サンプルのリソースをデプロイ

kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - gateway.yaml
  - namespace.yaml
  - service.yaml
  - virtual_service.yaml
namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: nginx
  labels:
    istio.io/rev: stable
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
      nodeSelector:
        app: "true"
service.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: nginx
spec:
  selector:
    app: nginx
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 80
virtual_service.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: nginx-virtual-service
  namespace: nginx
spec:
  hosts:
    - "*"
  gateways:
    - nginx-gateway
  http:
  - match:
    - port: 80
    route:
    - destination:
        host: nginx-service.nginx.svc.cluster.local
	port:
          number: 8080
gateway.yaml
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: nginx-gateway
  namespace: nginx
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - "*"
  • 上記ファイルをディレクトリに保存してapply
    • $ kubectl apply -k nginx

クラスタの情報

  • istiodとistio-ingressgatewayがWorkerにあります
$ docker exec -it 27ba7418c58f bash
root@kind-iptables-worker:/# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                ATTEMPT             POD ID              POD
03c9af68b9f13       d30470c3a71e4       2 hours ago         Running             istio-proxy         1                   ece587da5d00b       istio-ingressgateway-747b48b769-97sw9
32eb4b7f86960       839c166d0220e       2 hours ago         Running             discovery           1                   e43a4756ff2c0       istiod-1-12-7-6fc7b96bc7-4kjn2
2f00d2479d6f0       6960c0e47829d       2 hours ago         Running             kube-proxy          1                   4b8dd4ea1ca7f       kube-proxy-tp2bn
4d4f608ee18ea       6fb66cd78abfe       2 hours ago         Running             kindnet-cni         1                   7b4f7ff831de6       kindnet-q2pm8
  • nginxがWorker2にnginxが1つ、Worker3に2つあります。そして、nginxのあるPodにistio-proxyが挿入されていることが確認できます
$ docker exec -it 4cbf60373417 bash
root@kind-iptables-worker2:/# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                ATTEMPT             POD ID              POD
8dc62d326774b       d30470c3a71e4       2 hours ago         Running             istio-proxy         1                   6260cc29c02dc       nginx-deployment-6d47dbd4d-6jx9p
2149600f4039e       0e901e68141fd       2 hours ago         Running             nginx               1                   6260cc29c02dc       nginx-deployment-6d47dbd4d-6jx9p
9abf259b3a839       6960c0e47829d       2 hours ago         Running             kube-proxy          1                   e16f248c190a4       kube-proxy-lq7bx
f5524f5a65ac3       6fb66cd78abfe       2 hours ago         Running             kindnet-cni         1                   284b4c1a554a3       kindnet-29dkd
$ docker exec -it 042b1d4a47f5 bash
root@kind-iptables-worker3:/# crictl ps
CONTAINER           IMAGE               CREATED             STATE               NAME                ATTEMPT             POD ID              POD
0550b2a85117b       d30470c3a71e4       2 hours ago         Running             istio-proxy         1                   35f62bf4a3532       nginx-deployment-6d47dbd4d-4p477
511d50f1b85e8       0e901e68141fd       2 hours ago         Running             nginx               1                   35f62bf4a3532       nginx-deployment-6d47dbd4d-4p477
f22ca438e5540       d30470c3a71e4       2 hours ago         Running             istio-proxy         1                   25d6b027a3078       nginx-deployment-6d47dbd4d-zlr62
b74fbff00d282       0e901e68141fd       2 hours ago         Running             nginx               1                   25d6b027a3078       nginx-deployment-6d47dbd4d-zlr62
c31d0698f9dd5       6960c0e47829d       2 hours ago         Running             kube-proxy          1                   9b74410f5c4e9       kube-proxy-kfzlh
e056f7b55fd12       6fb66cd78abfe       2 hours ago         Running             kindnet-cni         1                   17c5b9444ac03       kindnet-krfnh

ネットワーク

  • mermaidの使い方が下手で見づらいかもです

Podのiptablesを覗く

  • iptablesによってenvoyが通信を仲介するように設定してあるので確認してみます

iptables

  • 送信先や宛先を変更できる。他にも色々できる

  • テーブル

    • 役割に応じて4種類ありk8s、Istioで利用しているのはnatテーブルで送信元や宛先を変更するのに利用します
  • チェイン

    • 実際のルールのリスト
    • テーブルの中にチェインがある
    • 組み込みのチェイン
      • PREROUTING、INPUT、OUTPUT、POSTROUTING
      • この順序で適用される
      • 今回だとLOCAL_PROCESSがnginx、envoy
    • ユーザー定義のチェインもある
      • k8sやIstioが用意
      • 組み込みのチェインの中にあるルールによってジャンプして適用される
  • iptablesについてはここに一番詳しく書かれていますが情報が膨大なので私は読めてません

iptablesが更新されるタイミング

  • envoyが挿入されるタイミングと同じくしてinitContainersでistio-iptablesによって更新されている
$ kubectl get pods nginx-deployment-6d47dbd4d-4p477 -o jsonpath='{.spec.initContainers[*].args[*]}'
istio-iptables -p 15001 -z 15006 -u 1337 -m REDIRECT -i * -x  -b * -d 15090,15021,15020

iptablesを確認

  • iptables -L -t nat
$ docker exec -it 042b1d4a47f5 bash
root@kind-iptables-worker3:/# nsenter -t $(pgrep envoy | sed -n 1p) -n iptables -L -t nat
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:ssh
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  all  --  anywhere            !localhost            owner UID match 1337
RETURN     all  --  anywhere             anywhere             ! owner UID match 1337
RETURN     all  --  anywhere             anywhere             owner UID match 1337
ISTIO_IN_REDIRECT  all  --  anywhere            !localhost            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
  • iptables -S -t nat
root@kind-iptables-worker3:/# nsenter -t $(pgrep envoy | sed -n 1p) -n iptables -S -t nat
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N ISTIO_INBOUND
-N ISTIO_IN_REDIRECT
-N ISTIO_OUTPUT
-N ISTIO_REDIRECT
-A PREROUTING -p tcp -j ISTIO_INBOUND
-A OUTPUT -p tcp -j ISTIO_OUTPUT
-A ISTIO_INBOUND -p tcp -m tcp --dport 15008 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 22 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 15090 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 15021 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 15020 -j RETURN
-A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT
-A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006
-A ISTIO_OUTPUT -s 127.0.0.6/32 -o lo -j RETURN
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -m owner --uid-owner 1337 -j ISTIO_IN_REDIRECT
-A ISTIO_OUTPUT -o lo -m owner ! --uid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -m owner --gid-owner 1337 -j ISTIO_IN_REDIRECT
-A ISTIO_OUTPUT -o lo -m owner ! --gid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN
-A ISTIO_OUTPUT -j ISTIO_REDIRECT
-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
  • ISTIO_INBOUND、ISTIO_IN_REDIRECT、ISTIO_OUTPUT、ISTIO_REDIRECTチェインがIstioによって定義されている
  • istio-proxyのuidが1337
root@kind-iptables-worker3:/# crictl exec 0550b2a85117b id
uid=1337(istio-proxy) gid=1337(istio-proxy) groups=1337(istio-proxy)
  • iptablesだけでは順序が分からないのでcurlでリクエストしてistio-proxyのログを確認します

    • $ curl http://localhost:31039
    • $ kubectl logs nginx-deployment-6d47dbd4d-6jx9p istio-proxy
      • [2022-06-04T13:36:03.773Z] "- - -" 0 - - - "-" 2583 1548 65091 - "-" "-" "-" "-" "10.244.2.4:80" inbound|80|| 127.0.0.6:49097 10.244.2.4:80 10.244.3.3:44008 outbound_.8080_._.nginx-service.nginx.svc.cluster.local -
      • UPSTREAM_HOST
        • 10.244.2.4:80
      • UPSTREAM_CLUSTER
        • inbound|80||
      • UPSTREAM_LOCAL_ADDRESS
        • 127.0.0.6:49097
      • DOWNSTREAM_LOCAL_ADDRESS
        • 10.244.2.4:80
      • DOWNSTREAM_REMOTE_ADDRESS
        • 10.244.3.3:44008
      • REQUESTED_SERVER_NAME
        • outbound_.8080_._.nginx-service.nginx.svc.cluster.local
      • https://istio.io/latest/docs/tasks/observability/logs/access-log/#default-access-log-format
  • envoyへのチェインの適用順

    • PREROUTING
    • ISTIO_INBOUND tcp -- anywhere anywhere
    • ISTIO_IN_REDIRECT tcp -- anywhere anywhere
    • REDIRECT tcp -- anywhere anywhere redir ports 15006
  • envoyからnginxへのチェインの適用順

    • OUTPUT
    • ISTIO_OUTPUT tcp -- anywhere anywhere
    • RETURN all -- 127.0.0.6 anywhere
      • RETURNは次のチェインでOUTPUTの次はPOSTROUTING
      • UPSTREAM_LOCAL_ADDRESSが127.0.0.6:49097
    • POSTROUTING
      • ルールなしでそのままUPSTREAM_HOSTの10.244.2.4:80

まとめ

istio-proxyの周りしか見れなかったですが、iptablesによって通信を仲介していることが確認できました
雰囲気でIstioと接していたので少し親睦が深められ良かったです

Discussion