如何使用Istio和Kubernetes进行金丝雀部署

在引入新版本的服务时,通常需要在逐步淘汰旧版本的过程中将受控百分比的用户流量转移到较新版本的服务。这种技术称为金丝雀部署。在本教程中,您将使用带有Kubernetes的Istio创建一个canary部署。

介绍

在引入新版本的服务时,通常需要在逐步淘汰旧版本的过程中将受控百分比的用户流量转移到较新版本的服务。 这种技术称为金丝雀部署

Kubernetes集群运营商可以使用标签部署本地协调canary部署 然而,该技术具有某些限制:流量分配和复制计数是耦合的,这实际上意味着必须手动控制复制比率以限制到金丝雀释放的流量。 换句话说,要将10%的流量引导到金丝雀部署,您需要拥有10个pod的池,其中一个pod接收10%的用户流量,另外9个接收其余的流量。

使用Istio服务网格进行部署可以通过在副本计数和流量管理之间实现明确分离来解决此问题。 Istio网格允许细粒度的流量控制,将流量分配和管理与副本扩展分离。 您可以定义流量百分比和目标,而不是手动控制副本比率,而Istio将管理其余部分。

在本教程中,您将使用Istio和Kubernetes创建一个canary部署。 您将部署两个版本的演示Node.js应用程序,并使用虚拟服务目标规则资源来配置到新版本和旧版本的流量路由。 这将成为使用Istio构建未来金丝雀部署的良好起点。

先决条件

注意:我们强烈建议使用具有至少8GB可用内存和4vCPU的群集进行此设置。 本教程将使用DigitalOcean的三个标准4GB / 2vCPU Droplet作为节点。

第1步 - 打包应用程序

在先决条件教程“ 如何使用Kubernetes安装和使用Istio”中 ,您创建了一个node-demo Docker镜像来运行鲨鱼信息应用程序并将此图像推送到Docker Hub。 在此步骤中,您将创建另一个映像:将用于金丝雀部署的较新版本的应用程序。

我们的原始演示应用程序在其Shark Info页面上强调了一些关于鲨鱼的友好事实:

鲨鱼信息页

但我们在新的金丝雀版本中决定强调一些可怕的事实:

可怕的鲨鱼信息页面

我们的第一步是将应用程序的第二个版本的代码克隆到名为node_image的目录中。 使用以下命令,从DigitalOcean社区GitHub帐户克隆nodejs-canary-app存储库 此存储库包含我们的应用程序的第二个更可怕的版本的代码:

git clone https://github.com/do-community/nodejs-canary-app.git node_image

导航到node_image目录:

cd node_image

此目录包含较新版本的shark信息应用程序的文件和文件夹,该应用程序为用户提供有关鲨鱼的信息,如原始应用程序,但强调可怕的事实。 除了应用程序文件之外,该目录还包含一个Dockerfile,其中包含使用应用程序代码构建Docker镜像的说明。 有关Dockerfile中的说明的更多信息,请参阅如何使用Docker构建Node.js应用程序的第3步

要测试应用程序代码和Dockerfile是否按预期工作,可以使用docker build命令构建和标记映像,然后使用该映像运行演示容器。 -t标志与docker build将允许您使用Docker Hub用户名标记映像,以便在测试后将其推送到Docker Hub。

使用以下命令构建映像:

docker build -t your_dockerhub_username/node-demo-v2 .

. 在命令中指定构建上下文是当前目录。 我们将图像命名为node-demo-v2 ,以引用我们如何使用Kubernetes安装和使用Istio中 创建node-demo图像。

构建过程完成后,您可以使用docker images列出docker images

docker images

您将看到以下输出确认图像构建:

REPOSITORY                            TAG                 IMAGE ID            CREATED             SIZE
your_dockerhub_username/node-demo-v2  latest              37f1c2939dbf        5 seconds ago       77.6MB
node                                  10-alpine           9dfa73010b19        2 days ago          75.3MB

接下来,您将使用docker run基于此图像创建容器。 我们将使用此命令包含三个标志:

  • -p :这将在容器上发布端口并将其映射到主机上的端口。 我们将在主机上使用端口80 ,但如果您在该端口上运行另一个进程,则可以根据需要随意修改它。 有关其工作原理的更多信息,请参阅有关端口绑定的Docker文档中的此讨论。
  • -d :这在后台运行容器。
  • --name :这允许我们为容器提供自定义名称。

运行以下命令来构建容器:

docker run --name node-demo-v2 -p 80:8080 -d your_dockerhub_username/node-demo-v2

使用docker ps检查正在运行的容器:

docker ps

您将看到确认您的应用程序容器正在运行的输出:

CONTAINER ID        IMAGE                                  COMMAND                  CREATED             STATUS              PORTS                  NAMES
49a67bafc325        your_dockerhub_username/node-demo-v2   "docker-entrypoint.s…"   8 seconds ago       Up 6 seconds        0.0.0.0:80->8080/tcp   node-demo-v2

您现在可以在浏览器中访问您的服务器IP以测试您的设置: http:// your_server_ip 您的应用程序将显示以下登录页面:

申请登陆页面

单击“ 获取鲨鱼信息”按钮以获取更可怕的鲨鱼信息:

可怕的鲨鱼信息页面

现在您已经测试了应用程序,您可以停止正在运行的容器。 再次使用docker ps获取您的CONTAINER ID

docker ps
CONTAINER ID        IMAGE                                  COMMAND                  CREATED              STATUS              PORTS                  NAMES
49a67bafc325        your_dockerhub_username/node-demo-v2   "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:80->8080/tcp   node-demo-v2

docker stop停止容器。 请务必使用您自己的应用程序CONTAINER ID替换此处列出的CONTAINER ID

docker stop 49a67bafc325

现在您已经测试了图像,可以将其推送到Docker Hub。 首先,登录您在先决条件中创建的Docker Hub帐户:

docker login -u your_dockerhub_username 

出现提示时,输入您的Docker Hub帐户密码。 以这种方式登录将使用您的Docker Hub凭据在非root用户的主目录中创建~/.docker/config.json文件。

使用docker push命令将应用程序映像推送到Docker Hub。 请记住将your_dockerhub_username替换为您自己的Docker Hub用户名:

docker push your_dockerhub_username/node-demo-v2

现在,您已将两个应用程序映像保存到Docker Hub: node-demo映像和node-demo-v2 我们现在将修改您在必备教程如何安装和使用Istio With Kubernetes中创建的清单,以将流量定向到应用程序的canary版本。

第2步 - 修改应用程序部署

如何使用Kubernetes安装和使用Istio中 ,您创建了一个应用程序清单,其中包含应用程序服务部署对象的规范 这些规范描述了每个对象的所需状态。 在此步骤中,您将为此清单添加应用程序的第二个版本的部署,以及将使Istio能够管理这些资源的版本标签。

按照先决条件教程中的设置说明操作时,您创建了一个名为istio_project的目录和两个yaml清单: node-app.yaml ,其中包含Service和Deployment对象的规范, node-istio.yaml ,其中包含您的Istio虚拟服务和网关资源。

立即导航到istio_project目录:

cd
cd istio_project

使用nano或您喜欢的编辑器打开node-app.yaml来更改应用程序清单:

nano node-app.yaml

目前,该文件如下所示:

〜/节点istio.yaml
apiVersion: v1
kind: Service
metadata:
  name: nodejs
  labels: 
    app: nodejs
spec:
  selector:
    app: nodejs
  ports:
  - name: http
    port: 8080 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nodejs
  labels:
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nodejs
  template:
    metadata:
      labels:
        app: nodejs
        version: v1
    spec:
      containers:
      - name: nodejs
        image: your_dockerhub_username/node-demo
        ports:
        - containerPort: 8080

有关此文件内容的完整说明,请参阅如何使用Kubernetes安装和使用Istio的 第3步

我们已经在我们的部署metadatatemplate字段中包含了版本标签,遵循Istio对Pod和服务的建议 现在我们可以为第二个Deployment对象添加规范,它将代表我们应用程序的第二个版本,并快速修改我们的第一个Deployment对象的name

首先,将现有Deployment对象的名称更改为nodejs -v1

〜/节点istio.yaml
...
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nodejs-v1
  labels:
    version: v1
...

接下来,在此部署的规范下方,添加第二个部署的规范。 请记住将您自己图像的名称添加到image字段:

〜/节点istio.yaml
...
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nodejs-v2
  labels:
    version: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nodejs
  template:
    metadata:
      labels:
        app: nodejs
        version: v2
    spec:
      containers:
      - name: nodejs
        image: your_dockerhub_username/node-demo-v2
        ports:
        - containerPort: 8080

与第一次部署一样,此部署使用version标签指定与此部署对应的应用程序的版本。 在这种情况下, v2将区分与此部署关联的应用程序版本与v1 ,后者对应于我们的第一个部署。

我们还确保由v2部署管理的v2将运行我们在上一步中构建的node-demo-v2 canary图像。

完成编辑后保存并关闭文件。

修改了应用程序清单后,您可以继续更改node-istio.yaml文件。

第3步 - 使用虚拟服务加权流量并添加目标规则

如何使用Kubernetes安装和使用Istio中 ,您创建了网关和虚拟服务对象,以允许外部流量进入Istio网格并将其路由到您的应用程序服务。 在这里,您将修改虚拟服务配置以包括到应用程序服务子集的路由 - v1v2 您还将添加目标规则 ,以便为要应用于nodejs应用程序服务的路由规则定义其他基于版本的策略。

打开node-istio.yaml文件:

nano node-istio.yaml

目前,该文件如下所示:

〜/ istio_project /节点istio.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: nodejs-gateway
spec:
  selector:
    istio: ingressgateway 
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: nodejs
spec:
  hosts:
  - "*"
  gateways:
  - nodejs-gateway
  http:
  - route:
    - destination:
        host: nodejs

有关此清单中规范的完整说明,请参阅如何使用Kubernetes安装和使用Istio的 第4步

我们的第一个修改是虚拟服务。 目前,该资源将通过nodejs-gateway进入网格的流量路由到我们的nodejs应用服务。 我们想要做的是配置一个路由规则,它将80%的流量发送到我们的原始应用程序,20%发送到更新的版本。 一旦我们对金丝雀的性能感到满意,我们就可以重新配置我们的流量规则,逐步将所有流量发送到更新的应用程序版本。

我们不会像在原始清单中那样路由到单个destination ,而是为我们的两个应用程序子集添加destination字段:原始版本( v1 )和金丝雀( v2 )。

对虚拟服务进行以下添加以创建此路由规则:

〜/ istio_project /节点istio.yaml
...
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: nodejs
spec:
  hosts:
  - "*"
  gateways:
  - nodejs-gateway
  http:
  - route:
    - destination:
        host: nodejs
        subset: v1
      weight: 80
    - destination:
        host: nodejs
        subset: v2
      weight: 20

我们添加的策略包括两个目标: nodejssubset运行我们的应用程序的原始版本的服务v1 ,以及运行canary的subset v2 子集1将接收80%的传入流量,而金丝雀将接收20%。

接下来,我们将添加一个目标规则,该规则将流量路由到相应的服务后将规则应用于传入流量。 在我们的示例中,我们将配置subset字段以使用适当的版本标签向Pod发送流量。

在虚拟服务定义下添加以下代码:

〜/ istio_project /节点istio.yaml
...
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: nodejs
spec:
  host: nodejs
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2

我们的规则确保我们的服务子集v1v2流量到达具有相应标签的Pod: version: v1version: v2 这些是我们在应用程序部署规范中包含的标签。

但是,如果我们想要,我们也可以在子集级别应用特定的流量策略,从而在我们的canary部署中实现更具体的特性。 有关在此级别定义流量策略的其他信息,请参阅官方的Istio文档

完成编辑后保存并关闭文件。

修改了应用程序清单后,您就可以使用Grafana遥测插件应用配置更改并检查应用程序流量数据。

第4步 - 应用配置更改和访问流量数据

应用程序清单已更新,但我们仍需要将这些更改应用于我们的Kubernetes集群。 我们将使用kubectl apply命令应用我们的更改,而不会完全覆盖现有配置。 完成此操作后,您将能够为您的应用程序生成一些请求,并查看Istio Grafana仪表板中的相关数据。

将配置应用于应用程序服务和部署对象:

kubectl apply -f node-app.yaml

您将看到以下输出:

service/nodejs unchanged
deployment.apps/nodejs-v1 created
deployment.apps/nodejs-v2 created

接下来,将您所做的配置更新应用于node-istio.yaml ,其中包括对虚拟服务和新目标规则的更改:

kubectl apply -f node-istio.yaml

您将看到以下输出:

gateway.networking.istio.io/nodejs-gateway unchanged
virtualservice.networking.istio.io/nodejs configured
destinationrule.networking.istio.io/nodejs created

您现在已准备好为您的应用程序生成流量。 但是,在执行此操作之前,请首先检查以确保您运行grafana服务:

kubectl get svc -n istio-system | grep grafana
grafana                  ClusterIP      10.245.233.51    <none>           3000/TCP                                                                                                                                     4d2h

还要检查相关的Pod:

kubectl get svc -n istio-system | grep grafana
grafana-67c69bb567-jpf6h                 1/1     Running     0          4d2h

最后,检查grafana-gateway网关和grafana-vs虚拟服务:

kubectl get gateway -n istio-system | grep grafana
grafana-gateway   3d5h
kubectl get virtualservice -n istio-system | grep grafana
grafana-vs   [grafana-gateway]   [*]     4d2h

如果您没有看到这些命令的输出,请查看如何安装和使用Istio with Kubernetes的步骤25 ,其中讨论如何在安装Istio时启用Grafana遥测插件以及如何启用对Grafana服务的HTTP访问。

您现在可以在浏览器中访问您的应用程序。 为此,您需要与istio-ingressgateway服务相关联的外部IP,这是一种LoadBalancer服务类型 我们在如何使用Kubernetes安装和使用Istio中编写网关清单时,将nodejs-gateway网关与此控制器进行了匹配 有关网关清单的更多详细信息,请参阅该教程的第4步

使用以下命令获取istio-ingressgateway服务的外部IP:

kubectl get svc -n istio-system

您将看到如下输出:

NAME                     TYPE           CLUSTER-IP       EXTERNAL-IP       PORT(S)                                                                                                                                      AGE
grafana                  ClusterIP      10.245.85.162    <none>            3000/TCP                                                                                                                                     42m
istio-citadel            ClusterIP      10.245.135.45    <none>            8060/TCP,15014/TCP                                                                                                                           42m
istio-galley             ClusterIP      10.245.46.245    <none>            443/TCP,15014/TCP,9901/TCP                                                                                                                   42m
istio-ingressgateway     LoadBalancer   10.245.171.39    ingressgateway_ip 15020:30707/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:30285/TCP,15030:31668/TCP,15031:32297/TCP,15032:30853/TCP,15443:30406/TCP   42m
istio-pilot              ClusterIP      10.245.56.97     <none>            15010/TCP,15011/TCP,8080/TCP,15014/TCP                                                                                                       42m
istio-policy             ClusterIP      10.245.206.189   <none>            9091/TCP,15004/TCP,15014/TCP                                                                                                                 42m
istio-sidecar-injector   ClusterIP      10.245.223.99    <none>            443/TCP                                                                                                                                      42m
istio-telemetry          ClusterIP      10.245.5.215     <none>            9091/TCP,15004/TCP,15014/TCP,42422/TCP                                                                                                       42m
prometheus               ClusterIP      10.245.100.132   <none>            9090/TCP                                                                                                                                     42m

istio-ingressgateway应该是唯一具有TYPE LoadBalancer的服务,并且是唯一具有外部IP的服务。

在浏览器中导航到此外部IP: http:// ingressgateway_ip

您应该会看到以下目标网页:

申请登陆页面

单击“ 获取鲨鱼信息”按钮。 您将看到两个鲨鱼信息页面中的一个:

鲨鱼信息页

可怕的鲨鱼信息页面

点击此页面上的刷新几次。 您应该比更可怕的版本更频繁地看到更友好的鲨鱼信息页面。

通过刷新五到六次产生一些负载后,您可以转到Grafana仪表板。

在浏览器中,再次使用istio-ingressgateway外部IP和Grafana网关清单中定义的端口导航到以下地址: http:// ingressgateway_ip:15031

您将看到以下登录页面:

Grafana Home Dash

单击页面顶部的主页将转到带有istio文件夹的页面。 要获取下拉选项列表,请单击istio文件夹图标:

Istio Dash选项下拉菜单

从此选项列表中,单击Istio Service Dashboard

这将带您进入另一个下拉菜单的登录页面:

Istio Service Dash中的服务下拉列表

从可用选项列表中选择nodejs.default.svc.cluster.local

如果您向下导航到页面的“ 服务工作负载”部分,您将能够查看按目的地和响应代码的传入请求

服务工作负载仪表板

在这里,您将看到200和304 HTTP响应代码的组合,表示成功的OKNot Modified响应。 标记为nodejs-v1的响应应超过标记为nodejs-v2的响应,表示传入的流量将按照我们在清单中定义的参数路由到应用程序子集。

结论

在本教程中,您使用Istio和Kubernetes部署了一个演示Node.js应用程序的canary版本。 您创建了虚拟服务和目标规则资源,这些资源共同允许您将80%的流量发送到原始应用程序服务,20%发送到较新版本。 一旦您对较新的应用程序版本的性能感到满意,就可以根据需要更新配置设置。

有关Istio中流量管理的更多信息,请参阅文档中的相关高级概述 ,以及使用Istio的bookinfohelloworld示例应用程序的特定示例。