云原生之深入解析K8S Istio Gateway服务的架构分析与实战操作

一、概述

  • Istio 提供一种简单的方式来为已部署的服务建立网络,该网络具有负载均衡、服务间认证、监控、网关等功能,而不需要对服务的代码做任何改动。
    • istio 适用于容器或虚拟机环境(特别是 k8s),兼容异构架构;
    • istio 使用 sidecar(边车模式)代理服务的网络,不需要对业务代码本身做任何的改动;
    • HTTP、gRPC、WebSocket 和 TCP 流量的自动负载均衡;
    • istio 通过丰富的路由规则、重试、故障转移和故障注入,可以对流量行为进行细粒度控制;支持访问控制、速率限制和配额;
    • istio 对出入集群入口和出口中所有流量的自动度量指标、日志记录和跟踪;
    • istio 支持蓝绿发布和金丝雀发布(灰度发布)等。
  • Istio Gateway 描述在网格边缘运行的负载均衡器 接收传入或传出的 HTTP/TCP 连接,规格描述应公开的一组端口,协议的类型使用、负载均衡器的 SNI 配置等。
    • 使用网关为网格来管理入站和出站流量,可以让用户指定要进入或离开网格的流量;
    • Gateway 用于为 HTTP / TCP 流量配置负载均衡器,并不管该负载均衡器将在哪里运行,网格中可以存在任意数量的 Gateway,并且多个不同的 Gateway 实现可以共存。实际上,通过在配置中指定一组工作负载(Pod)标签,可以将 Gateway 配置绑定到特定的工作负载,从而允许用户通过编写简单的 Gateway Controller 来重用现成的网络设备;
    • Gateway 只用于配置 L4-L6 功能(例如,对外公开的端口,TLS 配置),所有主流的 L7 代理均以统一的方式实现了这些功能,然后,通过在 Gateway 上绑定 VirtualService 的方式,可以使用标准的 Istio 规则来控制进入 Gateway 的 HTTP 和 TCP 流量。
  • Istio 相关的学习文档:

二、Istio 架构

  • 在 Kubernetes 环境中,Ingress controller 用于管理进入集群的流量,在 Istio 服务网格中 Istio Ingress Gateway 承担相应的角色,它使用新的配置模型(Gateway 和 VirtualServices)完成流量管理的功能。
  • Istio 架构大致如下:
  • 分析说明:
    • 上图 ①:用户向某端口发出请求;
    • 上图 ②:负载均衡器监听端口,并将请求转发到集群中的某个节点上,Istio Ingress Gateway Service 会监听集群节点端口的请求;
    • 上图 ③:Istio Ingress Gateway Service 将请求交给 Istio Ingress Gateway Pod 处理,IngressGateway Pod 通过 Gateway 和 VirtualService 配置规则处理请求,其中,Gateway 用来配置端口、协议和证书,VirtualService 用来配置一些路由信息(找到请求对应处理的服务 App Service);
    • 上图 ④:Istio Ingress Gateway Pod 将请求转给 App Service;
    • 上图 ⑤:最终的请求会交给 App Service 关联的 App Deployment 处理。

三、通过 istioctl 部署 Istio

① 安装 istioctl 工具

rust 复制代码
wget https://github.com/istio/istio/releases/download/1.16.0/istio-1.16.0-linux-amd64.tar.gz
tar -xf istio-1.16.0-linux-amd64.tar.gz
ln -s /opt/istio/istioctl/istio-1.16.0/bin/istioctl /usr/local/bin/istioctl
istioctl version

② 通过 istioctl 安装 istio

  • 要想知道有哪几个内置的配置文件,可以运行以下命令:
rust 复制代码
istioctl profile list
  • 相关的配置文件如下表所示:
配置文件 核心组件 说明
default istio-ingressgateway、istiod 根据 IstioOperator API 的默认设置启动组件,可用于生产部署
demo istio-egressgateway、istio-ingressgateway、istiod 旨在展示 Istio 的功能,启用了高级别的追踪和访问日志(需要具有适度的资源),适合学习使用
minimal istiod 与默认配置文件相同,但只安装了控制平面组件
remote - 配置 Multicluster Mesh 的 Remote Cluster
empty - 不部署任何东西,可以作为自定义配置的基本配置文件
preview istio-ingressgateway、istiod 实验性,用于探索 Istio 的新功能,不确保稳定性、安全性和性能
  • 当足够熟悉 Istio 后,可以自定义配置文件:
rust 复制代码
### 查看 demo 的配置信息
istioctl profile dump demo

### 开始安装
# 【方式一】通过--set传参
istioctl install --set profile=demo

# 【方式二】通过-f指定文件
cat >my-demo-config.yaml<<EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  profile: demo
EOF

istioctl install -f my-demo-config.yaml

③ 检查

rust 复制代码
istioctl version
kubectl -n istio-system get deploy

四、Istio Gateway

  • 在 Kubernetes 环境中,Ingress controller 用于管理进入集群的流量,在 Istio 服务网格中 Istio Ingress Gateway 承担相应的角色,它使用新的配置模型(Gateway 和 VirtualServices)完成流量管理的功能。
    • 网关是一个运行在网格边缘的负载均衡器,用于接收传入或传出的 HTTP/TCP 连接;
    • 主要工作是接受外部请求,把请求转发到内部服务,网格边缘的 Ingress 流量,会通过对应的 Istio IngressGateway Controller 进入到集群内部。
  • Istio Gateway 的官方文档
  • 示例配置:
rust 复制代码
# cat gateway.yaml
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: canary-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*" # *表示通配符,通过任何域名都可以访问
  • 在上面这个 yaml 里配置了一个监听 80 端口的入口网关,它会将 80 端口的 http 流量导入到集群内对应的 Virtual Service 上。

五、Istio VirtualService 虚拟服务

  • VirtualService 是 Istio 流量治理的一个核心配置,可以说是 Istio 流量治理中最重要、最复杂的。VirtualService 在形式上表示一个虚拟服务,将满足条件的流量都转发到对应的服务后端,这个服务后端可以是一个服务,也可以是在 DestinationRule 中定义的服务的子集。
  • VirtualService 的官方文档
  • 示例配置:
rust 复制代码
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews-route
spec:
  hosts:
  - reviews.prod.svc.cluster.local
  http:
  - name: "reviews-v2-routes"
    match:
    - uri:
        prefix: "/wpcatalog"
    - uri:
        prefix: "/consumercatalog"
    rewrite:
      uri: "/newcatalog"
    route:
    - destination:
        host: reviews.prod.svc.cluster.local
        subset: v2
  - name: "reviews-v1-route"
    route:
    - destination:
        host: reviews.prod.svc.cluster.local
        subset: v1
  • 说明:

六、示例演示(bookinfo)

① 安装 bookinfo 应用

  • 在线书店 -bookinfo:该应用由四个单独的微服务构成,这个应用模仿在线书店的一个分类,显示一本书的信息,页面上会显示一本书的描述,书籍的细节(ISBN、页数等),以及关于这本书的一些评论。
  • Bookinfo 应用分为四个单独的微服务:
    • productpage 这个微服务会调用 details 和 reviews 两个微服务,用来生成页面;
    • details 这个微服务中包含了书籍的信息;
    • reviews 这个微服务中包含了书籍相关的评论,它还会调用 ratings 微服务;
    • ratings 这个微服务中包含了由书籍评价组成的评级信息。
  • reviews 微服务有 3 个版本:
    • v1 版本不会调用 ratings 服务;
    • v2 版本会调用 ratings 服务,并使用 1 到 5 个黑色星形图标来显示评分信息;
    • v3 版本会调用 ratings 服务,并使用 1 到 5 个红色星形图标来显示评分信息。
  • 创建命令空间:
rust 复制代码
kubectl create ns bookinfo
  • 添加 label,因为 Istio proxy 的注入是基于 label,因此需要为 demo namespace 添加 label:
rust 复制代码
kubectl label namespace bookinfo istio-injection=enabled
kubectl get ns --show-labels bookinfo
  • 开始部署 bookinfo:
rust 复制代码
cd /opt/istio/istioctl/istio-1.16.0
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -n bookinfo
kubectl get pod -n bookinfo
  • 然后可查看应用 pod 里的容器信息,可以看到已经被注入 istio-proxy:
rust 复制代码
kubectl get pod productpage-v1-bf4b489d8-gt7gw -n bookinfo -o jsonpath='{.status.containerStatuses}' | jq

② 添加路由规则

  • 服务部署后,还需要添加路由规则,将请求路由到对应的服务:
rust 复制代码
kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml -n bookinfo
kubectl get virtualservice -n bookinfo

③ 访问服务

  • 通过 NodePort 访问:
    • 获取 host ip,也就是 ingressgateway pod 所在机器 ip:
rust 复制代码
kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}'
    • 获取 port,也就是 80 端口映射的目的端口,即 31082:
rust 复制代码
kubectl -n istio-system get service istio-ingressgateway
  • 通过 externalip 访问:
    • 因为是本地测试,肯定没法使用公网的 LB,因此可以直接将 externalip 修改为某个 node 的 ip 或者 VIP,这是设置一个 VIP(跟 node 节点同网段),这样就能通过 80 端口访问:
rust 复制代码
kubectl -n istio-system get service istio-ingressgateway

kubectl patch svc istio-ingressgateway --namespace istio-system --patch '{"spec": { "externalIPs": ["192.168.182.210"] }}'
    • 从上图可知,会把 VIP 帮到 kube-ipvs0 虚拟网卡上,接下来就可以通过 VIP 访问 web:

④ 卸载 bookinfo 服务

rust 复制代码
cd /opt/istio/istioctl/istio-1.16.0
sh samples/bookinfo/platform/kube/cleanup.sh

⑤ 卸载 istio

rust 复制代码
istioctl manifest generate --set profile=demo | kubectl delete -f -

七、Istio Gateway 示例演示

① Helm 安装 Nginx,Apache

rust 复制代码
# 添加chart源
helm repo add bitnami https://charts.bitnami.com/bitnami

# 安装Nginx
helm pull bitnami/nginx --version 13.2.1
helm install my-nginx-1 ./nginx-13.2.1.tgz

# 安装Apache
helm pull bitnami/apache --version 9.2.7
helm install my-apache-1 ./apache-9.2.7.tgz

② http 测试

  • 配置 Gateway,网关将是应用于在带有标签的容器上运行的代理 app: my-grafana-gateway:
rust 复制代码
cat >my-http-gw.yaml<<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: my-http-gw
spec:
  selector:
    istio: ingressgateway # use Istio default gateway implementation
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - my-http-gw.com
EOF
  • 使用默认网关,istio: ingressgateway需要跟默认网关 svc 的 labels 字段对应:

② 配置 VirtualService

  • 要为进入上面的 Gateway 的流量配置相应的路由,必须为同一个 host 定义一个 VirtualService,并使用配置中的 gateways 字段绑定到前面定义的 Gateway 上:
rust 复制代码
cat >my-http-vs.yaml<<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings-route
spec:
  hosts:
  - my-http-gw.com
  gateways:
  - my-http-gw # <---- bind to gateway
  http:
  - match:
    - uri:
        prefix: /nginx-1
    rewrite:
      uri: /
    route:
    - destination:
        host: my-nginx-1.default.svc.cluster.local  #<---- server name
        port:
          number: 80
  - match:
    - uri:
        prefix: /apache-1
    rewrite:
      uri: /
    route:
    - destination:
        host: my-apache-1.default.svc.cluster.local  #<---- server name
        port:
          number: 80
EOF
  • 因为是本地测试,肯定没法使用公网的 LB,因此可以直接将 externalip 修改为某个 node 的 ip 或者同网段的 VIP,且 type: LoadBalancer,这样就能通过 80 端口访问:
rust 复制代码
kubectl -n istio-system get service istio-ingressgateway

# 192.168.182.210为VIP,无需自动创建,这个vip会自动绑定到kube-ipvs0虚拟网卡上
kubectl patch svc istio-ingressgateway --namespace istio-system --patch '{"spec": { "externalIPs": ["192.168.182.210"] }}'
  • 配置 hosts:
rust 复制代码
192.168.182.210 my-http-gw.com

③ 测试验证

rust 复制代码
http://my-http-gw.com/nginx-1


③ https 测试

  • 生成证书(有证书可忽略),自签名证书来只允许 https 流量来保证 istio ingress gateway 的安全:
rust 复制代码
openssl req -x509 -nodes -newkey rsa:2048 -keyout my-http-gw.com.key -out my-http-gw.com.cert -subj "/CN=*.my-http-gw.com"

### 证书添加到 kubernetes secret
kubectl create -n istio-system secret tls istio-ingressgateway-certs --key my-http-gw.com.key --cert my-http-gw.com.cert

### 查看证书和私钥是否部署成功
kubectl exec -it -n istio-system \
  $(kubectl -n istio-system get pods \
    -l istio=ingressgateway \
    -o jsonpath='{.items[0].metadata.name}') \
  -- ls -l /etc/istio/ingressgateway-certs/
  • 配置 Gateway 和 VirtualService:网关将是 应用于在带有标签的容器上运行的代理 app: my-grafana-gateway:
rust 复制代码
cat >my-https.yaml<<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: my-https-gw
spec:
  selector:
    istio: ingressgateway # use Istio default gateway implementation
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - my-http-gw.com
    tls:
     httpsRedirect: true
  - port:
      number: 443
      name: https
      protocol: HTTPS
    hosts:
    - my-http-gw.com
    tls:
      mode: SIMPLE
      serverCertificate: /opt/istio/test/tls/my-http-gw.com.crt
      privateKey: /opt/istio/test/tls/my-http-gw.com.key
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: https-route
spec:
  hosts:
  - my-https-gw.com
  gateways:
  - my-https-gw # <---- bind to gateway
  http:
  - match:
    - uri:
        prefix: /nginx-1
    rewrite:
      uri: /
    route:
    - destination:
        host: my-nginx-1  #<---- server name
        port:
          number: 80
  - match:
    - uri:
        prefix: /apache-1
    rewrite:
      uri: /
    route:
    - destination:
        host: my-apache-1  #<---- server name
        port:
          number: 80
EOF

八、Ingress Controller 与 Istio Gateway 比较

  • K8S 官方维护的 Nginx Ingress Controller 及 Istio Gateway 比较:
NGINX Ingress Controller Istio Gateway
根据 HTTP Header 选择路由规则 仅支持单个 Header,不支持多个 Header 组合 支持
Header 规则支持正则表达式 支持 支持
服务之间设置权重拆分流量 支持 支持
Header 和权重规则组合使用 支持 支持
路由规则检查 不支持 支持
路由规则粒度 service service 下的不同 pod
支持的协议 HTTP1.1/HTTP2/gRPC/TCP/Websockets HTTP1.1/HTTP2/gRPC/TCP/Websockets/MongoDB
  • 这样一比较,就很显然看出,Istio Gateway 比 Ingress Controller 强大,这里只是介绍了常用的负载转发功能,还有流量控制,安全控制等功能,如果只是简单的负载转发用 istio 就点大材小用了,如果公司需要更复杂网络管控,可以选择 istio,所以一般在生产环境中可以使用 Istio Gateway 应对复杂的网络环境。