使用 Istio 出口閘道代理傳統服務
獨立部署多個 Istio 出口閘道,以便精細控制網格的出口通訊。
在 Deutsche Telekom Pan-Net,我們已採用 Istio 作為涵蓋我們服務的保護傘。不幸的是,有些服務尚未遷移到 Kubernetes,或無法遷移。
我們可以將 Istio 設定為這些上游服務的代理服務。這使我們能夠受益於授權/身份驗證、追蹤和可觀察性等功能,即使傳統服務保持原樣。
在本文末尾有一個實作練習,您可以在其中模擬該場景。在練習中,託管在 https://httpbin.org 的上游服務將由 Istio 出口閘道代理。
如果您熟悉 Istio,連接到上游服務的方法之一是透過出口閘道。
您可以部署一個來控制所有上游流量,或者您可以部署多個以進行精細控制並滿足單一職責原則,如這張圖片所示
透過此模型,一個出口閘道負責一個上游服務。
儘管 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)。
如您所見,您的可能性增加,並且 Istio 變得非常可擴展。
讓我們看看如何實作此模式。
解決方案
有多種方法可以執行此任務,但在此您將找到如何定義多個 Operator 並部署產生的資源。
在以下部分中,您將部署一個出口閘道以連接到上游服務:httpbin
(https://httpbin.org/)
最後,您將擁有
實作
先決條件
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
部署出口閘道
此任務的步驟假設
- 該服務安裝在命名空間:
httpbin
下。 - 服務名稱為:
http-egress
。
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 及其可能性,請聯絡我們其中一位