Istio 的配置分析

charlieroro發表於2020-09-07

Istio 的配置分析

Analyzer 的訊息格式

istioctl analyze 命令提供瞭如下訊息格式:

<level> [<code>] (<affected-resource>) <message-details>

欄位可以展開為:

<resource-kind> <resource-name>.<resource-namespace>

例如:

Error [IST0101] (VirtualService httpbin.default) Referenced gateway not found: "httpbin-gateway-bogus"

<message-details>欄位包含關於解決問題的詳細資訊。當對於叢集範圍的資源(如namespace)時,會忽略namespace字首。

ConflictingMeshGatewayVirtualServiceHosts

Message Name ConflictingMeshGatewayVirtualServiceHosts
Message Code IST0109
Description Conflicting hosts on VirtualServices associated with mesh gateway
Level Error

當Istio檢測到virtual service資源之間存在重疊導致的衝突時,會出現該訊息。例如,定義了多個使用相同的主機名的virtual service,並將其附加到網格閘道器上,這樣就會產生上述錯誤。注意,Istio支援合併附加到ingress閘道器的virtual services。

問題解決

可以使用如下動作來解決該問題:

  • 將多個衝突的virtual service合併為一個
  • 將附加到一個網格閘道器的多個virtual service的主機名配置為唯一的
  • 通過exportTo欄位將資源指定到某個指定的名稱空間中

舉例

例如,team1名稱空間中的 productpage virtual service 與team2名稱空間中的custom virtual service因為同時設定瞭如下條件導致了衝突:

  • 都附加到了預設的mesh閘道器上(沒有指定使用者閘道器)
  • 定義了相同的host productpage.default.svc.cluster.local
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: productpage
  namespace: team-1
spec:
  hosts:
  - productpage.default.svc.cluster.local
  http:
  - route:
    - destination:
        host: productpage
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: custom
  namespace: team-2
spec:
  hosts:
  - productpage.default.svc.cluster.local
  http:
  - route:
    - destination:
        host: productpage.team-2.svc.cluster.local
---

可以通過設定exportTo欄位來解決該問題,這樣,virtual service的範圍就限制於其所在的名稱空間。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: productpage
  namespace: team-1
spec:
  exportTo:
  - "." #當前名稱空間
  hosts:
  - productpage.default.svc.cluster.local
  http:
  - route:
    - destination:
        host: productpage
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: custom
  namespace: team-2
spec:
  exportTo:
  - "." #當前名稱空間
  hosts:
  - productpage.default.svc.cluster.local
  http:
  - route:
    - destination:
        host: productpage.team-2.svc.cluster.local
---

ConflictingSidecarWorkloadSelectors

Message Name ConflictingSidecarWorkloadSelectors
Message Code IST0110
Description A Sidecar resource selects the same workloads as another Sidecar resource
Level Error

當一個名稱空間中的多個sidecar選擇相同的負載例項時會出現該訊息,可能導致不可預知的行為。更多資訊參見Sidecar資源。

為了解決該問題,需要一個名稱空間中的Sidecar負載選擇器(workloadSelector)選擇的負載例項不會出現重疊。

GatewayPortNotOnWorkload

Message Name GatewayPortNotOnWorkload
Message Code IST0104
Description Unhandled gateway port
Level Warning

當一個閘道器(通常是istio-ingressgateway)提供的埠並不在閘道器選擇的kubernetes service負載上時會出現該訊息。

例如,Istio的配置包含如下值:

# Gateway with bogus port

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: httpbin-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
  - port:
      number: 8004
      name: http2
      protocol: HTTP
    hosts:
    - "*"

在上面例子中會出現GatewayPortNotOnWorkload訊息,因為一個預設的IngressGateway僅會開啟埠 80, 443, 31400, 和15443,並不包括8004。使用istioctl analyze分析的結果如下:

# istioctl analyze
Warn [IST0104] (Gateway httpbin-gateway.default) The gateway refers to a port that is not exposed on the workload (pod selector istio=ingressgateway; port 8004)
Info [IST0118] (Service mutatepodimages.default) Port name  (port: 443, targetPort: 8443) doesn't follow the naming convention of Istio port.
Error: Analyzers found issues when analyzing namespace: default.

為了解決該問題,可以修改閘道器的配置,使用一個有效的負載埠,並重新部署即可。

InternalError

Message Name InternalError
Message Code IST0001
Description There was an internal error in the toolchain. This is almost always a bug in the implementation.
Level Error

極有可能是因為Istio的內部錯誤造成的。可以參見Istio的issue頁面來了解會提交問題。

IstioProxyImageMismatch

Message Name IstioProxyImageMismatch
Message Code IST0105
Description The image of the Istio proxy running on the pod does not match the image defined in the injection configuration.
Level Warning

當一個Pod出現如下條件時會發生該問題:

  • 啟用sidecar自動注入(預設是啟用的,除非在安裝時禁用)
  • pod執行在一個啟用sidecar注入的名稱空間中(給名稱空間打上標籤istio-injection=enabled)
  • 執行在sidecar中的代理版本與自動注入的版本不匹配

該問題通常會發生在更新Istio的控制面之後,在升級Istio後,所有帶Istio sidecar執行的負載必須重啟來注入新版本的sidecar。

為了解決該問題,可以通過滾動策略來重新部署應用的sidecar。對於kubernetes的deployment:

  1. 如果使用kubernetes 1.15或更高版本,可以執行 kubectl rollout restart <my-deployment>來觸發滾動
  2. 或者,可以修改deployment的template欄位來強制觸發滾動。這通常是通過在模板的pod定義中新增諸如force-redeploy = <current-timestamp>之類的標籤來觸發deployment滾動的。

JwtFailureDueToInvalidServicePortPrefix

Message Name JwtFailureDueToInvalidServicePortPrefix
Message Code IST0119
Description Authentication policy with JWT targets Service with invalid port specification.
Level Warning

當一個認證策略使用JWT認證時,而目標kubernetes service配置不正確時會出現該訊息。正確的kubernetes service要求port使用http|http2|https作為字首來命名(參見Protocol Selection),並且協議為TCP。預設的協議為TCP。

舉例

當叢集中存在如下策略時:

apiVersion: authentication.istio.io/v1alpha1
kind: Policy
metadata:
  name: secure-httpbin
  namespace: default
spec:
  targets:
    - name: httpbin
  origins:
    - jwt:
        issuer: "testing@secure.istio.io"
        jwksUri: "https://raw.githubusercontent.com/istio/istio-1.4/security/tools/jwt/samples/jwks.json"

target的service配置如下:

apiVersion: v1
kind: Service
metadata:
  name: httpbin
  namespace: default
  labels:
    app: httpbin
spec:
  ports:
  - name: svc-8080
    port: 8080
    targetPort: 80
    protocol: TCP
  selector:
    app: httpbin

在上面例子中,port svc-8080並沒有遵守語法: name: <http|https|http2>[-<suffix>]。將會接收到如下訊息:

Warn [IST0119] (Policy secure-httpbin.default) Authentication policy with JWT targets Service with invalid port specification (port: 8080, name: svc-8080, protocol: TCP, targetPort: 80).

JWT認證僅支援http,https或http2,修改Service 埠名,使其遵守 <http|https|http2>[-<suffix>]即可。

MisplacedAnnotation

Message Name MisplacedAnnotation
Message Code IST0107
Description An Istio annotation is applied to the wrong kind of resource.
Level Warning

當Istio的annotation附加到一個無效的資源或錯誤的位置上時會出現該訊息。例如,如果建立一個deployment,然後將annotation附加到該deployment,而不是pods上時就會出現該錯誤提示。

將annotation放到正確的位置即可修改該問題。

MTLSPolicyConflict

Message Name MTLSPolicyConflict
Message Code IST0113
Description A DestinationRule and Policy are in conflict with regards to mTLS.
Level Error

當一個destination rule資源和一個策略資源因為mutual TLS衝突時會出現該訊息。當兩個資源選擇的TLS模式不匹配時就會出現這種情況。該衝突意味著,匹配到destination rule的流量將會被拒絕。

該訊息已經被廢棄,僅在使用alpha認證策略的服務網格中使用。(瞭解該問題仍然可以避免配置錯誤)

哪些destination rules和策略與服務相關

為了有效解決mutual TLS的衝突,需要同時瞭解destination rule和策略是如何影響到一個服務的流量的。考慮一個my-namespace名稱空間中的名為my-service的服務。為了確定應用到my-service上的是哪個策略物件,按順序匹配以下資源:

  1. my-namespace名稱空間中的策略資源包含一個target,指定了my-service
  2. my-namespace名稱空間中的一個名為default的策略資源不包含一個target,意味著該策略適用於整個名稱空間。
  3. 名為default的網格策略資源

為了確定哪個destination rule應用到到達my-service的流量,首先要知道流量來自哪個名稱空間。本例中,假設名稱空間為other-namespace。destination rule按照如下方式進行匹配:

  1. other-namespace名稱空間中的destination rule會指定一個host來匹配 my-service.my-namespace.svc.cluster.local(可能會通過完整匹配或萬用字元匹配)。注意exportTo欄位,該欄位控制了配置資源的可見性,當目標資源與源服務在相同的名稱空間時會被忽略(相同名稱空間下的服務總是可見的)。

  2. my-namespace名稱空間中的destination rule會指定一個host來匹配 my-service.my-namespace.svc.cluster.local(可能會通過完整匹配或萬用字元匹配)。注意為了進行匹配,exportTo欄位必須將該資源指定為公共的(即,值為*或不指定)。

  3. 根名稱空間(預設為istio-system)中的destination rule會匹配 my-service.my-namespace.svc.cluster.localMeshConfig 資源中的rootNamespace屬性會控制根名稱空間。注意為了進行匹配,exportTo欄位必須將該資源指定為公共的(即,值為*或不指定)。對rootNamespace的描述如下

    The namespace to treat as the administrative root namespace for Istio configuration. When processing a leaf namespace Istio will search for declarations in that namespace first and if none are found it will search in the root namespace. Any matching declaration found in the root namespace is processed as if it were declared in the leaf namespace.

最後,注意在遵循這些規則時,Istio不會應用任何繼承概念,它將使用符合指定條件的第一個資源。

問題解決

檢視如下輸出:

Error [IST0113] (DestinationRule default-rule.istio-system) A DestinationRule
and Policy are in conflict with regards to mTLS for host
myhost.my-namespace.svc.cluster.local:8080. The DestinationRule
"istio-system/default-rule" specifies that mTLS must be true but the Policy
object "my-namespace/my-policy" specifies Plaintext.

可以看出兩個資源是衝突的:

  • 策略資源my-namespace/my-policy使用Plaintext來支援mutual TLS模式
  • destination rule資源istio-system/default-rule,指定傳送到host myhost.my-namespace.svc.cluster.local:8080的流量需要啟用mutual TLS

可以使用下面的方式之一來修復該問題:

  • 修改策略資源my-namespace/my-policy來啟用mutual TLS作為認證模式。
  • 修改destination rule istio-system/default-rule,通過移除ISTIO_MUTUAL來禁用mutual TLS。注意default-rule位於istio-system名稱空間,即預設的根名稱空間中,意味著該destination rule會影響到網格中過的所有其他服務。
  • 在與服務相同的名稱空間(my-namespace)中新增一個新的destination rule,該destination rule不指定流量策略mutual TLS。由於該規則位於與服務相同的名稱空間中,它不會覆蓋全域性destination rule istio-system/default-rule.

MultipleSidecarsWithoutWorkloadSelectors

Message Name MultipleSidecarsWithoutWorkloadSelectors
Message Code IST0111
Description More than one sidecar resource in a namespace has no workload selector
Level Error

當一個名稱空間中的多個sidecar資源沒有定義任何負載選擇器時會出現該訊息,導致不可預知的行為。更多參見Sidecar

一個名稱空間僅允許一個sidecar資源不指定負載選擇器。

NamespaceNotInjected

Message Name NamespaceNotInjected
Message Code IST0102
Description A namespace is not enabled for Istio injection.
Level Warning

當一個名稱空間沒有annotation(如sidecar.istio.io/inject.)指明該名稱空間是否需要自動注入sidecar時會出現該提示。錯誤資訊如下:

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

可以通過給名稱空間打標籤來解決該問題,明確宣告是否需要啟用sidecar自動注入:

$ kubectl label namespace <namespace-name> istio-injection=enabled

強烈建議明確指定sidecar注入行為。忘記註釋名稱空間是導致錯誤的常見原因。

SchemaValidationError

Message Name SchemaValidationError
Message Code IST0106
Description The resource has a schema validation error.
Level Error

當Istio的配置沒有通過模式驗證時會出現該錯誤。如:

Error [IST0106] (VirtualService ratings-bogus-weight-default.default) Schema validation error: percentage 888 is not in range 0..100

Istio配置為:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings-bogus-weight-default
  namespace: default
spec:
  hosts:
  - ratings
  http:
  - route:
    - destination:
        host: ratings
        subset: v1
      weight: 999
    - destination:
        host: ratings
        subset: v2
      weight: 888

本例中可以看到weight元素為一個無效的值。可以通過訊息的details欄位來檢查哪個元素或值沒有符合模式要求,然後進行修正。

VirtualServiceDestinationPortSelectorRequired

Message Name VirtualServiceDestinationPortSelectorRequired
Message Code IST0112
Description A VirtualService routes to a service with more than one port exposed, but does not specify which to use.
Level Error

當一個virtual service路由到暴露多個port的服務,且沒有指定使用哪個埠時會出現該錯誤。這種模糊性可能導致不確定的行為。

可以在virtual service Destination中增加port欄位來解決該問題。

UnknownAnnotation

Message Name UnknownAnnotation
Message Code IST0108
Description An Istio annotation is not recognized for any kind of resource
Level Warning

當將格式為*.istio.io的無法識別的註釋附加到名稱空間時,會出現此訊息。Istio僅能識別特定的annotation名稱

ReferencedResourceNotFound

Message Name ReferencedResourceNotFound
Message Code IST0101
Description A resource being referenced does not exist.
Level Error

當Istio資源相關的資源不存在時會出現該錯誤。當Istio嘗試查詢引用的資源但無法找到時,將導致錯誤。錯誤資訊如:

Error [IST0101] (VirtualService httpbin.default) Referenced gateway not found: "httpbin-gateway-bogus"

本例中,VirtualService引用了一個不存在的閘道器。

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: httpbin-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http2
      protocol: HTTP2
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: httpbin
spec:
  hosts:
  - "*"
  gateways:
  - httpbin-gateway-bogus #  Should have been "httpbin-gateway"
  http:
  - route:
    - destination:
        host: httpbin-gateway

為了解決該問題,檢視detaild錯誤訊息中的資源型別,然後修正Istio配置即可。

PortNameIsNotUnderNamingConvention

Message Name PortNameIsNotUnderNamingConvention
Message Code IST0118
Description Port name is not under naming convention. Protocol detection is applied to the port.
Level Info

當埠不遵守Istio服務埠命名規範或埠未命名時會出現該錯誤。錯誤資訊如:

Info [IST0118] (Service httpbin.default) Port name foo-http (port: 80, targetPort: 80) doesn't follow the naming convention of Istio port.

對應的Service為:

apiVersion: v1
kind: Service
metadata:
  name: httpbin
  labels:
    app: httpbin
spec:
  ports:
  - name: foo-http
    port: 8000
    targetPort: 80
  selector:
    app: httpbin

可以通過將port foo-http按照語法name: <protocol>[-<suffix>]修改即可。

問題解決

  • 如果知道服務埠的協議,使用 <protocol>[-<suffix>] 格式重新命名即可
  • 如果不知道服務埠的協議,則需要從Prometheus請求metrics來獲取
    • 執行請求istio_requests_total
    • 如果有輸出,可以在metrics的request_protocol欄位中看到使用的協議
    • 如果沒有輸出,則可以保留埠不變。

PodMissingProxy

Message Name PodMissingProxy
Message Code IST0103
Description A pod is missing the Istio proxy.
Level Warning

當沒有sidecar或sidecar不正常時會出現該錯誤。

通常是因為啟用了自動注入,但後續沒有重啟pod導致sidecar不存在。

可以使用如下命令修復:

$ kubectl rollout restart deployment

相關文章