Istio Routing 实践掌握virtualservice/gateway/destinationrule/AB版本发布/金丝雀发布

原文html

在学习像 Istio 这样的新技术时,看一下示例应用程序老是一个好主意。 Istio repo 有一些示例应用程序,但它们彷佛有各类不足。 文档中的 BookInfo 是一个很好的示例。 可是,对于我而言,它太冗长,服务太多,并且文档彷佛专一于管理 BookInfo 应用程序,而不是从头开始构建。 有一个较小的 hellohttp 例子,但它更多的是关于自动伸缩而不是其余。shell

在这篇文章中,我想介绍一下基础知识,并向您展现如何从头开始构建支持 Istio 的“hellohttp”应用程序。 要记住的一点是,Istio 只管理您应用的流量。 在这种状况下,应用程序生命周期由底层平台 Kubernetes 管理。 所以,您须要了解容器和 Kubernetes 基础知识,而且须要了解 Istio Routing 原语,例如 Gateway,VirtualService,DestinationRule。 我假设大多数人都知道容器和 Kubernetes 基础知识。 我将在本文中专一于 Istio Routing。api

基础步骤

如下这些大体就是您须要遵循的,以得到 Istio 的“hellohttp”应用程序的步骤:浏览器

  1. 建立一个 Kubernetes 集群并安装带有 sidecare 自动注入的 Istio。
  2. 使用您选择的语言建立 Hellohttp 应用程序,建立 Docker 镜像并将其推送到公共镜像仓库。
  3. 为你的容器建立 Kubernetes deployment 和 service。
  4. 建立 Gateway 以启用到群集的 HTTP(S)流量。
  5. 建立 VirtualService,经过 Gateway 公开 Kubernetes 服务。
  6. (可选)若是要建立多个版本应用程序,请建立 DestinationRule 以定义可从 VirtualService 引用的 subsets。
  7. (可选)若是要在服务网格外部调用其余外部服务,请建立 ServiceEntry。

我不会在本文中介绍步骤 1 和 2,由于它们不是特定于 Istio 的。 若是您须要有关这些步骤的帮助,能够查看我在本文末尾提到的文章。 第 3 步也不是 Istio 特定的,但它是其余一切的先决条件,因此让咱们从那开始。app

Deployment 和 Service

正如我所提到的,应用程序生命周期由 Kubernetes 管理。 所以,您须要从建立 Kubernetes deployment 和 service 开始。 个人状况以下,我有一个容器化的 ASP.NET 核心应用程序,其镜像我已经推送到谷歌镜像仓库。 让咱们从建立一个hellohttp-deploy.yaml.yaml文件开始:负载均衡

apiVersion: v1
kind: Service
metadata:
  name: hellohttp-service
  labels:
    app: hellohttp
spec:
  ports:
    - port: 80
      name: http
  selector:
    app: hellohttp
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hellohttp-v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hellohttp
      version: v1
  template:
    metadata:
      labels:
        app: hellohttp
        version: v1
    spec:
      containers:
        - name: hellohttp
          image: busybox 
          imagePullPolicy: IfNotPresent
          command: ["/bin/sh", "-c", "echo 'hello httpd v1' > /var/www/index.html; httpd -f -p 80 -h /var/www/"]
          ports:
            - containerPort: 80

建立 Deployment 和 Service:ide

$ kubectl apply -f hellohttp-deploy.yaml
service "hellohttp-service" created
deployment.extensions "hellohttp-v1" created

到目前为止没有任何特定的针对 Istio 的内容。学习

Gateway

咱们如今能够开始研究 Istio Routing。 首先,咱们须要为服务网格启用 HTTP/HTTPS 流量。 为此,咱们须要建立一个网关。 Gateway 描述了在边缘运行的负载均衡,用于接收传入或传出的 HTTP/TCP 链接。测试

让咱们建立一个hellohttp-gateway.yaml文件:google

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: hellohttp-gateway
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - "hellohttp.com"

建立 Gateway:

$ kubectl apply -f hellohttp-gateway.yaml
gateway.networking.istio.io "hellohttp-gateway" created

此时,咱们为集群启用了 HTTP 流量。 咱们须要将以前建立的 Kubernetes 服务映射到 Gateway。 咱们将使用 VirtualService 执行此操做。

VirtualService

VirtualService 实际上将 Kubernetes 服务链接到 Istio 网关。 它还能够执行更多操做,例如定义一组流量路由规则,以便在主机被寻址时应用,但咱们不会深刻了解这些细节。

让咱们建立一个hellohttp-virtualservice.yaml文件:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: hellohttp-virtualservice
spec:
  hosts:
    - "hellohttp.com"
  gateways:
    - hellohttp-gateway
  http:
    - route:
        - destination:
            host: hellohttp-service

请注意,VirtualService 与特定网关绑定,并定义引用 Kubernetes 服务的主机。

建立 VirtualService:

$ kubectl apply -f hellohttp-virtualservice.yaml
virtualservice.networking.istio.io "hellohttp-virtualservice" created

测试 V1 版本 APP

咱们准备测试咱们的应用程序了。 咱们须要获取 Istio Ingress Gateway 的 IP 地址:

$ istio-ingressgateway   NodePort   10.109.111.38   <none>        15020:32105/TCP,80:30824/TCP,443:32478/TCP,31400:32419/TCP,15443:30884/TCP   4d

当咱们在浏览器中打开NodePort-IP时,咱们应该看到 hellohttp ASP.NET Core 应用程序:

DestinationRule

在某些时候,您但愿将应用更新为新版本。 也许你想分割两个版本之间的流量。 您须要建立一个 DestinationRule 来定义是哪些版本,在 Istio 中称为 subset。

首先,更新 hellohttp-deploy.yaml 文件以使用 v2 版本的容器定义 v2 的 deployment:

apiVersion: v1
kind: Service
metadata:
  name: hellohttp-service
  labels:
    app: hellohttp
spec:
  ports:
    - port: 80
      name: http
  selector:
    app: hellohttp
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hellohttp-v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hellohttp
      version: v1
  template:
    metadata:
      labels:
        app: hellohttp
        version: v1
    spec:
      containers:
        - name: hellohttp
          image: busybox 
          imagePullPolicy: IfNotPresent
          command: ["/bin/sh", "-c", "echo 'hello httpd v1' > /var/www/index.html; httpd -f -p 80 -h /var/www/"]
          ports:
            - containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hellohttp-v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hellohttp
      version: v2
  template:
    metadata:
      labels:
        app: hellohttp
        version: v2
    spec:
      containers:
        - name: hellohttp
          image: busybox 
          imagePullPolicy: IfNotPresent
          command: ["/bin/sh", "-c", "echo 'hello httpd v2' > /var/www/index.html; httpd -f -p 80 -h /var/www/"]
          ports:
            - containerPort: 80

建立新的 Deployment:

$ kubectl apply -f hellohttp-deploy.yaml
service "hellohttp-service" unchanged
deployment.extensions "hellohttp-v1" unchanged
deployment.extensions "hellohttp-v2" created

若是使用 EXTERNAL-IP 刷新浏览器,您将看到应用程序的 v1 和 v2 版本交替出现:

这是符合预期的,由于两个版本都暴露在相同的 Kubernetes 服务以后:hellohttp-service。

若是您想将服务仅指向 v2,该怎么办? 这能够经过在 VirtualService 中指定 subset 来完成,但咱们须要首先在 DestinationRules 中定义这些 subset。 DestinationRule 本质上是将标签映射到 Istio 的 subset。

建立一个hellohttp-destinationrule.yaml文件:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: hellohttp-destinationrule
spec:
  host: hellohttp-service
  trafficPolicy:
    tls:
      mode: ISTIO_MUTUAL
  subsets:
    - name: v1
      labels:
        version: v1
    - name: v2
      labels:
        version: v2

建立 DestinationRule:

$ kubectl apply -f hellohttp-destinationrule.yaml
destinationrule.networking.istio.io "hellohttp-destinationrule" created

如今你能够从 VirtualService 来引用 v2 subset:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: hellohttp-virtualservice
spec:
  hosts:
    - "hellohttp.com"
  gateways:
  - hellohttp-gateway
  http:
  - route:
    - destination:
        host: hellohttp-service
         subset: v2

更新 VirtualService:

$ kubectl apply -f hellohttp-virtualservice.yaml
virtualservice.networking.istio.io "hellohttp-virtualservice" configured

若是您如今继续浏览 EXTERNAL-IP,您如今应该只能看到应用程序的 v2 版本。

测试AB版本更新

能够从 VirtualService 来引用v2 subset和v1 subset

[root@localhost hello-world]# cat hellohttp-virtualservice.yaml 
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: hellohttp-virtualservice
spec:
  hosts:
    - "hellohttp.com"
  gateways:
    - hellohttp-gateway
  http:
    - route:
        - destination:
            host: hellohttp-service
            subset: v1
          weight: 75
        - destination:
            host: hellohttp-service
            subset: v2
          weight: 25

上面的配置就是经过VirtualService 调用DestinationRule 里面定义的host分类,来进行AB 版本的流量分离,进行AB 版本更新。

对于生产环境里面的版本更新能够进行header 主机头匹配,进行版本区分,基础的金丝雀发布更新版本就是这样实现的。

ServiceEntry

我想在 Istio Routing 中提到的最后一件事是 ServiceEntry。 默认状况下,Istio 中的全部外部流量都被阻止。 若是要启用外部流量,则须要建立 ServiceEntry 以列出为外部流量启用的协议和主机。 我不会在这篇文章中展现一个例子,但你能够在这里阅读更多相关内容。

但愿这篇文章对你有用! 若是您想了解更多信息,可使用 codelab 系列如下两部分,其中全部这些概念和更多内容将在逐步的详细教程中进行说明: