Istio Ingressgateway实践

N4Kf6E

Kubernetes Ingress, Istio Ingressgateway还是 Gateway API?Istio Ingressgateway

提前准备

  • 本次试验是在docker desktop 开启 k8s
  • istio版本1.16.1

任务:通过gateway把域名httpbin.example.com指向k8s服务httpbin,并配置https
核心重点:istio的Gateway和VirtualService使用

配置Http

前置条件:

  • Service名为httpbin,端口8000
    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
    apiVersion: v1
    kind: ServiceAccount
    metadata:
    name: httpbin
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: httpbin
    labels:
    app: httpbin
    service: httpbin
    spec:
    ports:
    - name: http
    port: 8000
    targetPort: 80
    selector:
    app: httpbin
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: httpbin
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: httpbin
    version: v1
    template:
    metadata:
    labels:
    app: httpbin
    version: v1
    spec:
    serviceAccountName: httpbin
    containers:
    - image: docker.io/kennethreitz/httpbin
    imagePullPolicy: IfNotPresent
    name: httpbin
    ports:
    - containerPort: 80

  • 假设拥有域名 httpbin.example.com

接下来,我们需要配置Gateway和VirtualService,如果你用过nginx,我们可以粗略的类比为server。其中Gateway相当于配置了server的基本信息,而VirtualService相当于配置了location。前者主要是配置域名端口等,后者配路由规则。

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
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
namespace: junyao
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "httpbin.example.com"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.example.com" ## 需与上面hosts域名对应
gateways:
- httpbin-gateway ## 需与上面metadata.name对应
http:
- match:
- uri:
prefix: /status ## 暴露路由
- uri:
prefix: /delay ## 暴露路由 (可以看到/headers和/get的路由暂时没有暴露)
route:
- destination:
port:
number: 8000
host: httpbin ## service

已为 httpbin 服务创建了Virtual Service配置,包含两个路由规则,允许流量流向路径 /status 和 /delay。
Gateways 列表规约了哪些请求允许通 httpbin-gateway 网关。 所有其他外部请求均被拒绝并返回 404 响应。

访问服务

  • 通过NodePort访问
    1
    kubectl patch service istio-ingressgateway -n istio-system -p '{"spec":{"type":"NodePort"}}'
    1
    2
    查看80绑定的端口为30984
    kubectl -n istio-system get service istio-ingressgateway
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ## 因为VirtualService 有匹配路由/status,所以能正常访问
    curl -s -I -HHost:httpbin.example.com "http://localhost:30984/status/200"
    HTTP/1.1 200 OK
    server: istio-envoy
    date: Wed, 28 Dec 2022 03:18:22 GMT
    content-type: text/html; charset=utf-8
    access-control-allow-origin: *
    access-control-allow-credentials: true
    content-length: 0
    x-envoy-upstream-service-time: 3
    1
    2
    3
    4
    5
    6
    7
    ## 因为VirtualService 没有匹配路由/headers,所以能提示404 Not Found
    curl -s -I -HHost:httpbin.example.com "http://localhost:30984/headers"
    HTTP/1.1 404 Not Found
    date: Wed, 28 Dec 2022 03:18:34 GMT
    server: istio-envoy
    transfer-encoding: chunked

配置Https

现在Https基本上已经是标配,这里也少不了,我们需要做三件事:

  • 创建一个Kubernetes sceret对象,用于保存服务器的证书和私钥。具体说来就是使用 kubectl 命令在命名空间 istio-system 中创建一个 secret 对象,命名为istio-ingressgateway-certs。Istio 网关会自动载入这个 secret。
    为了服务多个域名,我使用了Opaque类型,命名规则使用了{domain}.crt和{domain}.key。需要注意的是,对应的内容需要使用base64编码!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    apiVersion: v1
    kind: Secret
    type: Opaque
    metadata:
    name: istio-ingressgateway-certs
    namespace: istio-system
    data:
    httpbin.example.com.crt: {your-crt-content}
    httpbin.example.com.key: {your-key-content}
    another.example.com.crt: {your-crt-content}
    another.example.com.key: {your-key-content}
  • 把证书和私钥放于目录/etc/istio/ingressgateway-certs,需要注意的是,这里指的是宿主机器(集群的Master),又或者是你执行kubectl命令的机器,因为我是在Master执行的命令,非本机上没验证过。
    把证书和私钥放于目录/etc/istio/ingressgateway-certs下,命名规则和第一步一致,如下:

    注意,这里只需要把文件原封不动的放进来,不需要base64编码

    1
    2
    3
    4
    5
    .
    ├── httpbin.example.com.crt
    ├── httpbin.example.com.key
    ├── another.example.com.crt
    └── another.example.com.key
  • 在Gateway上增加对https的配置声明。

    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
    ---
    apiVersion: networking.istio.io/v1alpha3
    kind: Gateway
    metadata:
    name: httpbin-gateway
    spec:
    selector:
    istio: ingressgateway # use Istio default gateway implementation
    servers:
    - port:
    number: 80
    name: http-httpbin
    protocol: HTTP
    hosts:
    - "httpbin.example.com"
    # 以下是新增内容
    tls:
    httpsRedirect: true # 强制跳转至https协议
    - port:
    number: 443
    name: https-httpbin
    protocol: HTTPS
    tls:
    mode: SIMPLE
    serverCertificate: /etc/istio/ingressgateway-certs/httpbin.example.com.crt
    privateKey: /etc/istio/ingressgateway-certs/httpbin.example.com.key
    hosts:
    - httpbin.example.com
    # 以上是新增内容
    ---
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
    name: httpbin
    spec:
    hosts:
    - "httpbin.example.com" ## 需与上面hosts域名对应
    gateways:
    - httpbin-gateway ## 需与上面metadata.name对应
    http:
    - match:
    - uri:
    prefix: /status ## 暴露路由
    - uri:
    prefix: /delay ## 暴露路由 (可以看到/headers和/get的路由暂时没有暴露)
    route:
    - destination:
    port:
    number: 8000
    host: httpbin ## service