使用 Istio 出口閘道代理傳統服務

獨立部署多個 Istio 出口閘道,以便精細控制網格的出口通訊。

2020 年 12 月 16 日| 作者:Antonio Berben - Deutsche Telekom - PAN-NET

Deutsche Telekom Pan-Net,我們已採用 Istio 作為涵蓋我們服務的保護傘。不幸的是,有些服務尚未遷移到 Kubernetes,或無法遷移。

我們可以將 Istio 設定為這些上游服務的代理服務。這使我們能夠受益於授權/身份驗證、追蹤和可觀察性等功能,即使傳統服務保持原樣。

在本文末尾有一個實作練習,您可以在其中模擬該場景。在練習中,託管在 https://httpbin.org 的上游服務將由 Istio 出口閘道代理。

如果您熟悉 Istio,連接到上游服務的方法之一是透過出口閘道

您可以部署一個來控制所有上游流量,或者您可以部署多個以進行精細控制並滿足單一職責原則,如這張圖片所示

Overview multiple Egress Gateways
多個出口閘道概述

透過此模型,一個出口閘道負責一個上游服務。

儘管 Operator 規格允許您部署多個出口閘道,但清單可能會變得難以管理

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
[...]
spec:
    egressGateways:
    - name: egressgateway-1
      enabled: true
    - name: egressgateway-2
      enabled: true
    [egressgateway-3, egressgateway-4, ...]
    - name: egressgateway-N
      enabled: true
[...]

作為將出口閘道與 Operator 清單分離的好處,您已啟用設定自訂就緒探測的可能性,以使兩個服務(閘道和上游服務)對齊。

您還可以將 OPA 作為 sidecar 注入到 pod 中,以使用複雜的規則執行授權 (OPA envoy plugin)。

Authorization with OPA and `healthcheck` to upstream service
透過 OPA 和外部 `healthcheck` 進行授權

如您所見,您的可能性增加,並且 Istio 變得非常可擴展。

讓我們看看如何實作此模式。

解決方案

有多種方法可以執行此任務,但在此您將找到如何定義多個 Operator 並部署產生的資源。

在以下部分中,您將部署一個出口閘道以連接到上游服務:httpbin (https://httpbin.org/)

最後,您將擁有

Communication
通訊

實作

先決條件

Kind

將其另存為 config.yaml

kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
kubeadmConfigPatches:
  - |
    apiVersion: kubeadm.k8s.io/v1beta2
    kind: ClusterConfiguration
    metadata:
      name: config
    apiServer:
      extraArgs:
        "service-account-issuer": "kubernetes.default.svc"
        "service-account-signing-key-file": "/etc/kubernetes/pki/sa.key"
$ kind create cluster --name <my-cluster-name> --config config.yaml

其中 <my-cluster-name> 是叢集的名稱。

具有 Istioctl 的 Istio Operator

安裝 Operator

$ istioctl operator init --watchedNamespaces=istio-operator
$ kubectl create ns istio-system

將其另存為 operator.yaml

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: istio-operator
  namespace: istio-operator
spec:
  profile: default
  tag: 1.8.0
  meshConfig:
    accessLogFile: /dev/stdout
    outboundTrafficPolicy:
      mode: REGISTRY_ONLY
$ kubectl apply -f operator.yaml

部署出口閘道

此任務的步驟假設

Istio 1.8 引入了應用覆蓋配置的可能性,以精細控制建立的資源。

將其另存為 egress.yaml

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: empty
  tag: 1.8.0
  namespace: httpbin
  components:
    egressGateways:
    - name: httpbin-egress
      enabled: true
      label:
        app: istio-egressgateway
        istio: egressgateway
        custom-egress: httpbin-egress
      k8s:
        overlays:
        - kind: Deployment
          name: httpbin-egress
          patches:
          - path: spec.template.spec.containers[0].readinessProbe
            value:
              failureThreshold: 30
              exec:
                command:
                  - /bin/sh
                  - -c
                  - curl https://#:15021/healthz/ready && curl https://httpbin.org/status/200
              initialDelaySeconds: 1
              periodSeconds: 2
              successThreshold: 1
              timeoutSeconds: 1
  values:
    gateways:
      istio-egressgateway:
        runAsRoot: true

建立您將在其中安裝出口閘道的命名空間

$ kubectl create ns httpbin

文件中所述,您可以部署多個 Operator 資源。但是,它們必須先經過預先剖析,然後再套用至叢集。

$ istioctl manifest generate -f egress.yaml | kubectl apply -f -

Istio 配置

現在,您將配置 Istio 以允許連線到 https://httpbin.org 的上游服務。

TLS 憑證

您需要一個憑證才能從叢集外部安全連線到您的出口服務。

如何產生憑證在Istio 入口文件中有說明。

建立並套用一個,以在本文章末尾使用,以便從叢集外部存取該服務 (<my-proxied-service-hostname>)

$ kubectl create -n istio-system secret tls <my-secret-name> --key=<key> --cert=<cert>

其中 <my-secret-name> 是稍後用於 Gateway 資源的名稱。<key><cert> 是憑證的檔案。<cert>

入口閘道

建立 Gateway 資源以操作入口閘道以接受請求。

一個範例

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: my-ingressgateway
  namespace: istio-system
spec:
  selector:
    istio: ingressgateway
  servers:
  - hosts:
    - "<my-proxied-service-hostname>"
    port:
      name: http
      number: 80
      protocol: HTTP
    tls:
     httpsRedirect: true
  - port:
      number: 443
      name: https
      protocol: https
    hosts:
    - "<my-proxied-service-hostname>"
    tls:
      mode: SIMPLE
      credentialName: <my-secret-name>

其中 <my-proxied-service-hostname> 是透過 my-ingressgateway 存取服務的主機名稱,而 <my-secret-name> 是包含憑證的密鑰。

出口閘道

建立另一個 Gateway 物件,但這次是為了操作您已安裝的出口閘道

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: "httpbin-egress"
  namespace: "httpbin"
spec:
  selector:
    istio: egressgateway
    service.istio.io/canonical-name: "httpbin-egress"
  servers:
  - hosts:
    - "<my-proxied-service-hostname>"
    port:
      number: 80
      name: http
      protocol: HTTP

其中 <my-proxied-service-hostname> 是透過 my-ingressgateway 存取的主機名稱。

虛擬服務

為三個使用案例建立 VirtualService

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: "httpbin-egress"
  namespace: "httpbin"
spec:
  hosts:
  - "<my-proxied-service-hostname>"
  gateways:
  - mesh
  - "istio-system/my-ingressgateway"
  - "httpbin/httpbin-egress"
  http:
  - match:
    - gateways:
      - "istio-system/my-ingressgateway"
      - mesh
      uri:
        prefix: "/"
    route:
    - destination:
        host: "httpbin-egress.httpbin.svc.cluster.local"
        port:
          number: 80
  - match:
    - gateways:
      - "httpbin/httpbin-egress"
      uri:
        prefix: "/"
    route:
    - destination:
        host: "httpbin.org"
        subset: "http-egress-subset"
        port:
          number: 443

其中 <my-proxied-service-hostname> 是透過 my-ingressgateway 存取的主機名稱。

服務條目

建立 ServiceEntry 以允許與上游服務通訊

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: "httpbin-egress"
  namespace: "httpbin"
spec:
  hosts:
  - "httpbin.org"
  location: MESH_EXTERNAL
  ports:
  - number: 443
    name: https
    protocol: TLS
  resolution: DNS

目標規則

建立 DestinationRule 以允許出口流量的 TLS 源發,如文件中所述

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: "httpbin-egress"
  namespace: "httpbin"
spec:
  host: "httpbin.org"
  subsets:
  - name: "http-egress-subset"
    trafficPolicy:
      loadBalancer:
        simple: ROUND_ROBIN
      portLevelSettings:
      - port:
          number: 443
        tls:
          mode: SIMPLE

同層級驗證

為了保護服務對服務,您需要強制執行 mTLS

apiVersion: "security.istio.io/v1beta1"
kind: "PeerAuthentication"
metadata:
  name: "httpbin-egress"
  namespace: "httpbin"
spec:
  mtls:
    mode: STRICT

測試

驗證您的物件是否都已正確指定

$ istioctl analyze --all-namespaces

外部存取

透過轉發 ingressgateway 服務的連接埠並呼叫服務,從叢集外部測試出口閘道

$ kubectl -n istio-system port-forward svc/istio-ingressgateway 15443:443
$ curl -vvv -k -HHost:<my-proxied-service-hostname> --resolve "<my-proxied-service-hostname>:15443:127.0.0.1" --cacert <cert> "https://<my-proxied-service-hostname>:15443/status/200"

其中 <my-proxied-service-hostname> 是透過 my-ingressgateway 存取的主機名稱,而 <cert> 是為 ingressgateway 物件定義的憑證。這是因為 tls.mode: SIMPLE 不會終止 TLS

服務對服務存取

從叢集內部部署 sleep 服務來測試出口閘道。當您設計容錯移轉時,這會很有用。

$ kubectl label namespace httpbin istio-injection=enabled --overwrite
$ kubectl apply -n httpbin -f  https://raw.githubusercontent.com/istio/istio/release-1.24/samples/sleep/sleep.yaml
$ kubectl -n httpbin "$(kubectl get pod -n httpbin -l app=sleep -o jsonpath={.items..metadata.name})" -- curl -vvv http://<my-proxied-service-hostname>/status/200

其中 <my-proxied-service-hostname> 是透過 my-ingressgateway 存取的主機名稱。

現在是建立指向其他上游服務的第二個、第三個和第四個出口閘道的時候了。

最後的想法

Istio 的設定看起來可能很複雜。但由於它為您的服務帶來了大量好處(而且 Kiali 也非常棒),因此絕對值得這麼做。

Istio 的開發方式使我們能夠以最少的努力來滿足本文中介紹的不常見需求。

最後,我只想指出,Istio 作為一個好的雲原生技術,不需要龐大的團隊來維護。例如,我們目前的團隊由 3 位工程師組成。

若要深入討論 Istio 及其可能性,請聯絡我們其中一位

分享此貼文