1. 故事背景

这个没背景,用了Istio,就代表了TA接管了整个网络,进进出出就得经过TA,这样你才可以得到好处。但是不是说啥也不干就可以随进随出,嗯,你得告诉TA。

2. 提前准备

  • 本次试验是在CentOS 7.4 64位系统,root用户下进行
  • Kubernetes(k8s)集群
  • istio版本1.0.2

3. 实践

3.1 简述

参考官网文档:配置请求路由用 HTTPS 加密 Gateway

在公有云(阿里云)上,service支持LoadBalancer,而自建的不支持。当service指定类型为LoadBalancer,阿里云会在负载均衡服务里,新增一个实例,同时会提供一个公网IP,通过这个IP就可以访问到对应的service,而ingressgateway默认就是这种方式。在这一点上,我的自建集群(用于测试环境)和阿里云K8S集群(用于生产环境)在使用上会有少许差别。

现在我先描述大家共同的部分,也是属于Istio的部分。到最后,再把少许的差别补充上,仅在测试环境需要。

3.2 配置Http

任务:把域名foo.bar.com指向k8s服务bar

前置条件:

  • namespace为foo
  • 拥有service,名为bar,端口80
  • 假设拥有域名 foo.bar.com

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

---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bar
  namespace: foo
spec:
  selector:
    istio: ingressgateway # 此配置必须有
  servers:
  - port:
      number: 80
      name: http-bar
      protocol: HTTP
    hosts:
    - foo.bar.com
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bar
  namespace: foo
spec:
  hosts:
  - foo.bar.com
  gateways:
  - bar
  http:
  - match:
    - uri:
        prefix: "/"
    route:
    - destination:
        host: bar
        port:
          number: 80

3.3 配置Https

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

  1. 创建一个Kubernetes sceret对象,用于保存服务器的证书和私钥。具体说来就是使用 kubectl 命令在命名空间 istio-system 中创建一个 secret 对象,命名为istio-ingressgateway-certs。Istio 网关会自动载入这个 secret。

  2. 把证书和私钥放于目录/etc/istio/ingressgateway-certs,需要注意的是,这里指的是宿主机器(集群的Master),又或者是你执行kubectl命令的机器,因为我是在Master执行的命令,非本机上没验证过。

  3. Gateway上增加对https的配置声明。

第一件事 - 配置Secret

为了服务多个域名,我使用了Opaque类型,命名规则使用了{domain}.crt{domain}.key。需要注意的是,对应的内容需要使用base64编码!

apiVersion: v1
kind: Secret
type: Opaque
metadata:
  name: istio-ingressgateway-certs
  namespace: istio-system
data:
  foo.bar.com.crt: {your-crt-content}
  foo.bar.com.key: {your-key-content}
  foo2.bar.com.crt: {your-crt-content}
  foo2.bar.com.key: {your-key-content}

第二件事 - 放置证书和私钥

把证书和私钥放于目录/etc/istio/ingressgateway-certs下,命名规则和第一步一致,如下:

# 注意,这里只需要把文件原封不动的放进来,不需要base64编码
.
├── foo.bar.com.crt
├── foo.bar.com.key
├── foo2.bar.com.crt
└── foo2.bar.com.key

第三件事 - 增加配置

以下是修改后的完整配置

---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bar
  namespace: foo
spec:
  selector:
    istio: ingressgateway # 此配置必须有
  servers:
  - port:
      number: 80
      name: http-bar
      protocol: HTTP
    hosts:
    - foo.bar.com
  # 以下是新增内容
    tls:
      httpsRedirect: true # 强制跳转至https协议
  - port:
      number: 443
      name: https-bar
      protocol: HTTPS
    tls:
      mode: SIMPLE
      serverCertificate: /etc/istio/ingressgateway-certs/foo.bar.com.crt
      privateKey: /etc/istio/ingressgateway-certs/foo.bar.com.key
    hosts:
    - foo.bar.com
  # 以上是新增内容

---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: bar
  namespace: foo
spec:
  hosts:
  - foo.bar.com
  gateways:
  - bar
  http:
  - match:
    - uri:
        prefix: "/"
    route:
    - destination:
        host: bar
        port:
          number: 80

3.4 少许差别

一般到了这一步,只需要把域名解析指向到负载均衡的IP,就可以生效。(至少在阿里云K8S集群是这样的)。

然而在我自建的集群里,我早前已经使用了另外一个名为traefik的Ingress,而且自建并不支持LoadBalancer。所以在还没用Istio前,整条链路是这样的。

域名解析 👉 自行创建的负载均衡实例(公有IP) 👉 Traefik Ingress 👉 Service

当我使用了Istio后,在这个环境下,负载均衡貌似没办法直接到达Istio的Ingressgateway,具体原因我没有深究,就当是的情况,我用了取巧的方式,把traefik的Ingress再转发给Ingressgateway,具体如下:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: bar
  namespace: istio-system
  annotations:
    kubernetes.io/ingress.class: traefik
    traefik.frontend.passHostHeader: "true"
spec:
  rules:
  - host: 'foo.bar.com'
    http:
      paths:
      - path: /
        backend:
          serviceName: istio-ingressgateway
          servicePort: 80 

所以最终整条链路如下:

域名解析 👉 自行创建的负载均衡实例(公有IP) 👉 Traefik Ingress 👉 Ingressgateway 👉 Service

4. 总结

总的来说,配置还是比较直接简单,至于上面说的少许差距,在日后,有机会可深入再了解一下。这里肯定有更好的更简单的解决方案。