部署 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官网