目录

kubernetes流量-istio egress gateway 引导 HTTP 流量

部署 istio 作为出口网关对流量进行转发.

动机

谷歌 gcp kubernetes 集群如果不使用它的 nat 功能的话,我们如果需要集群里面的服务去访问做了白名单的资源的话,就非常麻烦,总不能每个节点的公网 ip 都做白名单吧,这样节点扩缩容 ip 也跟着变,维护起来很麻烦。

于是便有了用 istio egress 做出口网关的需求。

先决条件:

  • k8s 集群

  • 安装 istio ,本次版本为 1.14.3

安装 istio ,需要选择固定的主机,目的就是不让它出口经常变,可以搞2台做备用。(注意:不是高可用)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
wget https://github.com/istio/istio/releases/download/1.14.3/istio-1.14.3-linux-amd64.tar.gz
tar xf istio-1.14.3-linux-amd64.tar.gz
cd istio-1.14.3
export PATH=$PWD/bin:$PATH

cat <<EOF > istio-operator.yaml
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: "egress-gateway"
  namespace: istio-system
spec:
  meshConfig:
    accessLogFile: "/dev/stdout"
  components:
    egressGateways:
      - name: "istio-egressgateway"
        enabled: true
        namespace: "istio-system"
        label:
          istio: "egressgateway"
        k8s:
          tolerations:
          - key: "dedicated"
            operator: "Equal"
            value: "gateway"
          nodeSelector:
            cloud.google.com/gke-nodepool: "gateway"
EOF

istioctl install -f istio-operator.yaml

安装测试应用

1
2
3
4
5
6
7
kubectl apply -f <(istioctl kube-inject -f samples/sleep/sleep.yaml)
export SOURCE_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name})

# 查看ip出口
kubectl exec "$SOURCE_POD" -c sleep -- curl -sSL -o /dev/null -D - http://edition.cnn.com/politics
kubectl exec "$SOURCE_POD" -c sleep -- curl -sSL http://cip.cc
kubectl exec "$SOURCE_POD" -c sleep -- curl -sSL https://cip.cc

用 Egress Gateway 发起 HTTP 请求

这里主要针对 edition.cnn.com 这个域名做的演示,cip.cc 在这里也顺便做了,后面 https 部分再具体说。

配置 ServiceEntry 。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: cnn
spec:
  hosts:
  - edition.cnn.com
  - cip.cc
  ports:
  - number: 80
    name: http-port
    protocol: HTTP
  - number: 443
    name: https
    protocol: HTTPS
  resolution: DNS
EOF

配置 Gateway 。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: istio-egressgateway
spec:
  selector:
    istio: egressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - edition.cnn.com
	- cip.cc
  - port:
      number: 443
      name: https
      protocol: HTTPS
    hosts:
    - cip.cc
    tls:
      mode: PASSTHROUGH
EOF

配置 DestinationRule 。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: egressgateway-for-cnn
spec:
  host: istio-egressgateway.istio-system.svc.cluster.local
  subsets:
  - name: cnn
EOF

配置 VirtualService 。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: edition-cnn-com-egress-gateway
spec:
  hosts:
  - edition.cnn.com
  gateways:
  - istio-egressgateway
  - mesh
  http:
  - match:
    - gateways:
      - mesh
      port: 80
    route:
    - destination:
        host: istio-egressgateway.istio-system.svc.cluster.local
        subset: cnn
        port:
          number: 80
      weight: 100
  - match:
    - gateways:
      - istio-egressgateway
      port: 80
    route:
    - destination:
        host: edition.cnn.com
        port:
          number: 80
      weight: 100
EOF

上面的配置,可以看到 http 强制跳转 https 是能正常访问的,不过官网给的这个演示,没办法看出口ip。那我们按着这个思路,自己配置一个能返回出口ip的域名试试。

1
kubectl exec "$SOURCE_POD" -c sleep -- curl -sSL -o /dev/null -D - http://edition.cnn.com/politics

用 Egress Gateway 发起 HTTPS 请求

我们复用上面的 ServiceEntry、DestinationRule 和 Gateway ,我试过创建同样的端口的 ServiceEntry ,测试就一直失败,所以干脆复用就好了,在对应端口的 hosts 字段添加我们想要出去的域名。

重点是 VirtualService ,配置如下。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: cip-cc-com-egress-gateway
spec:
  hosts:
  - cip.cc
  gateways:
  - istio-egressgateway
  - mesh
  http:
  - match:
    - gateways:
      - mesh
      port: 80
    route:
    - destination:
        host: istio-egressgateway.istio-system.svc.cluster.local
        port:
          number: 80
        subset: cnn
      weight: 100
  - match:
    - gateways:
      - istio-egressgateway
      port: 80
    route:
    - destination:
        host: cip.cc
        port:
          number: 80
      weight: 100
  tls:
  - match:
    - gateways:
      - mesh
      port: 443
      sniHosts:
      - cip.cc
    route:
    - destination:
        host: istio-egressgateway.istio-system.svc.cluster.local
        subset: cnn
        port:
          number: 443
      weight: 100
  - match:
    - gateways:
      - istio-egressgateway
      port: 443
      sniHosts:
      - cip.cc
    route:
    - destination:
        host: cip.cc
        port:
          number: 443
      weight: 100
EOF

应用上去后,我们测试一下返回的ip是否是我们 egress pod 所在机器的公网ip。

1
2
kubectl exec "$SOURCE_POD" -c sleep -- curl -sSL http://cip.cc
kubectl exec "$SOURCE_POD" -c sleep -- curl -sSL https://cip.cc

就可以看到,无论是 http 还是 https ,都是返回出口网关所在节点的公网 ip 。

总结

这里配置也踩了坑,也是反复测试后才发现相同的端口,只要一份 ServiceEntry 即可。一个端口配置多个 ServiceEntry ,会出现访问失败的情况。

然后重点就是在对应端口的 hosts 字段添加我们想要出网关的域名, VirtualService 配置对即可正常使用。

参考:istio官网