用於出口流量的 Kubernetes 服務
Kubernetes 的 ExternalName 服務以及具有 端點 (Endpoints) 的 Kubernetes 服務,可讓您建立指向外部服務的本機 DNS別名。此 DNS 別名與本機服務的 DNS 條目形式相同,即 <服務名稱>.<命名空間名稱>.svc.cluster.local
。DNS 別名為您的工作負載提供位置透明性:工作負載可以相同的方式呼叫本機和外部服務。如果您在某個時間點決定在叢集內部署外部服務,您可以直接更新其 Kubernetes 服務以參考本機版本。工作負載將繼續運行,而無需進行任何更改。
此任務顯示這些用於存取外部服務的 Kubernetes 機制在 Istio 中仍然有效。您必須執行的唯一配置步驟是使用 Istio 的 雙向 TLS 以外的 TLS 模式。外部服務不屬於 Istio 服務網格,因此它們無法執行 Istio 的雙向 TLS。您必須根據外部服務的 TLS 要求以及工作負載存取外部服務的方式來設定 TLS 模式。如果您的工作負載發出普通的 HTTP 請求,而外部服務需要 TLS,您可能希望由 Istio 執行 TLS 發起 (origination)。如果您的工作負載已經使用 TLS,則流量已經加密,您可以直接停用 Istio 的雙向 TLS。
雖然此任務中的範例使用 HTTP 協定,但用於出口流量的 Kubernetes 服務也適用於其他協定。
開始之前
請依照安裝指南中的指示設定 Istio。
部署 curl 範例應用程式,作為發送請求的測試來源。如果您已啟用自動 Sidecar 注入,請執行以下命令來部署範例應用程式
$ kubectl apply -f @samples/curl/curl.yaml@
否則,請在部署
curl
應用程式之前,使用以下命令手動注入 Sidecar$ kubectl apply -f <(istioctl kube-inject -f @samples/curl/curl.yaml@)
將
SOURCE_POD
環境變數設定為您的來源 Pod 的名稱$ export SOURCE_POD=$(kubectl get pod -l app=curl -o jsonpath={.items..metadata.name})
建立一個不使用 Istio 控制的來源 Pod 的命名空間
$ kubectl create namespace without-istio
在
without-istio
命名空間中啟動 curl 範例。$ kubectl apply -f @samples/curl/curl.yaml@ -n without-istio
若要發送請求,請建立
SOURCE_POD_WITHOUT_ISTIO
環境變數以儲存來源 Pod 的名稱$ export SOURCE_POD_WITHOUT_ISTIO="$(kubectl get pod -n without-istio -l app=curl -o jsonpath={.items..metadata.name})"
確認 Istio Sidecar 未被注入,也就是說,該 Pod 只有一個容器
$ kubectl get pod "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio NAME READY STATUS RESTARTS AGE curl-66c8d79ff5-8tqrl 1/1 Running 0 32s
Kubernetes ExternalName 服務以存取外部服務
在預設命名空間中為
httpbin.org
建立 Kubernetes ExternalName 服務$ kubectl apply -f - <<EOF kind: Service apiVersion: v1 metadata: name: my-httpbin spec: type: ExternalName externalName: httpbin.org ports: - name: http protocol: TCP port: 80 EOF
觀察您的服務。請注意,它沒有叢集 IP。
$ kubectl get svc my-httpbin NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-httpbin ExternalName <none> httpbin.org 80/TCP 4s
從沒有 Istio Sidecar 的來源 Pod,透過 Kubernetes 服務的主機名稱存取
httpbin.org
。請注意,下面的 curl 命令使用服務的 Kubernetes DNS 格式:<服務名稱>.<命名空間>.svc.cluster.local
。$ kubectl exec "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio -c curl -- curl -sS my-httpbin.default.svc.cluster.local/headers { "headers": { "Accept": "*/*", "Host": "my-httpbin.default.svc.cluster.local", "User-Agent": "curl/7.55.0" } }
在此範例中,未加密的 HTTP 請求會傳送至
httpbin.org
。為了方便說明範例,您停用 TLS 模式,並允許未加密的流量傳送至外部服務。在真實場景中,我們建議由 Istio 執行出口 TLS 發起 (origination)。$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: DestinationRule metadata: name: my-httpbin spec: host: my-httpbin.default.svc.cluster.local trafficPolicy: tls: mode: DISABLE EOF
從具有 Istio Sidecar 的來源 Pod,透過 Kubernetes 服務的主機名稱存取
httpbin.org
。請注意由 Istio Sidecar 新增的標頭,例如X-Envoy-Peer-Metadata
。另請注意,Host
標頭等於您服務的主機名稱。$ kubectl exec "$SOURCE_POD" -c curl -- curl -sS my-httpbin.default.svc.cluster.local/headers { "headers": { "Accept": "*/*", "Content-Length": "0", "Host": "my-httpbin.default.svc.cluster.local", "User-Agent": "curl/7.64.0", "X-B3-Sampled": "0", "X-B3-Spanid": "5795fab599dca0b8", "X-B3-Traceid": "5079ad3a4af418915795fab599dca0b8", "X-Envoy-Peer-Metadata": "...", "X-Envoy-Peer-Metadata-Id": "sidecar~10.28.1.74~curl-6bdb595bcb-drr45.default~default.svc.cluster.local" } }
清理 Kubernetes ExternalName 服務
$ kubectl delete destinationrule my-httpbin
$ kubectl delete service my-httpbin
使用具有端點的 Kubernetes 服務以存取外部服務
為 Wikipedia 建立不帶選取器的 Kubernetes 服務
$ kubectl apply -f - <<EOF kind: Service apiVersion: v1 metadata: name: my-wikipedia spec: ports: - protocol: TCP port: 443 name: tls EOF
為您的服務建立端點。從Wikipedia 範圍列表中選取幾個 IP。
$ kubectl apply -f - <<EOF kind: Endpoints apiVersion: v1 metadata: name: my-wikipedia subsets: - addresses: - ip: 198.35.26.96 - ip: 208.80.153.224 ports: - port: 443 name: tls EOF
觀察您的服務。請注意,它有一個叢集 IP,您可以使用該 IP 存取
wikipedia.org
。$ kubectl get svc my-wikipedia NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-wikipedia ClusterIP 172.21.156.230 <none> 443/TCP 21h
從沒有 Istio Sidecar 的來源 Pod,透過 Kubernetes 服務的叢集 IP 發送 HTTPS 請求至
wikipedia.org
。使用curl
的--resolve
選項,透過叢集 IP 存取wikipedia.org
$ kubectl exec "$SOURCE_POD_WITHOUT_ISTIO" -n without-istio -c curl -- curl -sS --resolve en.wikipedia.org:443:"$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}')" https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>" <title>Wikipedia, the free encyclopedia</title>
在此案例中,工作負載會傳送 HTTPS 請求(開啟 TLS 連線)至
wikipedia.org
。流量已由工作負載加密,因此您可以安全地停用 Istio 的雙向 TLS$ kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1 kind: DestinationRule metadata: name: my-wikipedia spec: host: my-wikipedia.default.svc.cluster.local trafficPolicy: tls: mode: DISABLE EOF
從具有 Istio Sidecar 的來源 Pod,透過 Kubernetes 服務的叢集 IP 存取
wikipedia.org
$ kubectl exec "$SOURCE_POD" -c curl -- curl -sS --resolve en.wikipedia.org:443:"$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}')" https://en.wikipedia.org/wiki/Main_Page | grep -o "<title>.*</title>" <title>Wikipedia, the free encyclopedia</title>
檢查存取是否確實由叢集 IP 執行。請注意
curl -v
輸出中的句子Connected to en.wikipedia.org (172.21.156.230)
,其中提到了在您的服務輸出中印出的叢集 IP。$ kubectl exec "$SOURCE_POD" -c curl -- curl -sS -v --resolve en.wikipedia.org:443:"$(kubectl get service my-wikipedia -o jsonpath='{.spec.clusterIP}')" https://en.wikipedia.org/wiki/Main_Page -o /dev/null * Added en.wikipedia.org:443:172.21.156.230 to DNS cache * Hostname en.wikipedia.org was found in DNS cache * Trying 172.21.156.230... * TCP_NODELAY set * Connected to en.wikipedia.org (172.21.156.230) port 443 (#0) ...
清理具有端點的 Kubernetes 服務
$ kubectl delete destinationrule my-wikipedia
$ kubectl delete endpoints my-wikipedia
$ kubectl delete service my-wikipedia