天天看點

基于Istio Ingress對外提供服務

文章目錄

    • 建立應用服務
    • 建立VirtualService
    • 通過Ingress Gateway通路服務
    • 分析請求過程
      • Ingress Gateway Service
      • iptables規則
      • Envoy配置

上一篇是在Service Mesh中兩個應用之間互相通路,本篇介紹下通過Istio Ingress把服務網格中的應用對外暴露,通過Ingress Gateway控制從外邊通路服務網格中的應用。

在Service Mesh中部署兩個服務,一個httpserver應用,一個Nginx,通過在Ingress Gateway中配置路由控制,使用同一個域名,不同的URI通路兩個應用服務。如下:

curl -H "Host: simple.baihl.io" $INGRESS_IP/simple/httpserver
curl -H "Host: simple.baihl.io" $INGRESS_IP/simple/nginx
           

$INGRESS_IP

為 Istio中Ingress Gateway對外的IP位址。

建立應用服務

kubectl create ns simple
kubectl create -f simple.yaml -n simple
kubectl create -f nginx.yaml -n simple
kubectl apply -f istio-specs.yaml -n simple
           
  • simple.yaml

simple.yaml就是運作httpserver,并且定義了Service對外提供服務。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: simple
spec:
  replicas: 1
  selector:
    matchLabels:
      app: simple
  template:
    metadata:
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "80"
      labels:
        app: simple
    spec:
      containers:
        - name: simple
          imagePullPolicy: Always
          image: cncamp/httpserver:v1.0-metrics
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: simple
spec:
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: simple
           
  • nginx.yaml

一個基本的Nginx服務

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 80
  selector:
    app: nginx
           

建立VirtualService

  • istio-specs.yaml

VirtualService是在Istio服務網格内對服務的請求進行路由控制。

如下,通過建立VirtualService與gateway關聯。配置設定控制對httpserver和nginx的通路。

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: simple
spec:
  gateways:
    - simple
  hosts:
    - simple.baihl.io
  http:
  # 會在Envoy中生成對應的route配置
  - match:
    - uri:
        exact: "/simple/httpserver"
    rewrite:
      uri: "/hello"
    route:
      - destination:
          host: simple.simple.svc.cluster.local
          port:
            number: 80
  - match:
    - uri:
        prefix: "/simple/nginx"
    rewrite:
      uri: "/"
    route:
      - destination:
          host: nginx.simple.svc.cluster.local
          port:
            number: 80
---
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: simple
spec:
  selector:
    istio: ingressgateway
  servers:
  # 會在Envoy中生成對應的listener配置
    - hosts:
        - simple.baihl.io
      port:
        name: http-simple
        number: 80 #對外提供的服務端口為80
        protocol: HTTP
           

部署完以上的服務,整體看下所有建立出來的對象:

執行

kubectl get pod,svc,deployment,endpoints,VirtualService,Gateway -n simple

基于Istio Ingress對外提供服務

可以看到,service/nginx 和 service/simple 分别是我們建立的兩個應用程式Pod對外提供服務的Service,還有一個virtualservice,比對的Host為"simple.baihl.io"。

通過Ingress Gateway通路服務

檢視Ingress Gateway對外提供暴露的IP位址:

基于Istio Ingress對外提供服務

Ingress Gateway對外的IP為:

10.96.190.18

INGRESS_IP=10.96.190.18
curl -H "Host: simple.baihl.io" $INGRESS_IP/simple/httpserver
curl -H "Host: simple.baihl.io" $INGRESS_IP/simple/nginx
           
  • 通路httpserver
基于Istio Ingress對外提供服務
  • 通路Nginx
基于Istio Ingress對外提供服務

分析請求過程

Ingress Gateway Service

在通路IngressGateway時,首先經過的就是Ingress Gateway配置的Service,可以看下Service配置是什麼。

執行

kubectl get svc istio-ingressgateway -n istio-system -o json

"ports": [
              {
                "name": "http2",
                "nodePort": 31373,
                "port": 80,
                "protocol": "TCP",
                "targetPort": 8080
            },
            {
                "name": "https",
                "nodePort": 31860,
                "port": 443,
                "protocol": "TCP",
                "targetPort": 8443
            },
        ],
        "selector": {
            "app": "istio-ingressgateway",
            "istio": "ingressgateway"
        },
        "sessionAffinity": "None",
        "type": "LoadBalancer"
           

Service使用的type為LoadBalancer,配置了對外提供的端口80映射到主控端的31373,在上邊通路應用服務的時候因為是在Master節點,是以就直接通路了Service的IP位址10.96.190.18,但是在叢集外部是無法通路10.96.190.18的,需要通路Master節點對外的IP位址,對于我本地的環境來說就是Master節點的IP位址192.168.170.137。是以在叢集外部通路httpserver和nginx,需要通路 10.96.190.18:31373,操作如下:

$ curl -H "Host: simple.baihl.io" 192.168.170.137:31373/simple/nginx
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   615  100   615    0     0  90667      0 --:--:-- --:--:-- --:--:--  150k<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/" target="_blank" rel="external nofollow" >nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/" target="_blank" rel="external nofollow" >nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
           

如上我在本地筆記本上通路Master節點的IP位址請求Isito中的Nginx服務。

iptables規則

為什麼在外部通路192.168.170.137:31373和在Master節點上通路IngressGateway的IP都可以獲得應用服務的響應,就是因為在Kubernetes的Master節點上的iptables規則。

比如,通路192.168.170.137:31373

#對于通路目标端口為31373的請求,轉到KUBE-SVC-G6D3V5KS3PXPUEDS
-A KUBE-NODEPORTS -p tcp -m comment --comment "istio-system/istio-ingressgateway:http2" -m tcp --dport 31373 -j KUBE-SVC-G6D3V5KS3PXPUEDS
# 比對KUBE-SVC-G6D3V5KS3PXPUEDS請求轉到KUBE-SEP-LAV34IONK7IOT5SV
-A KUBE-SVC-G6D3V5KS3PXPUEDS -m comment --comment "istio-system/istio-ingressgateway:http2" -j KUBE-SEP-LAV34IONK7IOT5SV
# 比對KUBE-SEP-LAV34IONK7IOT5SV,請求做DNAT,目标IP修改為10.10.1.4,目标端口為8080
-A KUBE-SEP-LAV34IONK7IOT5SV -p tcp -m comment --comment "istio-system/istio-ingressgateway:http2" -m tcp -j DNAT --to-destination 10.10.1.4:8080
           

比如,通路10.96.190.18:80,會比對到如下的iptables規則:

#對于通路目标IP為10.96.190.18/32,目标端口為80的請求,轉到KUBE-SVC-G6D3V5KS3PXPUEDS
-A KUBE-SERVICES -d 10.96.190.18/32 -p tcp -m comment --comment "istio-system/istio-ingressgateway:http2 cluster IP" -m tcp --dport 80 -j KUBE-SVC-G6D3V5KS3PXPUEDS
# 比對KUBE-SVC-G6D3V5KS3PXPUEDS請求轉到KUBE-SEP-LAV34IONK7IOT5SV
-A KUBE-SVC-G6D3V5KS3PXPUEDS -m comment --comment "istio-system/istio-ingressgateway:http2" -j KUBE-SEP-LAV34IONK7IOT5SV
# 比對KUBE-SEP-LAV34IONK7IOT5SV,請求做DNAT,目标IP修改為10.10.1.4,目标端口為8080
-A KUBE-SEP-LAV34IONK7IOT5SV -p tcp -m comment --comment "istio-system/istio-ingressgateway:http2" -m tcp -j DNAT --to-destination 10.10.1.4:8080
           

對比上邊兩種通路情況的iptables規則比對流程可以看到,最終都是對請求做了DNAT後,請求的目标IP位址變為10.10.1.4,目标端口變為8080。

基于Istio Ingress對外提供服務

可以看到,10.10.1.4的IP就是istio-ingressgateway的IP位址。

Envoy配置

目前請求轉到了10.10.1.4:8080,是以可以看下在istio-ingressgateway中監聽8080端口的是誰?

基于Istio Ingress對外提供服務

使用nsenter指令,進入istio-ingressgateway内部檢視,可以發現監聽8080端口的正式Envoy程式。

下邊就可以通過看Envoy的配置,看看請求後邊是怎麼處理的。

  1. 首先看下監聽8080端口的配置資訊
[email protected]:~$ istioctl pc listener -n istio-system istio-ingressgateway-576c469c96-spndl --port 8080
ADDRESS PORT MATCH DESTINATION
0.0.0.0 8080 ALL   Route: http.8080
           

監聽8080的listener比對的route為http.8080,繼續檢視route資訊。

2. 檢視route為http.8080

[email protected]-master:~$ istioctl pc route  -n istio-system istio-ingressgateway-576c469c96-spndl --name=http.8080 -o yaml
- ignorePortInHostMatching: true
  name: http.8080
  validateClusters: false
  virtualHosts:
  - domains:
    - simple.baihl.io
    includeRequestAttemptCount: true
    name: simple.baihl.io:80
    routes:
      match:
        caseSensitive: true
        ## 比對/simple/httpserver的請求
        path: /simple/httpserver
      route:
      # httpserver route對應的cluster
        cluster: outbound|80||simple.simple.svc.cluster.local
        maxStreamDuration:
          grpcTimeoutHeaderMax: 0s
          maxStreamDuration: 0s
        prefixRewrite: /hello
    - decorator:
        operation: nginx.simple.svc.cluster.local:80/simple/nginx*
      match:
        caseSensitive: true
        prefix: /simple/nginx
      metadata:
        filterMetadata:
          istio:
            config: /apis/networking.istio.io/v1alpha3/namespaces/simple/virtual-service/simple
      route:
      # nginx 服務對應的cluster
        cluster: outbound|80||nginx.simple.svc.cluster.local
        maxStreamDuration:
          grpcTimeoutHeaderMax: 0s
          maxStreamDuration: 0s
        prefixRewrite: /
           

根據route配置可以看到:

  1. 請求uri為/simple/httpserver,被outbound|80||simple.simple.svc.cluster.local處理。
  2. 請求uri為/simple/nginx,被outbound|80||nginx.simple.svc.cluster.local處理。
  3. 檢視cluster

下邊檢視httpserver對應的的cluter:outbound|80||simple.simple.svc.cluster.local:

[email protected]:~$ istioctl pc endpoints  -n istio-system istio-ingressgateway-576c469c96-spndl --cluster="outbound|80||simple.simple.svc.cluster.local"
ENDPOINT          STATUS      OUTLIER CHECK     CLUSTER
10.10.1.13:80     HEALTHY     OK                outbound|80||simple.simple.svc.cluster.local
           

可以看到httpserver最終選擇的endpoint為10.10.1.13:80。

[email protected]:~$ kubectl get pod -n simple -o wide
NAME                                READY   STATUS    RESTARTS   AGE    IP           NODE         NOMINATED NODE   READINESS GATES
nginx-deployment-85b98978db-9rhvd   1/1     Running   0          110m   10.10.1.14   baihl-node   <none>           <none>
simple-fb6498fdb-rmdg2              1/1     Running   0          110m   10.10.1.13   baihl-node   <none>           <none>
           

可以看到運作httpserver的simple Pod,在叢集内的IP位址就是10.10.1.13。

同樣的方式,可以檢視nginx服務對應的cluster:outbound|80||nginx.simple.svc.cluster.local:

[email protected]:~$ istioctl pc endpoints  -n istio-system istio-ingressgateway-576c469c96-spndl --cluster="outbound|80||nginx.simple.svc.cluster.local"
ENDPOINT          STATUS      OUTLIER CHECK     CLUSTER
10.10.1.14:80     HEALTHY     OK                outbound|80||nginx.simple.svc.cluster.local
           

10.10.1.14對應的就是nginx-deployment Pod在叢集内的IP位址。

根據上邊的分析,在叢集外通過istio-ingressgateway通路叢集内部的應用程式,經過了iptables規則和ingressgateway中的路由控制,最後把請求分發到各個應用程式,通過ingressgateway也可以實作更加複雜的流量管理需求。

繼續閱讀