在之前的文章 Istio 服務網格中的閘道器 中,我已經介紹了簡單的暴露 Ingress Gateway
的方案。當時的方案只是用於臨時測試,不適合在大規模場景下使用,本文將探討更加優化的暴露 Ingress Gateway 的方案。
HostNetwork
第一種方法比較簡單,可以直接使用 HostNetwork
模式執行 Ingress Gateway。但你會發現無法啟動 ingressgateway 的 Pod,因為如果 Pod 設定了 HostNetwork=true
,則 dnsPolicy 就會從 ClusterFirst
被強制轉換成 Default
。而 Ingress Gateway 啟動過程中需要通過 DNS 域名連線 pilot
等其他元件,所以無法啟動。
我們可以通過強制將 dnsPolicy
的值設定為 ClusterFirstWithHostNet
來解決這個問題,詳情參考:Kubernetes DNS 高階指南。
修改後的 ingressgateway deployment 配置檔案如下:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: istio-ingressgateway
namespace: istio-system
...
spec:
...
template:
metadata:
...
spec:
affinity:
nodeAffinity:
...
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- 192.168.123.248 # 比如你想排程到這臺主機上
...
dnsPolicy: ClusterFirstWithHostNet
hostNetwork: true
restartPolicy: Always
...
複製程式碼
接下來我們就可以在瀏覽器中通過 Gateway 的 URL 來訪問服務網格中的服務了。
但是作為服務網格的流量接入層,Ingress Gateway 的高可靠性顯得尤為重要,高可靠性首先要解決的就是單點故障問題,一般常用的是採用多副本部署的方式。而上述方案只適用於單例項(Deployment 的副本數為 1)的情況,為了適應多節點部署架構,需要尋求更好的暴露方案。
使用 Envoy 作為前端代理
我們已經知道,Ingress Gateway 實際上內部執行的是 Envoy
代理,我們可以在 Ingress Gateway 前面再加一層代理,這樣就解決了高可用問題,你可以將 Ingress Gateway 的副本數擴充套件為多個,前端代理只需要通過 Service Name
來連線後端的 Gateway 就行了。同時建議採用獨佔節點的方式部署前端代理,以避免業務應用與前端代理服務發生資源爭搶。
前端代理可以使用一般的負載均衡軟體(如 Haproxy
、Nginx
等),也可以使用 Envoy
。由於 Envoy 是 Istio Service Mesh 中預設的 data plane,所以這裡推薦使用 Envoy。
Envoy 官方提供了一組 Envoy 的用例,我們只需要用到其中的 Dockerfile
。首先克隆 Envoy 的程式碼倉庫並轉到 examples/front-proxy
目錄:
$ git clone https://github.com/envoyproxy/envoy
$ cd envoy/examples/front-proxy
複製程式碼
修改 front-envoy.yaml
配置檔案,修改後的內容如下:
static_resources:
listeners:
- address:
socket_address:
address: 0.0.0.0
port_value: 80
filter_chains:
- filters:
- name: envoy.tcp_proxy ①
config:
stat_prefix: ingress_tcp
cluster: ingressgateway
access_log:
- name: envoy.file_access_log
config:
path: /dev/stdout
- address:
socket_address:
address: 0.0.0.0
port_value: 443
filter_chains:
- filters:
- name: envoy.tcp_proxy
config:
stat_prefix: ingress_tcp
cluster: ingressgateway_tls
access_log:
- name: envoy.file_access_log
config:
path: /dev/stdout
clusters:
- name: ingressgateway
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
http2_protocol_options: {}
hosts:
- socket_address:
address: istio-ingressgateway.istio-system ②
port_value: 80
- name: ingressgateway_tls
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
http2_protocol_options: {}
hosts:
- socket_address:
address: istio-ingressgateway.istio-system
port_value: 443
admin:
access_log_path: "/dev/null"
address:
socket_address:
address: 0.0.0.0
port_value: 8001
複製程式碼
- ① envoy.tcp_proxy 表示要例項化的過濾器的名稱。該名稱必須與內建支援的過濾器匹配,也就是說,該欄位的值不可隨意填寫,必須使用指定的幾個值。這裡
envoy.tcp_proxy
表示使用 TCP 代理。詳情參考:listener.Filter - ② istio-ingressgateway.istio-system 表示 Ingress Gateway 在叢集內部的 DNS 域名。
其他配置解析請參考:Envoy 的架構與基本術語
接下來通過 Dockerfile-frontenvoy
和 front-envoy.yaml
來構建 Docker 映象,我們來看下該 Dockerfile 的內容。
FROM envoyproxy/envoy:latest
RUN apt-get update && apt-get -q install -y \
curl
CMD /usr/local/bin/envoy -c /etc/front-envoy.yaml --service-cluster front-proxy
複製程式碼
其中 /etc/front-envoy.yaml
是本地的 front-envoy.yaml
掛載進去的。在 Kubernetes 中可以通過 ConfigMap
來掛載,所以我們還要建立一個 ConfigMap:
$ kubectl -n istio-system create cm front-envoy --from-file=front-envoy.yaml
複製程式碼
你可以將構建好的映象 push 到私有映象倉庫中或者公共倉庫中,也可以使用我已經上傳好的映象。
最後我們就可以通過該映象來部署前端代理了,需要建立一個 Deployment
,配置檔案 front-envoy-deploy.yaml
內容如下:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: front-envoy
spec:
replicas: 1
template:
metadata:
labels:
app: front-envoy
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- 192.168.123.248 # 比如你想排程到這臺主機上
containers:
- name: front-envoy
image: yangchuansheng/front-envoy
ports:
- containerPort: 80
volumeMounts:
- name: front-envoy
mountPath: /etc/front-envoy.yaml
subPath: front-envoy.yaml
hostNetwork: true
volumes:
- name: front-envoy
configMap:
name: front-envoy
複製程式碼
你可以將映象換成你自己的映象,然後通過該 yaml 檔案來部署:
$ kubectl -n istio-system create -f front-envoy-deploy.yaml
複製程式碼
接下來我們就可以在瀏覽器中通過前端代理所在節點的 URL 來訪問服務網格中的服務了。
更一般的場景,我們還可以配置前端代理的高可用。對於 Kubernetes 叢集以外只暴露一個訪問入口,可以使用 keepalived
排除單節點問題。具體實現方式與 Ingress 的高可用類似,可以參考 Ingress 的高可用方案。