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

使用 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 微服务的服务和 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

如果我们要运行该应用程序,我们需要部署的其他两个服务是 detailsreviews-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,用于管理服务的传入和传出流量。

在 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。