本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。

使用 Istio 服务网格管理微服务

今天的文章由 Istio 团队撰写,展示了如何在 Kubernetes 中为微服务提供可见性、弹性、安全性和控制。

服务是现代软件架构的核心。部署一系列模块化、小型(微型)服务而不是大型单体服务,让开发人员可以灵活地在整个系统中使用不同的语言、技术和发布节奏;从而提高生产力和速度,尤其适用于大型团队。

然而,随着微服务的采用,由于大型系统中存在的服务数量庞大,新的问题也随之出现。对于单体应用只需解决一次的问题,如安全性、负载均衡、监控和速率限制,现在需要为每个服务单独处理。

Kubernetes 和服务

Kubernetes 通过 服务 构造支持微服务架构。它允许开发人员抽象出一组 Pod 的功能,并通过定义明确的 API 将其暴露给其他开发人员。它允许为这一抽象层添加名称并执行基本的 L4 负载均衡。但它无助于解决更高级别的问题,例如 L7 指标、流量拆分、速率限制、熔断等。

上周在 GlueCon 2017 大会上发布的 Istio 通过服务网格框架从根本上解决了这些问题。有了 Istio,开发人员可以实现微服务的核心逻辑,然后让框架负责其余部分——流量管理、发现、服务身份和安全性以及策略实施。更棒的是,这也可以应用于现有微服务,而无需重写或重新编译其任何部分。Istio 使用 Envoy 作为其运行时代理组件,并提供了一个 可扩展的中间层,允许全局跨领域策略实施和遥测数据收集。

Istio 的当前版本面向 Kubernetes 用户,并且以一种方式打包,您只需几行代码即可安装,并为 Kubernetes 中的微服务提供开箱即用的可见性、弹性、安全性和控制。

在一系列博客文章中,我们将研究一个由 4 个独立微服务组成的简单应用程序。我们将首先介绍如何使用纯 Kubernetes 部署应用程序。然后,我们将在启用 Istio 的集群中部署完全相同的服务,而无需更改任何应用程序代码——并查看如何观察指标。

在后续文章中,我们将重点介绍更高级的功能,例如 HTTP 请求路由、策略、身份和安全管理。

示例应用程序:BookInfo

我们将使用一个名为 BookInfo 的简单应用程序,它显示商店中书籍的信息、评论和评分。该应用程序由四种不同语言编写的微服务组成

BookInfo-all (2).png由于这些微服务的容器镜像都可以在 Docker Hub 中找到,因此我们只需要 Kubernetes 的 yaml 配置即可部署此应用程序。

值得注意的是,这些服务对 Kubernetes 和 Istio 没有依赖关系,但却是一个有趣的案例研究。特别是,评论服务的服务、语言和版本众多,使其成为一个有趣的服务网格示例。有关此示例的更多信息可以在此处找到。

在 Kubernetes 中运行 Bookinfo 应用程序

在这篇文章中,我们将重点关注应用程序的 v1 版本

BookInfo-v1 (3).png

使用 Kubernetes 部署它很简单,与其他任何服务的部署方式没有区别。 productpage 微服务的 Service 和 Deployment 资源如下所示

apiVersion: v1

kind: Service

metadata:

name: productpage

labels:

  app: productpage

spec:

type: NodePort

ports:

- port: 9080

  name: http

selector:

  app: productpage

---

apiVersion: extensions/v1beta1

kind: Deployment

metadata:

name: productpage-v1

spec:

replicas: 1

template:

  metadata:

    labels:

      app: productpage

      track: stable

  spec:

    containers:

    - name: productpage

      image: istio/examples-bookinfo-productpage-v1

      imagePullPolicy: IfNotPresent

      ports:

      - containerPort: 9080

如果我们想运行该应用程序,还需要部署另外两个服务:**details** 和 **reviews-v1**。此时我们不需要部署 **ratings** 服务,因为 reviews 服务的 v1 版本不使用它。其余服务基本上遵循与 **productpage** 相同的模式。所有服务的 yaml 文件都可以在 此处 找到。

将服务作为普通的 Kubernetes 应用程序运行

kubectl apply -f bookinfo-v1.yaml

要从集群外部访问应用程序,我们需要 **productpage** 服务的 NodePort 地址

export BOOKINFO\_URL=$(kubectl get po -l app=productpage -o jsonpath={.items[0].status.hostIP}):$(kubectl get svc productpage -o jsonpath={.spec.ports[0].nodePort})

我们现在可以将浏览器指向 http://$BOOKINFO_URL/productpage,并看到

使用 Istio 运行 Bookinfo 应用程序

现在我们已经看到了应用程序,我们将稍微调整部署以使其与 Istio 一起工作。我们首先需要在集群中安装 Istio。为了看到所有指标和跟踪功能,我们还安装了可选的 Prometheus、Grafana 和 Zipkin 插件。我们现在可以删除之前的应用程序并使用完全相同的 yaml 文件再次启动 Bookinfo 应用程序,这次是使用 Istio

kubectl delete -f bookinfo-v1.yaml

kubectl apply -f \<(istioctl kube-inject -f bookinfo-v1.yaml)

请注意,这次我们使用 `istioctl kube-inject` 命令修改 `bookinfo-v1.yaml`,然后再创建部署。它将 Envoy Sidecar 注入到 Kubernetes Pod 中,具体请参阅此处。因此,所有微服务都与 Envoy Sidecar 一起打包,该 Sidecar 管理服务的传入和传出流量。

在 Istio 服务网格中,我们不希望像在纯 Kubernetes 中那样直接访问应用程序 **productpage**。相反,我们希望请求路径中有一个 Envoy sidecar,这样我们就可以使用 Istio 的管理功能(版本路由、熔断器、策略等)来控制对 **productpage** 的外部调用,就像我们可以控制内部请求一样。Istio 的 Ingress 控制器用于此目的。

要使用 Istio Ingress 控制器,我们需要为应用程序创建一个 Kubernetes Ingress 资源,并使用 `kubernetes.io/ingress.class: "istio"` 进行标注,如下所示

cat \<\<EOF  ``` kubectl create -f -

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

name: bookinfo

annotations:

  kubernetes.io/ingress.class: "istio"

spec:

rules:

- http:

    paths:

    - path: /productpage

      backend:

        serviceName: productpage

        servicePort: 9080

    - path: /login

      backend:

        serviceName: productpage

        servicePort: 9080

    - path: /logout

      backend:

        serviceName: productpage

        servicePort: 9080

EOF

使用 Istio 和 bookinfo 应用的 v1 版本进行部署,结果如下

BookInfo-v1-Istio (5).png

这次我们将使用 Istio Ingress 控制器的 NodePort 地址访问应用程序

export BOOKINFO\_URL=$(kubectl get po -l istio=ingress -o jsonpath={.items[0].status.hostIP}):$(kubectl get svc istio-ingress -o jsonpath={.spec.ports[0].nodePort})

我们现在可以在 http://$BOOKINFO_URL/productpage 加载页面,并再次看到正在运行的应用程序——对于用户来说,应该与之前没有 Istio 的部署没有任何区别。

然而,现在应用程序正在 Istio 服务网格中运行,我们可以立即开始看到一些好处。

指标收集

我们从 Istio 开箱即用获得的第一件事是 Prometheus 中的指标收集。这些指标由 Envoy 中的 Istio 过滤器生成,根据默认规则(可以自定义)收集,然后发送到 Prometheus。指标可以在 Grafana 的 Istio 仪表板中可视化。请注意,虽然 Prometheus 是开箱即用的默认指标后端,但 Istio 允许您插入其他后端,我们将在未来的博客文章中演示。

为了演示,我们首先运行以下命令来为应用程序生成一些负载

wrk -t1 -c1 -d20s http://$BOOKINFO\_URL/productpage

我们获取 Grafana 的 NodePort URL

export GRAFANA\_URL=$(kubectl get po -l app=grafana -o jsonpath={.items[0].status.hostIP}):$(kubectl get svc grafana -o jsonpath={.spec.ports[0].nodePort})

我们现在可以在浏览器中打开 http://$GRAFANA_URL/dashboard/db/istio-dashboard,并检查每个 Bookinfo 服务的各种性能指标

istio-dashboard-k8s-blog.png

分布式追踪 接下来,我们从 Istio 获得的是使用 Zipkin 进行调用追踪。我们获取其 NodePort URL

export ZIPKIN\_URL=$(kubectl get po -l app=zipkin -o jsonpath={.items[0].status.hostIP}):$(kubectl get svc zipkin -o jsonpath={.spec.ports[0].nodePort})

我们现在可以将浏览器指向 http://$ZIPKIN_URL/,以查看通过 Bookinfo 服务的请求跟踪跨度。

尽管 Envoy 代理开箱即用地将跟踪跨度发送到 Zipkin,但要充分发挥其潜力,应用程序需要感知 Zipkin 并转发一些标头以将各个跨度关联起来。有关详细信息,请参阅 zipkin-tracing

整个机群的整体视图 Istio 提供的指标不仅仅是方便。通过在整个服务网格中生成统一指标,它们提供了服务网格的一致视图。我们不必担心协调各种运行时代理发出的不同类型的指标,也不必添加任意代理来为未检测的遗留应用程序收集指标。我们也不再需要依赖开发过程来正确检测应用程序以生成指标。服务网格能够看到所有流量,甚至包括进出遗留“黑盒”服务的流量,并为所有这些流量生成指标。 总结 上述演示展示了如何通过几个步骤启动 Istio 支持的服务并观察其上的 L7 指标。在接下来的几周,我们将继续演示 Istio 的更多功能,例如策略管理和 HTTP 请求路由。Google、IBM 和 Lyft 联手创建了 Istio,这是基于我们在为内部和企业客户构建和运营大型复杂微服务部署方面的共同经验。Istio 是一项行业范围的社区工作。我们很高兴看到行业合作伙伴的热情以及他们带来的见解。当我们迈出下一步并将 Istio 发布到野外时,我们迫不及待地想看到更广泛的贡献者社区将为它带来什么。如果您正在使用或考虑在 Kubernetes 上使用微服务架构,我们鼓励您尝试 Istio,在 istio.io 上了解更多信息,告诉我们您的想法,或者更好的是,加入开发人员社区,帮助塑造它的未来!

——代表 Istio 团队。IBM 软件工程师 Frank Budinsky,Google 软件工程师 Andra Cismaru 和产品经理 Israel Shalom。