Istio的運維-診斷工具(istio 系列五)

charlieroro發表於2020-06-09

Istio的運維-診斷工具

在參考官方文件的時候發現環境偶爾會出現問題,因此插入一章與除錯有關的內容,便於簡單問題的定位。涵蓋官方文件的診斷工具章節

使用istioctl命令列工具

首先可以通過日誌Introspection檢查各個元件,如果不足以支援問題定位,可以參考如下操作:

istioctl是一個可以用於除錯和診斷istio服務網格的工具。Istio專案為Bash和ZSH執行下的istioctl提供了自動補全功能。

建議安裝對應istio版本的istioctl

istioctl自動補全

  • 將如下內容新增到 ~/.bash_profile 檔案中

    [[ -r "/usr/local/etc/profile.d/bash_completion.sh" ]] && . "/usr/local/etc/profile.d/bash_completion.sh"
    
  • 使用bash時,將在tools命令中的istioctl.bash檔案拷貝到$HOME目錄下,然後執行如下操作即可

    $ source ~/istioctl.bash
    

檢視網格的狀態

可以使用istioctl proxy-statusistioctl ps命令檢視網格的狀態。如果輸出結果中缺少某個代理,說明該代理當前沒有連線到Pilot例項,因而無法接收到任何配置。如果狀態為stale,表示當前存在網路故障,或Pilot需要擴容。

獲取代理配置

可以使用istioctl proxy-configistioctl pc檢索代理配置資訊。

例如,使用如下方式可以檢索特定pod中的Envoy例項的叢集配置資訊。

$ istioctl proxy-config cluster <pod-name> [flags]

使用如下方式可以檢索特定pod中的Envoy例項的bootstrap配置資訊。

$ istioctl proxy-config bootstrap <pod-name> [flags]

使用如下方式可以檢索特定pod中的Envoy例項的listener(監聽器)配置資訊。

$ istioctl proxy-config listener <pod-name> [flags]

使用如下方式可以檢索特定pod中的Envoy例項的route(路由)配置資訊。

$ istioctl proxy-config route <pod-name> [flags]

使用如下方式可以檢索特定pod中的Envoy例項的endpoint (後端)配置資訊。

$ istioctl proxy-config endpoints <pod-name> [flags]

更多參見下一節除錯Envoy和istiod

除錯Envoy和istiod

istio提供了兩個非常有用的命令來診斷流量管理配置問題:proxy-statusproxy-configproxy-status可以獲取網格的概述並確定導致問題的代理。proxy-config可以檢查Envoy配置並診斷該問題。

如果要嘗試如下命令,可以:

獲取網格概況

通過proxy-status命令可以檢視網格的概況,瞭解是否有sidecar無法接收配置或無法保持同步。

如果某個代理沒有出現在輸出列表中,則說明該代理沒有連線到istiod例項,因此也無法接收任何配置資訊。狀態資訊如下:

  • SYNCED:表示Envoy確認了istiod發過來的配置
  • NOT SENT:表示istiod還沒有傳送配置到Envoy。通常時因為istiod當前沒有需要傳送的配置資訊
  • STALE:表示istiod傳送了一個更新到Envoy,但沒有接收到確認。通常表示Envoy和istiod之間的網路出現了問題,或istio本身出現了bug。
$ istioctl ps                                                                               
NAME                                                  CDS      LDS       EDS       RDS        PILOT                     VERSION
details-v1-78d78fbddf-psnmk.default                   SYNCED   SYNCED    SYNCED    SYNCED     istiod-788cf6c878-4pq5g   1.6.0
istio-ingressgateway-569669bb67-dsd5h.istio-system    SYNCED   SYNCED    SYNCED    NOT SENT   istiod-788cf6c878-4pq5g   1.6.0
productpage-v1-85b9bf9cd7-d8hm8.default               SYNCED   SYNCED    SYNCED    SYNCED     istiod-788cf6c878-4pq5g   1.6.0
prometheus-79878ff5fd-tjdxx.istio-system              SYNCED   SYNCED    SYNCED    SYNCED     istiod-788cf6c878-4pq5g   1.6.0
ratings-v1-6c9dbf6b45-xlf2q.default                   SYNCED   SYNCED    SYNCED    SYNCED     istiod-788cf6c878-4pq5g   1.6.0
reviews-v1-564b97f875-q5l9r.default                   SYNCED   SYNCED    SYNCED    SYNCED     istiod-788cf6c878-4pq5g   1.6.0
reviews-v2-568c7c9d8f-vcd94.default                   SYNCED   SYNCED    SYNCED    SYNCED     istiod-788cf6c878-4pq5g   1.6.0
reviews-v3-67b4988599-psllq.default                   SYNCED   SYNCED    SYNCED    SYNCED     istiod-788cf6c878-4pq5g   1.6.0
sleep-78484c89dd-fmxbc.default                        SYNCED   SYNCED    SYNCED    SYNCED     istiod-788cf6c878-4pq5g   1.6.0

檢索Envoy和istiod的差異

proxy-status加上proxy ID可以檢索Envoy載入的配置和istiod傳送的配置之間的差異,通過這種方式可以確定哪部分內容沒有被同步,並確定可能存在的問題。

下面的例子可以看到ingressgateway的listeners和routers配置都與istiod發過來的配置匹配,但clusters不匹配。

$ istioctl proxy-status details-v1-6dcc6fbb9d-wsjz4.default
--- Istiod Clusters
+++ Envoy Clusters
@@ -374,36 +374,14 @@
             "edsClusterConfig": {
                "edsConfig": {
                   "ads": {

                   }
                },
                "serviceName": "outbound|443||public-cr0bdc785ce3f14722918080a97e1f26be-alb1.kube-system.svc.cluster.local"
-            },
-            "connectTimeout": "1.000s",
-            "circuitBreakers": {
-               "thresholds": [
-                  {
-
-                  }
-               ]
-            }
-         }
-      },
-      {
-         "cluster": {
-            "name": "outbound|53||kube-dns.kube-system.svc.cluster.local",
-            "type": "EDS",
-            "edsClusterConfig": {
-               "edsConfig": {
-                  "ads": {
-
-                  }
-               },
-               "serviceName": "outbound|53||kube-dns.kube-system.svc.cluster.local"
             },
             "connectTimeout": "1.000s",
             "circuitBreakers": {
                "thresholds": [
                   {

                   }

Listeners Match
Routes Match

深入探究Envoy配置

proxy-config命令可以檢視一個Envoy例項的配置,用於定位無法通過檢視istio配置和使用者資源發現的問題。例如,使用如下命令可以獲取特定pod的clusters,listeners或routes概要。注:首先通過istioctl ps檢視出不匹配的代理,然後使用istioctl pc檢視具體的不匹配的資訊。

$ istioctl proxy-config cluster -n istio-system istio-ingressgateway-7d6874b48f-qxhn5
SERVICE FQDN                                           PORT    SUBSET  DIRECTION  TYPE
BlackHoleCluster                                       -       -       -          STATIC
agent                                                  -       -       -          STATIC
details.default.svc.cluster.local                      9080    -       outbound   EDS
istio-ingressgateway.istio-system.svc.cluster.local    80      -       outbound   EDS
istio-ingressgateway.istio-system.svc.cluster.local    443     -       outbound   EDS
istio-ingressgateway.istio-system.svc.cluster.local    15021   -       outbound   EDS
istio-ingressgateway.istio-system.svc.cluster.local    15443   -       outbound   EDS
istiod.istio-system.svc.cluster.local                  443     -       outbound   EDS
istiod.istio-system.svc.cluster.local                  853     -       outbound   EDS
istiod.istio-system.svc.cluster.local                  15010   -       outbound   EDS
istiod.istio-system.svc.cluster.local                  15012   -       outbound   EDS
istiod.istio-system.svc.cluster.local                  15014   -       outbound   EDS
kube-dns.kube-system.svc.cluster.local                 53      -       outbound   EDS
kube-dns.kube-system.svc.cluster.local                 9153    -       outbound   EDS
kubernetes.default.svc.cluster.local                   443     -       outbound   EDS
...                                                                               
productpage.default.svc.cluster.local                  9080    -       outbound   EDS
prometheus.istio-system.svc.cluster.local              9090    -       outbound   EDS
prometheus_stats                                       -       -       -          STATIC
ratings.default.svc.cluster.local                      9080    -       outbound   EDS
reviews.default.svc.cluster.local                      9080    -       outbound   EDS
sds-grpc                                               -       -       -          STATIC
xds-grpc                                               -       -       -          STRICT_DNS
zipkin                                                 -       -       -          STRICT_DNS

為了除錯Envoy,首先需要理解Envoy的clusters/listeners/routes/endpoints,以及它們之間是如何互動的。下面將使用帶有-o json和篩選標誌的proxy config命令來跟蹤Envoy,因為它決定在哪裡將請求從productpage pod傳送到reviews pod的 reviews:9080

  1. 如果請求了一個pod的listener概要,可以看到istio生成了如下listeners:

    • 一個0.0.0.0:15006的listener,用於接收到pod的入站流量;以及一個 0.0.0.0:15001的listener,用於接收所有到pod的出站流量,然後將請求交給一個 virtual listener。
    • 每個kubernetes service IP都對應一個virtual listener,非HTTP的listener用於出站的TCP/HTTPS流量
    • pod IP中的virtual listener暴露了接收入站流量的埠
    • 0.0.0.0的HTTP型別的virtual listener,用於出站的HTTP流量

    Istio使用的資訊如下:

    Port Protocol Used by Description
    15000 TCP Envoy Envoy admin port (commands/diagnostics)
    15001 TCP Envoy √ Envoy Outbound
    15006 TCP Envoy √ Envoy Inbound
    15020 HTTP Envoy Istio agent Prometheus telemetry
    15021 HTTP Envoy Health checks
    15090 HTTP Envoy Envoy Prometheus telemetry
    15010 GRPC Istiod XDS and CA services (plaintext)
    15012 GRPC Istiod XDS and CA services (TLS)
    8080 HTTP Istiod Debug interface
    443 HTTPS Istiod Webhooks
    15014 HTTP Mixer, Istiod Control plane monitoring
    15443 TLS Ingress and Egress Gateways SNI
    9090 HTTP Prometheus Prometheus
    42422 TCP Mixer Telemetry - Prometheus
    15004 HTTP Mixer, Pilot Policy/Telemetry - mTLS
    9091 HTTP Mixer Policy/Telemetry

    可以看到TYPE欄位是沒有HTTPS的,HTTPS作為TCP型別。下面是productpage的listeners,刪減了部分資訊。10.84開頭的是各個kubernetes service的CLUSTER-IP,以172.20開頭的是kubernetes的node IP,以nodePort方式暴露服務。

    $ istioctl proxy-config listeners productpage-v1-85b9bf9cd7-d8hm8.default
    ADDRESS          PORT     TYPE    
    0.0.0.0          443      TCP     <--+
    10.84.71.37      443      TCP        |
    10.84.223.189    443      TCP        |
    10.84.100.226    15443    TCP        |
    10.84.121.154    443      TCP        |
    10.84.142.44     443      TCP        | #從0.0.0.0_15001相關IP:PORT上接收出站的non-HTTP流量
    10.84.155.219    443      TCP        |
    172.20.127.212   9100     TCP        |
    10.84.205.103    443      TCP        | 
    10.84.167.116    443      TCP        |
    172.20.127.211   9100     TCP     <--+
    10.84.113.197    9979     HTTP+TCP<--+
    0.0.0.0          9091     HTTP+TCP   |
    10.84.30.227     9092     HTTP+TCP   |
    10.84.108.37     8080     HTTP+TCP   |
    10.84.158.64     8443     HTTP+TCP   |
    10.84.202.185    8080     HTTP+TCP   |
    10.84.21.252     8443     HTTP+TCP   |
    10.84.215.56     8443     HTTP+TCP   |
    0.0.0.0          60000    HTTP+TCP   | # 從0.0.0.0_15001的相關埠上接收出站的HTTP+TCP流量
    10.84.126.74     8778     HTTP+TCP   |
    10.84.126.74     8080     HTTP+TCP   |
    10.84.123.207    8080     HTTP+TCP   |
    10.84.30.227     9091     HTTP+TCP   |
    10.84.229.5      8080     HTTP+TCP<--+
    0.0.0.0          9080     HTTP+TCP     # 從 0.0.0.0_15006 上接收所有到9080的入站流量
    0.0.0.0          15001    TCP          # 從IP tables接收pod的所有出站流量,並移交給虛擬偵聽器
    0.0.0.0          15006    HTTP+TCP     # Envoy 入站
    0.0.0.0          15090    HTTP         # Envoy Prometheus 遙測
    0.0.0.0          15021    HTTP         # 健康檢查
    

    下面是productpage Pod中實際監聽的埠資訊,與上述對應。

    $ ss -ntpl                                 
    State          Recv-Q        Send-Q        Local Address:Port          Peer Address:Port
    LISTEN         0             128                 0.0.0.0:15090              0.0.0.0:*
    LISTEN         0             128               127.0.0.1:15000              0.0.0.0:*
    LISTEN         0             128                 0.0.0.0:9080               0.0.0.0:*
    LISTEN         0             128                 0.0.0.0:15001              0.0.0.0:*
    LISTEN         0             128                 0.0.0.0:15006              0.0.0.0:*
    LISTEN         0             128                 0.0.0.0:15021              0.0.0.0:*
    LISTEN         0             128                       *:15020                    *:* 
    
  2. 從上述輸出概要中可以看到每個sidecar都有一個繫結到 0.0.0.0:15006的listener,IP tables會將所有入站的Pod流量匯入該listener;以及一個繫結到 0.0.0.0:15001的listener,IP tables會將所有出站流量匯入該listener,該listener有一個欄位useOriginalDst設定為true,表示會使用最佳匹配原始目的地的方式將請求分發到virtual listener,如果沒有找到任何virtual listener,將會直接傳送到連線目的地的PassthroughCluster

    $ istioctl pc listener productpage-v1-85b9bf9cd7-d8hm8.default --port 15001 -o json
    [
        {
            "name": "virtualOutbound",
            "address": {
                "socketAddress": {
                    "address": "0.0.0.0",
                    "portValue": 15001
                }
            },
            "filterChains": [
                {
                    "filters": [
                        {
                            "name": "istio.stats",
                            "typedConfig": {
                                "@type": "type.googleapis.com/udpa.type.v1.TypedStruct",
                                "typeUrl": "type.googleapis.com/envoy.extensions.filters.network.wasm.v3.Wasm",
                                "value": {
                                    "config": {
                                        "configuration": "{\n  \"debug\": \"false\",\n  \"stat_prefix\": \"istio\"\n}\n",
                                        "root_id": "stats_outbound",
                                        "vm_config": {
                                            "code": {
                                                "local": {
                                                    "inline_string": "envoy.wasm.stats"
                                                }
                                            },
                                            "runtime": "envoy.wasm.runtime.null",
                                            "vm_id": "tcp_stats_outbound"
                                        }
                                    }
                                }
                            }
                        },
                        {
                            "name": "envoy.tcp_proxy",
                            "typedConfig": {
                                "@type": "type.googleapis.com/envoy.config.filter.network.tcp_proxy.v2.TcpProxy",
                                "statPrefix": "PassthroughCluster",
                                "cluster": "PassthroughCluster",
                                "accessLog": [
                                    {
                                        "name": "envoy.file_access_log",
                                        "typedConfig": {
                                            "@type": "type.googleapis.com/envoy.config.accesslog.v2.FileAccessLog",
                                            "path": "/dev/stdout",
                                            "format": "[%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" %RESPONSE_CODE% %RESPONSE_FLAGS% \"%DYNAMIC_METADATA(istio.mixer:status)%\" \"%UPSTREAM_TRANSPORT_FAILURE_REASON%\" %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% \"%REQ(X-FORWARDED-FOR)%\" \"%REQ(USER-AGENT)%\" \"%REQ(X-REQUEST-ID)%\" \"%REQ(:AUTHORITY)%\" \"%UPSTREAM_HOST%\" %UPSTREAM_CLUSTER% %UPSTREAM_LOCAL_ADDRESS% %DOWNSTREAM_LOCAL_ADDRESS% %DOWNSTREAM_REMOTE_ADDRESS% %REQUESTED_SERVER_NAME% %ROUTE_NAME%\n"
                                        }
                                    }
                                ]
                            }
                        }
                    ],
                    "name": "virtualOutbound-catchall-tcp"
                }
            ],
            "useOriginalDst": true,
            "trafficDirection": "OUTBOUND"
        }
    ]
    
  3. 應用的請求為一個出站HTTP請求,會到達9080埠,這意味著請求將傳遞給0.0.0.0:9080 virtual listener。該listener會檢視其RDS中配置的路由。這種情況下會查詢istiod配置的RDS的9080路由

    $ istioctl pc listener productpage-v1-85b9bf9cd7-d8hm8.default  -o json --address 0.0.0.0 --port 9080
    [
        {
            "name": "0.0.0.0_9080",
            "address": {
                "socketAddress": {
                    "address": "0.0.0.0",
                    "portValue": 9080
                }
            },
            "filterChains": [
                {
                    "filterChainMatch": {
                        "applicationProtocols": [
                            "http/1.0",
                            "http/1.1",
                            "h2c"
                        ]
                    },
                    "filters": [
                        {
                            "name": "envoy.http_connection_manager",
                            "typedConfig": {
                                "@type": "type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager",
                                "statPrefix": "outbound_0.0.0.0_9080",
                                "rds": {
                                    "configSource": {
                                        "ads": {}
                                    },
                                    "routeConfigName": "9080"
                                },
    ...
    ]
    
  4. 9080的路由配置中每個服務只有一個virtual host。由於應用的請求會傳遞到reviews服務,因此Envoy會選擇請求與域相匹配的virtual host。一旦匹配到域,Envoy會檢視匹配請求的第一個路由。下面場景中,由於沒有配置任何高階路由,因此只有一條可以匹配的路由,該路由告訴Envoy將請求傳送到 outbound|9080||reviews.default.svc.cluster.local叢集。

    $ istioctl proxy-config routes productpage-v1-85b9bf9cd7-d8hm8.default  --name 9080 -o json
    [
        {
            "name": "9080",
            "virtualHosts": [
    ...
                {
                    "name": "reviews.default.svc.cluster.local:9080", 
                    "domains": [
                        "reviews.default.svc.cluster.local",
                        "reviews.default.svc.cluster.local:9080",
                        "reviews",
                        "reviews:9080",
                        "reviews.default.svc.cluster",
                        "reviews.default.svc.cluster:9080",
                        "reviews.default.svc",
                        "reviews.default.svc:9080",
                        "reviews.default",
                        "reviews.default:9080",
                        "10.84.110.152",
                        "10.84.110.152:9080"
                    ],
                    "routes": [
                        {
                            "name": "default",
                            "match": {
                                "prefix": "/"
                            },
                            "route": {
                                "cluster": "outbound|9080||reviews.default.svc.cluster.local",
                                "timeout": "0s",
                                "retryPolicy": {
                                    "retryOn": "connect-failure,refused-stream,unavailable,cancelled,retriable-status-codes",
                                    "numRetries": 2,
                                    "retryHostPredicate": [
                                        {
                                            "name": "envoy.retry_host_predicates.previous_hosts"
                                        }
                                    ],
                                    "hostSelectionRetryMaxAttempts": "5",
                                    "retriableStatusCodes": [
                                        503
                                    ]
                                },
                                "maxGrpcTimeout": "0s"
                            },
                            "decorator": {
                                "operation": "reviews.default.svc.cluster.local:9080/*"
                            }
                        }
                    ],
                    "includeRequestAttemptCount": true
                }
            ],
            "validateClusters": false
        }
    ]
    
  5. cluster的配置用於從istiod中檢索後端。Envoy會使用serviceName作為key在Endpoints列表中進行查詢,並將請求傳遞到這些後端。

    $  istioctl pc cluster productpage-v1-85b9bf9cd7-d8hm8.default  --fqdn reviews.default.svc.cluster.local -o json
    [
        {
           ...
            "name": "outbound|9080||reviews.default.svc.cluster.local",
            "type": "EDS",
            "edsClusterConfig": {
                "edsConfig": {
                    "ads": {}
                },
                "serviceName": "outbound|9080||reviews.default.svc.cluster.local"
            },
            "connectTimeout": "10s",
            "circuitBreakers": {
                "thresholds": [
                    {
                        "maxConnections": 4294967295,
                        "maxPendingRequests": 4294967295,
                        "maxRequests": 4294967295,
                        "maxRetries": 4294967295
                    }
                ]
            },
            "filters": [
                {
                    "name": "istio.metadata_exchange",
                    "typedConfig": {
                        "@type": "type.googleapis.com/udpa.type.v1.TypedStruct",
                        "typeUrl": "type.googleapis.com/envoy.tcp.metadataexchange.config.MetadataExchange",
                        "value": {
                            "protocol": "istio-peer-exchange"
                        }
                    }
                }
            ]
        }
    ]
    
  6. 使用proxy-config endpoint命令檢視本叢集中當前可用的後端

    $ istioctl pc endpoint productpage-v1-85b9bf9cd7-d8hm8.default --cluster "outbound|9080||reviews.default.svc.cluster.local"
    ENDPOINT            STATUS      OUTLIER CHECK     CLUSTER
    10.80.3.55:9080     HEALTHY     OK                outbound|9080||reviews.default.svc.cluster.local
    10.80.3.56:9080     HEALTHY     OK                outbound|9080||reviews.default.svc.cluster.local
    10.80.3.58:9080     HEALTHY     OK                outbound|9080||reviews.default.svc.cluster.local
    

流量方向為:listener(應用出站port)->route(routeConfigName)->cluster(domain)->endpoint(serviceName)

檢查bootstrap配置

到目前為止已經檢視了istiod的大部分配置,然而,Envoy需要一些如哪裡可以發現istiod的bootstrap配置,使用如下方式檢視:

$  istioctl proxy-config bootstrap -n istio-system istio-ingressgateway-569669bb67-dsd5h.istio-system
{
    "bootstrap": {
        "node": {
            "id": "router~10.83.0.14~istio-ingressgateway-569669bb67-dsd5h.istio-system~istio-system.svc.cluster.local",
            "cluster": "istio-ingressgateway",
            "metadata": {
                    "CLUSTER_ID": "Kubernetes",
                    "CONFIG_NAMESPACE": "istio-system",
                    "EXCHANGE_KEYS": "NAME,NAMESPACE,INSTANCE_IPS,LABELS,OWNER,PLATFORM_METADATA,WORKLOAD_NAME,MESH_ID,SERVICE_ACCOUNT,CLUSTER_ID",
                    "INSTANCE_IPS": "10.83.0.14,fe80::6871:95ff:fe5b:9e3e",
                    "ISTIO_PROXY_SHA": "istio-proxy:12cfbda324320f99e0e39d7c393109fcd824591f",
                    "ISTIO_VERSION": "1.6.0",
                    "LABELS": {
                                "app": "istio-ingressgateway",
                                "chart": "gateways",
                                "heritage": "Tiller",
                                "istio": "ingressgateway",
                                "pod-template-hash": "569669bb67",
                                "release": "istio",
                                "service.istio.io/canonical-name": "istio-ingressgateway",
                                "service.istio.io/canonical-revision": "latest"
                            },
                    "MESH_ID": "cluster.local",
                    "NAME": "istio-ingressgateway-569669bb67-dsd5h",
                    "NAMESPACE": "istio-system",
                    "OWNER": "kubernetes://apis/apps/v1/namespaces/istio-system/deployments/istio-ingressgateway",
...
                    "ROUTER_MODE": "sni-dnat",
                    "SDS": "true",
                    "SERVICE_ACCOUNT": "istio-ingressgateway-service-account",
                    "TRUSTJWT": "true",
                    "WORKLOAD_NAME": "istio-ingressgateway"
                },
...
}

校驗到istiod的連通性

服務網格中的所有Envoy代理容器都應該連線到istiod,使用如下步驟測試:

  1. 建立一個sleep pod

    $ kubectl create namespace foo
    $ kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml) -n foo
    
  2. 使用curl測試到istiod的連通性。下面呼叫v1註冊API,使用預設的istiod配置引數,並啟用雙向TLS認證

    $ kubectl exec $(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name}) -c sleep -n foo -- curl -sS istiod.istio-system:15014/debug/endpointz
    

通過istioctl的輸出理解網格

如下內容是一個實驗特性,僅用於評估

istio 1.3中包含一個istioctl experimental describe命令。該CLI命令提供瞭解影響pod的配置所需的資訊。本節展示如何使用該experimental 子命令檢視一個pod是否在網格中,以及檢查該pod的配置。該命令的基本使用方式為:

$ istioctl experimental describe pod <pod-name>[.<namespace>] #或
$ istioctl experimental describe pod <pod-name> -n <namespace> 

校驗pod是否在網格中

如果一個pod不在網格中,istioctl describe會顯示一個告警資訊,此外,如果pod缺少istio需要的配置時也會給出告警資訊。

$ istioctl experimental describe pod  mutatepodimages-7575797d95-qn7p5
Pod: mutatepodimages-7575797d95-qn7p5
   Pod does not expose ports
WARNING: mutatepodimages-7575797d95-qn7p5 is not part of mesh; no Istio sidecar
--------------------
Error: failed to execute command on sidecar: error 'execing into mutatepodimages-7575797d95-qn7p5/default istio-proxy container: container istio-proxy is not valid for pod mutatepodimages-7575797d95-qn7p5

如果一個pod在網格中,則不會產生告警。

$ istioctl x describe pod ratings-v1-6c9dbf6b45-xlf2q
Pod: ratings-v1-6c9dbf6b45-xlf2q
   Pod Ports: 9080 (details), 15090 (istio-proxy)
--------------------
Service: details
   Port: http 9080/HTTP targets pod port 9080
Pilot reports that pod enforces HTTP/mTLS and clients speak HTTP

輸出為:

  • pod的服務容器埠,上述為ratings的9080埠
  • pod中的istio-proxy埠,15090
  • pod服務使用的協議,9080埠的http協議
  • pod設定的mutual TLS

校驗destination rule配置

可以使用istioctl describe檢查應用到一個pod的destination rule。例如執行如下命令部署destination rule

$ kubectl apply -f samples/bookinfo/networking/destination-rule-all-mtls.yaml

檢視ratings pod

$ export RATINGS_POD=$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')
$ istioctl x describe pod $RATINGS_POD
Pod: ratings-v1-6c9dbf6b45-xlf2q
   Pod Ports: 9080 (ratings), 15090 (istio-proxy)
--------------------
Service: ratings
   Port: http 9080/HTTP targets pod port 9080
DestinationRule: ratings for "ratings"
   Matching subsets: v1
      (Non-matching subsets v2,v2-mysql,v2-mysql-vm)
   Traffic Policy TLS Mode: ISTIO_MUTUAL
Pilot reports that pod enforces HTTP/mTLS and clients speak mTLS

輸出為:

  • 應用到ratings 服務的ratings destination rule
  • 匹配pod的ratings destination rule,上述為v1
  • destination rule定義的其他subset
  • pod接收HTTP或mutual TLS,但客戶端使用mutual TLS

校驗virtual service配置

部署如下virtual service

$ kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml

檢視v1版本的reviews服務:

$ export REVIEWS_V1_POD=$(kubectl get pod -l app=reviews,version=v1 -o jsonpath='{.items[0].metadata.name}')
istioctl x describe pod $REVIEWS_V1_POD
$ istioctl x describe pod $REVIEWS_V1_POD
Pod: reviews-v1-564b97f875-q5l9r
   Pod Ports: 9080 (reviews), 15090 (istio-proxy)
--------------------
Service: reviews
   Port: http 9080/HTTP targets pod port 9080
DestinationRule: reviews for "reviews"
   Matching subsets: v1
      (Non-matching subsets v2,v3)
   Traffic Policy TLS Mode: ISTIO_MUTUAL
VirtualService: reviews
   1 HTTP route(s)

輸出結果與前面的ratings pod型別,但多了到pod的virtual service路由。

istioctl describe命令不僅僅顯示了影響pod的virtual service。如果一個virtual service配置的host為一個pod,但流量不可達,會輸出告警資訊,這種請求可能發生在當一個virtual service如果沒有可達的pod subset時。例如:

$ export REVIEWS_V2_POD=$(kubectl get pod -l app=reviews,version=v2 -o jsonpath='{.items[0].metadata.name}')
istioctl x describe pod $REVIEWS_V2_POD
[root@bastion istio-1.6.0]# istioctl x describe pod $REVIEWS_V2_POD
Pod: reviews-v2-568c7c9d8f-vcd94
...
VirtualService: reviews
   WARNING: No destinations match pod subsets (checked 1 HTTP routes)
      Route to non-matching subset v1 for (everything)

告警資訊給出導致問題的原因,檢查的路由數目,以及其他路由資訊。例如,由於virtual service將所有的流量到匯入了v1 subset,因此v2 pod無法接收到任何流量。

如果刪除如下destination rule:

$ kubectl delete -f samples/bookinfo/networking/destination-rule-all-mtls.yaml

可以看到如下資訊:

$ istioctl x describe pod $REVIEWS_V1_POD
Pod: reviews-v1-564b97f875-q5l9r
   Pod Ports: 9080 (reviews), 15090 (istio-proxy)
--------------------
Service: reviews
   Port: http 9080/HTTP targets pod port 9080
VirtualService: reviews
   WARNING: No destinations match pod subsets (checked 1 HTTP routes)
      Warning: Route to subset v1 but NO DESTINATION RULE defining subsets!

輸出展示了已刪除destination rule,但沒有刪除依賴它的virtual service。該virtual service將流量路由到v1 subset,但沒有定義v1 subset的destination rule。因此流量無法分發到v1版本的pod。

恢復環境:

$ kubectl apply -f samples/bookinfo/networking/destination-rule-all-mtls.yaml

校驗流量路由

istioctl describe也可以展示流量權重。如理如下命令會將90%的流量匯入reviews服務的v1 subset,將10%的流量匯入reviews服務的v2 subset。

$ kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-90-10.yaml

檢視reviews v1` pod:

$ istioctl x describe pod $REVIEWS_V1_POD
...
VirtualService: reviews
   Weight 90%

輸出顯示90%的reviews服務的流量匯入到了v1 subset中。

部署其他型別的路由,如部署指定HTTP首部的路由:

$ kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-jason-v2-v3.yaml

再次檢視pod:

$ istioctl x describe pod $REVIEWS_V1_POD
...
VirtualService: reviews
   WARNING: No destinations match pod subsets (checked 2 HTTP routes)
      Route to non-matching subset v2 for (when headers are end-user=jason)
      Route to non-matching subset v3 for (everything)

由於檢視了位於v1 subset的pod,而virtual service將包含 end-user=jason 的流量分發給v2 subset,其他流量分發給v3 subset,v1 subset沒有任何流量匯入,此時會輸出告警資訊。

檢查strict mutual TLS(官方文件待更新)

根據mutual TLS遷移指南,可以給ratings服務啟用strict mutual TLS。

$ kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: ratings-strict
spec:
  selector:
    matchLabels:
      app: ratings
  mtls:
    mode: STRICT
EOF

執行如下命令檢視ratings pod,輸出顯示ratings pod已經使用mutual TLS防護。

$ istioctl x describe pod $RATINGS_POD
Pilot reports that pod enforces mTLS and clients speak mTLS

有時,將mutual TLS切換位STRICT模式時會對部署的元件造成影響,通常是因為destination rule不匹配新配置造成的。例如,如果配置Bookinfo客戶端不使用mutualTLS,而使用明文的HTTP destination rules:

$ kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml

如果在瀏覽器傻瓜開啟Bookinfo,會顯示Ratings service is currently unavailable,使用如下命令檢視原因:

$ istioctl x describe pod $RATINGS_POD
...
WARNING Pilot predicts TLS Conflict on ratings-v1-f745cf57b-qrxl2 port 9080 (pod enforces mTLS, clients speak HTTP)
  Check DestinationRule ratings/default and AuthenticationPolicy ratings-strict/default

輸出中有一個描述destination rule和authentication policy衝突的告警資訊。

使用如下方式恢復:

$ kubectl apply -f samples/bookinfo/networking/destination-rule-all-mtls.yaml

解除安裝

$ kubectl delete -f samples/bookinfo/platform/kube/bookinfo.yaml
$ kubectl delete -f samples/bookinfo/networking/bookinfo-gateway.yaml
$ kubectl delete -f samples/bookinfo/networking/destination-rule-all-mtls.yaml
$ kubectl delete -f samples/bookinfo/networking/virtual-service-all-v1.yaml

使用istioctl analyse診斷配置

istioctl analyze是一個可以探測istio配置中潛在錯誤的診斷工具,它可以診斷現有的叢集或一組本地配置檔案,會同時診斷這兩者。

可以使用如下方式診斷當前的kubernetes:

$ istioctl analyze --all-namespaces

例如,如果某些名稱空間沒有啟用istiod注入,會列印如下告警資訊:

Warn [IST0102] (Namespace openshift) The namespace is not enabled for Istio injection. Run 'kubectl label namespace openshift istio-injection=enabled' to enable it, or 'kubectl label namespace openshift istio-injection=disabled' to explicitly mark it as not needing injection

分析現有的叢集/本地檔案或二者

上述的例子用於分析一個存在的叢集,但該工具也可以支援分析本地kubernetes yaml的配置檔案集,或同時分析本地檔案和叢集。當分析一個本地檔案集時,這些檔案集應該是完全自包含的。通常用於分析需要部署到叢集的一個完整的配置檔案集。

分析特定的本地kubernetes yaml檔案集:

$ istioctl analyze --use-kube=false a.yaml b.yaml

分析當前目錄中的所有yaml檔案:

$ istioctl analyze --use-kube=false *.yaml

模擬將當前目錄中的files部署到當前叢集中:

$ istioctl analyze *.yaml

使用istioctl analyze --help命令檢視完整的選項。更多analyse的使用參見Q&A.

元件內省

Istio元件是用一個靈活的內省框架構建的,它使檢查和操作執行元件的內部狀態變得簡單。元件會開放一個埠,用於通過web瀏覽器的互動式檢視獲取元件的狀態,或使用外部工具通過REST訪問。

Mixer, PilotGalley 都實現了ControlZ 功能(1.6版本可以檢視istiod)。當啟用這些元件時將記錄一條訊息,指示要連線的IP地址和埠,以便與ControlZ互動。

2018-07-26T23:28:48.889370Z     info    ControlZ available at 100.76.122.230:9876

可以使用如下命令進行埠轉發,類似kubectl的port-forward,用於遠端訪問。

$ istioctl dashboard controlz <podname> -n <namespaces>

元件日誌

日誌作用域

元件的日誌按照作用域進行分類。取決於元件提供的功能,不同的元件有不同的作用域。所有的元件都有一個default的作用域,用於未分類的日誌訊息。

各個元件的日誌作用域參見:reference documentation

每個作用域對應一個唯一的日誌級別:

  1. none
  2. error
  3. warning
  4. info
  5. debug

其中none表示沒有劃分作用域的輸出,debug會最大化輸出。預設的作用域為info,用於在一般情況下為istio提供何時的日誌輸出。

可以使用 --log_output_level 控制輸出級別:

控制輸出

日誌資訊通常會傳送到元件的標準輸出流中。 --log_target選項可以將輸出重定向到任意(數量的)位置,可以通過逗號分割的列表給出檔案系統的路徑。stdoutstderr分別表示標準輸出和標準錯誤輸出流。

日誌滾動

istio元件能夠自動管理日誌滾動,將大的日誌切分為小的日誌檔案。--log_rotate選項允許指定用於滾動的基本檔名。派生的名稱將用於單個日誌檔案。

--log_rotate_max_age選項指定檔案發生滾動前的最大時間(天為單位),--log_rotate_max_size選項用於指定檔案滾動發生前的最大檔案大小(MB為單位), --log_rotate_max_backups選項控制儲存的滾動檔案的最大數量,超過該值的老檔案會被自動刪除。

元件除錯

--log_caller--log_stacktrace_level選項可以控制日誌資訊是否包含程式設計師級別的資訊。在跟蹤元件bug時很有用,但日常用不到。

相關文章