<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 深入理解Istio Service Mesh中的Envoy Sidecar注入與流量劫持 **注意:本書中的 Service Mesh 章節已不再維護,請轉到 [istio-handbook](https://jimmysong.io/istio-handbook) 中瀏覽。** 在講解 Istio 如何將 Envoy 代理注入到應用程序 Pod 中之前,我們需要先了解以下幾個概念: - Sidecar 模式:容器應用模式之一,Service Mesh 架構的一種實現方式。 - Init 容器:Pod 中的一種專用的容器,在應用程序容器啟動之前運行,用來包含一些應用鏡像中不存在的實用工具或安裝腳本。 - iptables:流量劫持是通過 iptables 轉發實現的。 查看目前 `productpage-v1-745ffc55b7-2l2lw` Pod 中運行的容器: ```bash $ kubectl -n default get pod productpage-v1-745ffc55b7-2l2lw -o=jsonpath='{..spec.containers[*].name}' productpage istio-proxy ``` `productpage` 即應用容器,`istio-proxy` 即 Envoy 代理的 sidecar 容器。另外該 Pod 中實際上還運行過一個 Init 容器,因為它執行結束就自動終止了,所以我們看不到該容器的存在。關注 `jsonpath` 的用法請參考 [JSONPath Support](https://kubernetes.io/docs/reference/kubectl/jsonpath/)。 ## Sidecar 模式 在了解 Istio 使用 Sidecar 注入之前,需要先說明下什么是 Sidecar 模式。Sidecar 是容器應用模式的一種,也是在 Service Mesh 中發揚光大的一種模式,詳見 [Service Mesh 架構解析](http://www.servicemesher.com/blog/service-mesh-architectures/),其中詳細描述了**節點代理**和 **Sidecar** 模式的 Service Mesh 架構。 使用 Sidecar 模式部署服務網格時,無需在節點上運行代理(因此您不需要基礎結構的協作),但是集群中將運行多個相同的 Sidecar 副本。從另一個角度看:我可以為一組微服務部署到一個服務網格中,你也可以部署一個有特定實現的服務網格。在 Sidecar 部署方式中,你會為每個應用的容器部署一個伴生容器。Sidecar 接管進出應用容器的所有流量。在 Kubernetes 的 Pod 中,在原有的應用容器旁邊運行一個 Sidecar 容器,可以理解為兩個容器共享存儲、網絡等資源,可以廣義的將這個注入了 Sidecar 容器的 Pod 理解為一臺主機,兩個容器共享主機資源。 例如下圖 [SOFAMesh & SOFA MOSN—基于Istio構建的用于應對大規模流量的Service Mesh解決方案](https://jimmysong.io/posts/sofamesh-and-mosn-proxy-sidecar-service-mesh-by-ant-financial/)的架構圖中描述的,MOSN 作為 Sidecar 的方式和應用運行在同一個 Pod 中,攔截所有進出應用容器的流量,[SOFAMesh](https://github.com/alipay/sofa-mesh) 兼容 Istio,其中使用 Go 語言開發的 [SOFAMosn](https://github.com/alipay/sofa-mosn) 替換了 Envoy。 ![SOFAMesh架構圖](https://ws4.sinaimg.cn/large/006tNbRwgy1fuyr4vizzwj31kw1biq98.jpg) **注意**:下文中所指的 Sidecar 都是指的 Envoy 代理容器。 ## Init 容器 Init 容器是一種專用容器,它在應用程序容器啟動之前運行,用來包含一些應用鏡像中不存在的實用工具或安裝腳本。 一個 Pod 中可以指定多個 Init 容器,如果指定了多個,那么 Init 容器將會按順序依次運行。只有當前面的 Init 容器必須運行成功后,才可以運行下一個 Init 容器。當所有的 Init 容器運行完成后,Kubernetes 才初始化 Pod 和運行應用容器。 Init 容器使用 Linux Namespace,所以相對應用程序容器來說具有不同的文件系統視圖。因此,它們能夠具有訪問 Secret 的權限,而應用程序容器則不能。 在 Pod 啟動過程中,Init 容器會按順序在網絡和數據卷初始化之后啟動。每個容器必須在下一個容器啟動之前成功退出。如果由于運行時或失敗退出,將導致容器啟動失敗,它會根據 Pod 的 `restartPolicy` 指定的策略進行重試。然而,如果 Pod 的 `restartPolicy` 設置為 Always,Init 容器失敗時會使用 `RestartPolicy` 策略。 在所有的 Init 容器沒有成功之前,Pod 將不會變成 `Ready` 狀態。Init 容器的端口將不會在 Service 中進行聚集。 正在初始化中的 Pod 處于 `Pending` 狀態,但應該會將 `Initializing` 狀態設置為 true。Init 容器運行完成以后就會自動終止。 關于 Init 容器的詳細信息請參考 [Init 容器 - Kubernetes 中文指南/云原生應用架構實踐手冊](https://jimmysong.io/kubernetes-handbook/concepts/init-containers.html)。 ## Sidecar 注入示例分析 我們看下 Istio 官方示例 `bookinfo` 中 `productpage` 的 YAML 配置,關于 `bookinfo` 應用的詳細 YAML 配置請參考 [bookinfo.yaml](https://github.com/rootsongjc/kubernetes-vagrant-centos-cluster/blob/master/yaml/istio-bookinfo/bookinfo.yaml)。 ```yaml apiVersion: v1 kind: Service metadata: name: productpage labels: app: productpage spec: ports: - port: 9080 name: http selector: app: productpage --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: productpage-v1 spec: replicas: 1 template: metadata: labels: app: productpage version: v1 spec: containers: - name: productpage image: istio/examples-bookinfo-productpage-v1:1.8.0 imagePullPolicy: IfNotPresent ports: - containerPort: 9080 ``` 再查看下 `productpage` 容器的 [Dockerfile](https://github.com/istio/istio/blob/master/samples/bookinfo/src/productpage/Dockerfile)。 ```docker FROM python:2.7-slim COPY requirements.txt ./ RUN pip install --no-cache-dir -r requirements.txt COPY productpage.py /opt/microservices/ COPY templates /opt/microservices/templates COPY requirements.txt /opt/microservices/ EXPOSE 9080 WORKDIR /opt/microservices CMD python productpage.py 9080 ``` 我們看到 `Dockerfile` 中沒有配置 `ENTRYPOINT`,所以 `CMD` 的配置 `python productpage.py 9080` 將作為默認的 `ENTRYPOINT`,記住這一點,再看下注入 sidecar 之后的配置。 ```bash $ istioctl kube-inject -f yaml/istio-bookinfo/bookinfo.yaml ``` 我們只截取其中與 `productpage` 相關的 `Service` 和 `Deployment` 配置部分。 ```yaml apiVersion: v1 kind: Service metadata: name: productpage labels: app: productpage spec: ports: - port: 9080 name: http selector: app: productpage --- apiVersion: extensions/v1beta1 kind: Deployment metadata: creationTimestamp: null name: productpage-v1 spec: replicas: 1 strategy: {} template: metadata: annotations: sidecar.istio.io/status: '{"version":"fde14299e2ae804b95be08e0f2d171d466f47983391c00519bbf01392d9ad6bb","initContainers":["istio-init"],"containers":["istio-proxy"],"volumes":["istio-envoy","istio-certs"],"imagePullSecrets":null}' creationTimestamp: null labels: app: productpage version: v1 spec: containers: - image: istio/examples-bookinfo-productpage-v1:1.8.0 imagePullPolicy: IfNotPresent name: productpage ports: - containerPort: 9080 resources: {} - args: - proxy - sidecar - --configPath - /etc/istio/proxy - --binaryPath - /usr/local/bin/envoy - --serviceCluster - productpage - --drainDuration - 45s - --parentShutdownDuration - 1m0s - --discoveryAddress - istio-pilot.istio-system:15007 - --discoveryRefreshDelay - 1s - --zipkinAddress - zipkin.istio-system:9411 - --connectTimeout - 10s - --statsdUdpAddress - istio-statsd-prom-bridge.istio-system:9125 - --proxyAdminPort - "15000" - --controlPlaneAuthPolicy - NONE env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: INSTANCE_IP valueFrom: fieldRef: fieldPath: status.podIP - name: ISTIO_META_POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: ISTIO_META_INTERCEPTION_MODE value: REDIRECT image: jimmysong/istio-release-proxyv2:1.0.0 imagePullPolicy: IfNotPresent name: istio-proxy resources: requests: cpu: 10m securityContext: privileged: false readOnlyRootFilesystem: true runAsUser: 1337 volumeMounts: - mountPath: /etc/istio/proxy name: istio-envoy - mountPath: /etc/certs/ name: istio-certs readOnly: true initContainers: - args: - -p - "15001" - -u - "1337" - -m - REDIRECT - -i - '*' - -x - "" - -b - 9080, - -d - "" image: jimmysong/istio-release-proxy_init:1.0.0 imagePullPolicy: IfNotPresent name: istio-init resources: {} securityContext: capabilities: add: - NET_ADMIN privileged: true volumes: - emptyDir: medium: Memory name: istio-envoy - name: istio-certs secret: optional: true secretName: istio.default status: {} ``` 我們看到 Service 的配置沒有變化,所有的變化都在 `Deployment` 里,Istio 給應用 Pod 注入的配置主要包括: - Init 容器 `istio-init`:用于給 Sidecar 容器即 Envoy 代理做初始化,設置 iptables 端口轉發 - Envoy sidecar 容器 `istio-proxy`:運行 Envoy 代理 接下來將分別解析下這兩個容器。 ### Init 容器解析 Istio 在 Pod 中注入的 Init 容器名為 `istio-init`,我們在上面 Istio 注入完成后的 YAML 文件中看到了該容器的啟動參數: ```bash -p 15001 -u 1337 -m REDIRECT -i '*' -x "" -b 9080 -d "" ``` 我們再檢查下該容器的 [Dockerfile](https://github.com/istio/istio/blob/master/pilot/docker/Dockerfile.proxy_init) 看看 `ENTRYPOINT` 是什么以確定啟動時執行的命令。 ```docker FROM ubuntu:xenial RUN apt-get update && apt-get install -y \ iproute2 \ iptables \ && rm -rf /var/lib/apt/lists/* ADD istio-iptables.sh /usr/local/bin/ ENTRYPOINT ["/usr/local/bin/istio-iptables.sh"] ``` 我們看到 `istio-init` 容器的入口是 `/usr/local/bin/istio-iptables.sh` 腳本,再按圖索驥看看這個腳本里到底寫的什么,該腳本的位置在 Istio 源碼倉庫的 [tools/deb/istio-iptables.sh](https://github.com/istio/istio/blob/master/tools/deb/istio-iptables.sh),一共 300 多行,就不貼在這里了。下面我們就來解析下這個啟動腳本。 ### Init 容器啟動入口 Init 容器的啟動入口是 `/usr/local/bin/istio-iptables.sh` 腳本,該腳本的用法如下: ```bash $ istio-iptables.sh -p PORT -u UID -g GID [-m mode] [-b ports] [-d ports] [-i CIDR] [-x CIDR] [-h] -p: 指定重定向所有 TCP 流量的 Envoy 端口(默認為 $ENVOY_PORT = 15001) -u: 指定未應用重定向的用戶的 UID。通常,這是代理容器的 UID(默認為 $ENVOY_USER 的 uid,istio_proxy 的 uid 或 1337) -g: 指定未應用重定向的用戶的 GID。(與 -u param 相同的默認值) -m: 指定入站連接重定向到 Envoy 的模式,“REDIRECT” 或 “TPROXY”(默認為 $ISTIO_INBOUND_INTERCEPTION_MODE) -b: 逗號分隔的入站端口列表,其流量將重定向到 Envoy(可選)。使用通配符 “*” 表示重定向所有端口。為空時表示禁用所有入站重定向(默認為 $ISTIO_INBOUND_PORTS) -d: 指定要從重定向到 Envoy 中排除(可選)的入站端口列表,以逗號格式分隔。使用通配符“*” 表示重定向所有入站流量(默認為 $ISTIO_LOCAL_EXCLUDE_PORTS) -i: 指定重定向到 Envoy(可選)的 IP 地址范圍,以逗號分隔的 CIDR 格式列表。使用通配符 “*” 表示重定向所有出站流量。空列表將禁用所有出站重定向(默認為 $ISTIO_SERVICE_CIDR) -x: 指定將從重定向中排除的 IP 地址范圍,以逗號分隔的 CIDR 格式列表。使用通配符 “*” 表示重定向所有出站流量(默認為 $ISTIO_SERVICE_EXCLUDE_CIDR)。 環境變量位于 $ISTIO_SIDECAR_CONFIG(默認在:/var/lib/istio/envoy/sidecar.env) ``` 通過查看該腳本你將看到,以上傳入的參數都會重新組裝成 [`iptables` 命令](https://wangchujiang.com/linux-command/c/iptables.html)的參數。 再參考 `istio-init` 容器的啟動參數,完整的啟動命令如下: ```bash $ /usr/local/bin/istio-iptables.sh -p 15001 -u 1337 -m REDIRECT -i '*' -x "" -b 9080 -d "" ``` 該容器存在的意義就是讓 Envoy 代理可以攔截所有的進出 Pod 的流量,即將入站流量重定向到 Sidecar,再攔截應用容器的出站流量經過 Sidecar 處理后再出站。 **命令解析** 這條啟動命令的作用是: - 將應用容器的所有流量都轉發到 Envoy 的 15001 端口。 - 使用 `istio-proxy` 用戶身份運行, UID 為 1337,即 Envoy 所處的用戶空間,這也是 `istio-proxy` 容器默認使用的用戶,見 YAML 配置中的 `runAsUser` 字段。 - 使用默認的 `REDIRECT` 模式來重定向流量。 - 將所有出站流量都重定向到 Envoy 代理。 - 將所有訪問 9080 端口(即應用容器 `productpage` 的端口)的流量重定向到 Envoy 代理。 因為 Init 容器初始化完畢后就會自動終止,因為我們無法登陸到容器中查看 iptables 信息,但是 Init 容器初始化結果會保留到應用容器和 Sidecar 容器中。 ### istio-proxy 容器解析 為了查看 iptables 配置,我們需要登陸到 Sidecar 容器中使用 root 用戶來查看,因為 `kubectl` 無法使用特權模式來遠程操作 docker 容器,所以我們需要登陸到 `productpage` Pod 所在的主機上使用 `docker` 命令登陸容器中查看。 查看 `productpage` Pod 所在的主機。 ```bash $ kubectl -n default get pod -l app=productpage -o wide NAME READY STATUS RESTARTS AGE IP NODE productpage-v1-745ffc55b7-2l2lw 2/2 Running 0 1d 172.33.78.10 node3 ``` 從輸出結果中可以看到該 Pod 運行在 `node3` 上,使用 `vagrant` 命令登陸到 `node3` 主機中并切換為 root 用戶。 ```bash $ vagrant ssh node3 $ sudo -i ``` 查看 iptables 配置,列出 NAT(網絡地址轉換)表的所有規則,因為在 Init 容器啟動的時候選擇給 `istio-iptables.sh` 傳遞的參數中指定將入站流量重定向到 Envoy 的模式為 “REDIRECT”,因此在 iptables 中將只有 NAT 表的規格配置,如果選擇 `TPROXY` 還會有 `mangle` 表配置。`iptables` 命令的詳細用法請參考 [iptables](https://wangchujiang.com/linux-command/c/iptables.html),規則配置請參考 [iptables 規則配置](http://www.zsythink.net/archives/1517)。 ## 理解 iptables `iptables` 是 Linux 內核中的防火墻軟件 netfilter 的管理工具,位于用戶空間,同時也是 netfilter 的一部分。Netfilter 位于內核空間,不僅有網絡地址轉換的功能,也具備數據包內容修改、以及數據包過濾等防火墻功能。 在了解 Init 容器初始化的 iptables 之前,我們先來了解下 iptables 和規則配置。 下圖展示了 iptables 調用鏈。 ![iptables 調用鏈](https://ws4.sinaimg.cn/large/0069RVTdly1fv5hukl647j30k6145gnt.jpg) ### iptables 中的表 Init 容器中使用的的 iptables 版本是 `v1.6.0`,共包含 5 張表: 1. `raw` 用于配置數據包,`raw` 中的數據包不會被系統跟蹤。 2. `filter` 是用于存放所有與防火墻相關操作的默認表。 3. `nat` 用于 [網絡地址轉換](https://en.wikipedia.org/wiki/Network_address_translation)(例如:端口轉發)。 4. `mangle` 用于對特定數據包的修改(參考[損壞數據包](https://en.wikipedia.org/wiki/Mangled_packet))。 5. `security` 用于[強制訪問控制](https://wiki.archlinux.org/index.php/Security#Mandatory_access_control) 網絡規則。 **注**:在本示例中只用到了 `nat` 表。 不同的表中的具有的鏈類型如下表所示: | 規則名稱 | raw | filter | nat | mangle | security | | ----------- | ---- | ------ | ---- | ------ | -------- | | PREROUTING | ? | | ? | ? | | | INPUT | | ? | ? | ? | ? | | OUTPUT | | ? | ? | ? | ? | | POSTROUTING | | | ? | ? | | | FORWARD | ? | ? | | ? | ? | 下圖是 iptables 的調用鏈順序。 ![iptables 調用鏈](https://ws1.sinaimg.cn/large/0069RVTdgy1fv5dq2bptdj31110begnl.jpg) 關于 iptables 的詳細介紹請參考[常見 iptables 使用規則場景整理](https://www.aliang.org/Linux/iptables.html)。 ### iptables 命令 `iptables` 命令的主要用途是修改這些表中的規則。`iptables` 命令格式如下: ```bash $ iptables [-t 表名] 命令選項[鏈名][條件匹配][-j 目標動作或跳轉] ``` Init 容器中的 `/istio-iptables.sh` 啟動入口腳本就是執行 iptables 初始化的。 ### 理解 iptables 規則 查看 `istio-proxy` 容器中的默認的 iptables 規則,默認查看的是 filter 表中的規則。 ```bash $ iptables -L -v Chain INPUT (policy ACCEPT 350K packets, 63M bytes) pkts bytes target prot opt in out source destination Chain FORWARD (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 18M packets, 1916M bytes) pkts bytes target prot opt in out source destination ``` 我們看到三個默認的鏈,分別是 INPUT、FORWARD 和 OUTPUT,每個鏈中的第一行輸出表示鏈名稱(在本例中為INPUT/FORWARD/OUTPUT),后跟默認策略(ACCEPT)。 下圖是 iptables 的建議結構圖,流量在經過 INPUT 鏈之后就進入了上層協議棧,比如 ![iptables結構圖](https://ws4.sinaimg.cn/large/0069RVTdgy1fv5dm4a9ygj30w50czdi3.jpg) 圖片來自[常見 iptables 使用規則場景整理](https://www.aliang.org/Linux/iptables.html) 每條鏈中都可以添加多條規則,規則是按照順序從前到后執行的。我們來看下規則的表頭定義。 - **pkts**:處理過的匹配的報文數量 - **bytes**:累計處理的報文大小(字節數) - **target**:如果報文與規則匹配,指定目標就會被執行。 - **prot**:協議,例如 `tdp`、`udp`、`icmp` 和 `all`。 - **opt**:很少使用,這一列用于顯示 IP 選項。 - **in**:入站網卡。 - **out**:出站網卡。 - **source**:流量的源 IP 地址或子網,后者是 `anywhere`。 - **destination**:流量的目的地 IP 地址或子網,或者是 `anywhere`。 還有一列沒有表頭,顯示在最后,表示規則的選項,作為規則的擴展匹配條件,用來補充前面的幾列中的配置。`prot`、`opt`、`in`、`out`、`source` 和 `destination` 和顯示在 `destination` 后面的沒有表頭的一列擴展條件共同組成匹配規則。當流量匹配這些規則后就會執行 `target`。 關于 iptables 規則請參考[常見iptables使用規則場景整理](https://www.aliang.org/Linux/iptables.html)。 **target 支持的類型** `target` 類型包括 ACCEPT`、REJECT`、`DROP`、`LOG` 、`SNAT`、`MASQUERADE`、`DNAT`、`REDIRECT`、`RETURN` 或者跳轉到其他規則等。只要執行到某一條鏈中只有按照順序有一條規則匹配后就可以確定報文的去向了,除了 `RETURN` 類型,類似編程語言中的 `return` 語句,返回到它的調用點,繼續執行下一條規則。`target` 支持的配置詳解請參考 [iptables 詳解(1):iptables 概念](http://www.zsythink.net/archives/1199)。 從輸出結果中可以看到 Init 容器沒有在 iptables 的默認鏈路中創建任何規則,而是創建了新的鏈路。 ## 查看 iptables nat 表中注入的規則 Init 容器通過向 iptables nat 表中注入轉發規則來劫持流量的,下圖顯示的是 productpage 服務中的 iptables 流量劫持的詳細過程。 ![Envoy sidecar 流量劫持 Istio iptables 宋凈超 Jimmy Song 服務網格 Service Mesh](https://ws1.sinaimg.cn/large/0069RVTdgy1fv5doj8fuij31kw0ytn7h.jpg) Init 容器啟動時命令行參數中指定了 `REDIRECT` 模式,因此只創建了 NAT 表規則,接下來我們查看下 NAT 表中創建的規則,這是全文中的**重點部分**,前面講了那么多都是為它做鋪墊的。下面是查看 nat 表中的規則,其中鏈的名字中包含 `ISTIO` 前綴的是由 Init 容器注入的,規則匹配是根據下面顯示的順序來執行的,其中會有多次跳轉。 ```bash # 查看 NAT 表中規則配置的詳細信息 $ iptables -t nat -L -v # PREROUTING 鏈:用于目標地址轉換(DNAT),將所有入站 TCP 流量跳轉到 ISTIO_INBOUND 鏈上 Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 2 120 ISTIO_INBOUND tcp -- any any anywhere anywhere # INPUT 鏈:處理輸入數據包,非 TCP 流量將繼續 OUTPUT 鏈 Chain INPUT (policy ACCEPT 2 packets, 120 bytes) pkts bytes target prot opt in out source destination # OUTPUT 鏈:將所有出站數據包跳轉到 ISTIO_OUTPUT 鏈上 Chain OUTPUT (policy ACCEPT 41146 packets, 3845K bytes) pkts bytes target prot opt in out source destination 93 5580 ISTIO_OUTPUT tcp -- any any anywhere anywhere # POSTROUTING 鏈:所有數據包流出網卡時都要先進入POSTROUTING 鏈,內核根據數據包目的地判斷是否需要轉發出去,我們看到此處未做任何處理 Chain POSTROUTING (policy ACCEPT 41199 packets, 3848K bytes) pkts bytes target prot opt in out source destination # ISTIO_INBOUND 鏈:將所有目的地為 9080 端口的入站流量重定向到 ISTIO_IN_REDIRECT 鏈上 Chain ISTIO_INBOUND (1 references) pkts bytes target prot opt in out source destination 2 120 ISTIO_IN_REDIRECT tcp -- any any anywhere anywhere tcp dpt:9080 # ISTIO_IN_REDIRECT 鏈:將所有的入站流量跳轉到本地的 15001 端口,至此成功的攔截了流量到 Envoy Chain ISTIO_IN_REDIRECT (1 references) pkts bytes target prot opt in out source destination 2 120 REDIRECT tcp -- any any anywhere anywhere redir ports 15001 # ISTIO_OUTPUT 鏈:選擇需要重定向到 Envoy(即本地) 的出站流量,所有非 localhost 的流量全部轉發到 ISTIO_REDIRECT。為了避免流量在該 Pod 中無限循環,所有到 istio-proxy 用戶空間的流量都返回到它的調用點中的下一條規則,本例中即 OUTPUT 鏈,因為跳出 ISTIO_OUTPUT 規則之后就進入下一條鏈 POSTROUTING。如果目的地非 localhost 就跳轉到 ISTIO_REDIRECT;如果流量是來自 istio-proxy 用戶空間的,那么就跳出該鏈,返回它的調用鏈繼續執行下一條規則(OUPT 的下一條規則,無需對流量進行處理);所有的非 istio-proxy 用戶空間的目的地是 localhost 的流量就跳轉到 ISTIO_REDIRECT Chain ISTIO_OUTPUT (1 references) pkts bytes target prot opt in out source destination 0 0 ISTIO_REDIRECT all -- any lo anywhere !localhost 40 2400 RETURN all -- any any anywhere anywhere owner UID match istio-proxy 0 0 RETURN all -- any any anywhere anywhere owner GID match istio-proxy 0 0 RETURN all -- any any anywhere localhost 53 3180 ISTIO_REDIRECT all -- any any anywhere anywhere # ISTIO_REDIRECT 鏈:將所有流量重定向到 Envoy(即本地) 的 15001 端口 Chain ISTIO_REDIRECT (2 references) pkts bytes target prot opt in out source destination 53 3180 REDIRECT tcp -- any any anywhere anywhere redir ports 15001 ``` `iptables` 顯示的鏈的順序,即流量規則匹配的順序。其中要特別注意 `ISTIO_OUTPUT` 鏈中的規則配置。為了避免流量一直在 Pod 中無限循環,所有到 istio-proxy 用戶空間的流量都返回到它的調用點中的下一條規則,本例中即 OUTPUT 鏈,因為跳出 `ISTIO_OUTPUT` 規則之后就進入下一條鏈 `POSTROUTING`。 `ISTIO_OUTPUT` 鏈規則匹配的詳細過程如下: - 如果目的地非 localhost 就跳轉到 ISTIO_REDIRECT 鏈 - 所有來自 istio-proxy 用戶空間的流量跳轉到它的調用點 `OUTPUT` 繼續執行 `OUTPUT` 鏈的下一條規則,因為 `OUTPUT` 鏈中沒有下一條規則了,所以會繼續執行 `POSTROUTING` 鏈然后跳出 iptables,直接訪問目的地 - 如果目的地是 localhost 但是流量又不是來自 istio-proxy 用戶空間的就跳轉到 `ISTIO_REDIRECT` 鏈 以上 iptables 規則都是 Init 容器啟動的時使用 [istio-iptables.sh](https://github.com/istio/istio/blob/master/tools/deb/istio-iptables.sh) 腳本生成的,詳細過程可以查看該腳本。 ## 查看 Envoy 運行狀態 首先查看 `proxyv2` 鏡像的 [Dockerfile](https://github.com/istio/istio/blob/master/pilot/docker/Dockerfile.proxyv2)。 ```docker FROM istionightly/base_debug ARG proxy_version ARG istio_version # 安裝 Envoy ADD envoy /usr/local/bin/envoy # 使用環境變量的方式明文指定 proxy 的版本/功能 ENV ISTIO_META_ISTIO_PROXY_VERSION "1.1.0" # 使用環境變量的方式明文指定 proxy 明確的 sha,用于指定版本的配置和調試 ENV ISTIO_META_ISTIO_PROXY_SHA $proxy_version # 環境變量,指定明確的構建號,用于調試 ENV ISTIO_META_ISTIO_VERSION $istio_version ADD pilot-agent /usr/local/bin/pilot-agent ADD envoy_pilot.yaml.tmpl /etc/istio/proxy/envoy_pilot.yaml.tmpl ADD envoy_policy.yaml.tmpl /etc/istio/proxy/envoy_policy.yaml.tmpl ADD envoy_telemetry.yaml.tmpl /etc/istio/proxy/envoy_telemetry.yaml.tmpl ADD istio-iptables.sh /usr/local/bin/istio-iptables.sh COPY envoy_bootstrap_v2.json /var/lib/istio/envoy/envoy_bootstrap_tmpl.json RUN chmod 755 /usr/local/bin/envoy /usr/local/bin/pilot-agent # 將 istio-proxy 用戶加入 sudo 權限以允許執行 tcpdump 和其他調試命令 RUN useradd -m --uid 1337 istio-proxy && \ echo "istio-proxy ALL=NOPASSWD: ALL" >> /etc/sudoers && \ chown -R istio-proxy /var/lib/istio # 使用 pilot-agent 來啟動 Envoy ENTRYPOINT ["/usr/local/bin/pilot-agent"] ``` 該容器的啟動入口是 `pilot-agent` 命令,根據 YAML 配置中傳遞的參數,詳細的啟動命令入下: ```bash /usr/local/bin/pilot-agent proxy sidecar --configPath /etc/istio/proxy --binaryPath /usr/local/bin/envoy --serviceCluster productpage --drainDuration 45s --parentShutdownDuration 1m0s --discoveryAddress istio-pilot.istio-system:15007 --discoveryRefreshDelay 1s --zipkinAddress zipkin.istio-system:9411 --connectTimeout 10s --statsdUdpAddress istio-statsd-prom-bridge.istio-system:9125 --proxyAdminPort 15000 --controlPlaneAuthPolicy NONE ``` 主要配置了 Envoy 二進制文件的位置、服務發現地址、服務集群名、監控指標上報地址、Envoy 的管理端口、熱重啟時間等,詳細用法請參考 [Istio官方文檔 pilot-agent 的用法](https://istio.io/docs/reference/commands/pilot-agent/)。 `pilot-agent` 是容器中 PID 為 1 的啟動進程,它啟動時又創建了一個 Envoy 進程,如下: ```bash /usr/local/bin/envoy -c /etc/istio/proxy/envoy-rev0.json --restart-epoch 0 --drain-time-s 45 --parent-shutdown-time-s 60 --service-cluster productpage --service-node sidecar~172.33.78.10~productpage-v1-745ffc55b7-2l2lw.default~default.svc.cluster.local --max-obj-name-len 189 -l warn --v2-config-only ``` 我們分別解釋下以上配置的意義。 - `-c /etc/istio/proxy/envoy-rev0.json`:配置文件,支持 `.json`、`.yaml`、`.pb` 和 `.pb_text` 格式,`pilot-agent` 啟動的時候讀取了容器的環境變量后創建的。 - `--restart-epoch 0`:Envoy 熱重啟周期,第一次啟動默認為 0,每熱重啟一次該值加 1。 - `--drain-time-s 45`:熱重啟期間 Envoy 將耗盡連接的時間。 - `--parent-shutdown-time-s 60`: Envoy 在熱重啟時關閉父進程之前等待的時間。 - `--service-cluster productpage`:Envoy 運行的本地服務集群的名字。 - `--service-node sidecar~172.33.78.10~productpage-v1-745ffc55b7-2l2lw.default~default.svc.cluster.local`:定義 Envoy 運行的本地服務節點名稱,其中包含了該 Pod 的名稱、IP、DNS 域等信息,根據容器的環境變量拼出來的。 - `-max-obj-name-len 189`:cluster/route_config/listener 中名稱字段的最大長度(以字節為單位) - `-l warn`:日志級別 - `--v2-config-only`:只解析 v2 引導配置文件 詳細配置請參考 [Envoy 的命令行選項](http://www.servicemesher.com/envoy/operations/cli.html)。 查看 Envoy 的配置文件 `/etc/istio/proxy/envoy-rev0.json`。 ```json { "node": { "id": "sidecar~172.33.78.10~productpage-v1-745ffc55b7-2l2lw.default~default.svc.cluster.local", "cluster": "productpage", "metadata": { "INTERCEPTION_MODE": "REDIRECT", "ISTIO_PROXY_SHA": "istio-proxy:6166ae7ebac7f630206b2fe4e6767516bf198313", "ISTIO_PROXY_VERSION": "1.0.0", "ISTIO_VERSION": "1.0.0", "POD_NAME": "productpage-v1-745ffc55b7-2l2lw", "istio": "sidecar" } }, "stats_config": { "use_all_default_tags": false }, "admin": { "access_log_path": "/dev/stdout", "address": { "socket_address": { "address": "127.0.0.1", "port_value": 15000 } } }, "dynamic_resources": { "lds_config": { "ads": {} }, "cds_config": { "ads": {} }, "ads_config": { "api_type": "GRPC", "refresh_delay": {"seconds": 1, "nanos": 0}, "grpc_services": [ { "envoy_grpc": { "cluster_name": "xds-grpc" } } ] } }, "static_resources": { "clusters": [ { "name": "xds-grpc", "type": "STRICT_DNS", "connect_timeout": {"seconds": 10, "nanos": 0}, "lb_policy": "ROUND_ROBIN", "hosts": [ { "socket_address": {"address": "istio-pilot.istio-system", "port_value": 15010} } ], "circuit_breakers": { "thresholds": [ { "priority": "default", "max_connections": "100000", "max_pending_requests": "100000", "max_requests": "100000" }, { "priority": "high", "max_connections": "100000", "max_pending_requests": "100000", "max_requests": "100000" }] }, "upstream_connection_options": { "tcp_keepalive": { "keepalive_time": 300 } }, "http2_protocol_options": { } } , { "name": "zipkin", "type": "STRICT_DNS", "connect_timeout": { "seconds": 1 }, "lb_policy": "ROUND_ROBIN", "hosts": [ { "socket_address": {"address": "zipkin.istio-system", "port_value": 9411} } ] } ] }, "tracing": { "http": { "name": "envoy.zipkin", "config": { "collector_cluster": "zipkin" } } }, "stats_sinks": [ { "name": "envoy.statsd", "config": { "address": { "socket_address": {"address": "10.254.109.175", "port_value": 9125} } } } ] } ``` 下圖是使用 Istio 管理的 bookinfo 示例的訪問請求路徑圖。 ![Istio bookinfo](https://ws3.sinaimg.cn/large/0069RVTdgy1fv5df9lq1aj317o0o6wia.jpg) 圖片來自 [Istio 官方網站](https://istio.io/zh/docs/examples/bookinfo/) 對照 bookinfo 示例的 productpage 的查看建立的連接。在 `productpage-v1-745ffc55b7-2l2lw` Pod 的 `istio-proxy` 容器中使用 root 用戶查看打開的端口。 ```bash $ lsof -i COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME envoy 11 istio-proxy 9u IPv4 73951 0t0 TCP localhost:15000 (LISTEN) # Envoy admin 端口 envoy 11 istio-proxy 17u IPv4 74320 0t0 TCP productpage-v1-745ffc55b7-2l2lw:46862->istio-pilot.istio-system.svc.cluster.local:15010 (ESTABLISHED) # 15010:istio-pilot 的 grcp-xds 端口 envoy 11 istio-proxy 18u IPv4 73986 0t0 UDP productpage-v1-745ffc55b7-2l2lw:44332->istio-statsd-prom-bridge.istio-system.svc.cluster.local:9125 # 給 Promethues 發送 metric 的端口 envoy 11 istio-proxy 52u IPv4 74599 0t0 TCP *:15001 (LISTEN) # Envoy 的監聽端口 envoy 11 istio-proxy 53u IPv4 74600 0t0 UDP productpage-v1-745ffc55b7-2l2lw:48011->istio-statsd-prom-bridge.istio-system.svc.cluster.local:9125 # 給 Promethues 發送 metric 端口 envoy 11 istio-proxy 54u IPv4 338551 0t0 TCP productpage-v1-745ffc55b7-2l2lw:15001->172.17.8.102:52670 (ESTABLISHED) # 52670:Ingress gateway 端口 envoy 11 istio-proxy 55u IPv4 338364 0t0 TCP productpage-v1-745ffc55b7-2l2lw:44046->172.33.78.9:9091 (ESTABLISHED) # 9091:istio-telemetry 服務的 grpc-mixer 端口 envoy 11 istio-proxy 56u IPv4 338473 0t0 TCP productpage-v1-745ffc55b7-2l2lw:47210->zipkin.istio-system.svc.cluster.local:9411 (ESTABLISHED) # 9411: zipkin 端口 envoy 11 istio-proxy 58u IPv4 338383 0t0 TCP productpage-v1-745ffc55b7-2l2lw:41564->172.33.84.8:9080 (ESTABLISHED) # 9080:details-v1 的 http 端口 envoy 11 istio-proxy 59u IPv4 338390 0t0 TCP productpage-v1-745ffc55b7-2l2lw:54410->172.33.78.5:9080 (ESTABLISHED) # 9080:reivews-v2 的 http 端口 envoy 11 istio-proxy 60u IPv4 338411 0t0 TCP productpage-v1-745ffc55b7-2l2lw:35200->172.33.84.5:9091 (ESTABLISHED) # 9091:istio-telemetry 服務的 grpc-mixer 端口 envoy 11 istio-proxy 62u IPv4 338497 0t0 TCP productpage-v1-745ffc55b7-2l2lw:34402->172.33.84.9:9080 (ESTABLISHED) # reviews-v1 的 http 端口 envoy 11 istio-proxy 63u IPv4 338525 0t0 TCP productpage-v1-745ffc55b7-2l2lw:50592->172.33.71.5:9080 (ESTABLISHED) # reviews-v3 的 http 端口 ``` 從輸出級過上可以驗證 Sidecar 是如何接管流量和與 istio-pilot 通信,及向 Mixer 做遙測數據匯聚的。感興趣的讀者可以再去看看其他幾個服務的 istio-proxy 容器中的 iptables 和端口信息。 ## 參考 - [SOFAMesh & SOFA MOSN—基于Istio構建的用于應對大規模流量的Service Mesh解決方案 - jimmysong.io](https://jimmysong.io/posts/sofamesh-and-mosn-proxy-sidecar-service-mesh-by-ant-financial/ - jimmysong.io) - [Init 容器 - Kubernetes 中文指南/云原生應用架構實踐手冊 - jimmysong.io](https://jimmysong.io/kubernetes-handbook/concepts/init-containers.html) - [JSONPath Support - kubernetes.io](https://kubernetes.io/docs/reference/kubectl/jsonpath/) - [iptables 命令使用說明 - wangchujiang.com](https://wangchujiang.com/linux-command/c/iptables.html) - [How To List and Delete Iptables Firewall Rules - digitalocean.com](https://www.digitalocean.com/community/tutorials/how-to-list-and-delete-iptables-firewall-rules) - [一句一句解說 iptables的詳細中文手冊 - cnblog.com](https://www.cnblogs.com/fhefh/archive/2011/04/04/2005249.html) - [常見iptables使用規則場景整理 - aliang.org](https://www.aliang.org/Linux/iptables.html)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看