Istio 服务网格路由入门

阅读数:1339 2018 年 12 月 4 日 14:28

Istio服务网格路由入门

摘要: 在本教程中,我们将使用 Istio 演示服务网格最强大的特性之一:“以请求为基准的路由”。这个特性允许把具有指定 HTTP 头标记的任意请求路由到特定的目标,这只有在(OSI)第 7 层代理中才可能实现。没有哪个第 4 层的负载均衡器或代理可以实现此功能。

本文要点

  • 本教程将演示如何在 Kubernetes 集群中安装和使用 Istio 服务网格,并讨论如何充分利用 Istio 的路由功能。

  • 探讨第 4 层和第 7 层网络代理之间的区别,并了解如何充分利用 L7 代理的好处。

  • 用户可以借助 Istio 的可扩展性和服务网格的一般功能实现路由场景,节省大量的时间和资源。

在本教程中,我们将使用 Istio 演示服务网格最强大的特性之一:“以请求为基准的路由”。这个特性允许把具有指定 HTTP 头标记的任意请求路由到特定的目标,这只有在(OSI)第 7 层代理中才可能实现。没有哪个第 4 层的负载均衡器或代理可以实现此功能。

如果你想继续阅读本文,我们假设你有一个正在运行的 Kubernetes 集群。对于本教程来说,一个包含 1 个主节点和 2 个工作节点的小集群就足够了。

Istio 是什么?

Istio 是一个服务网格。它由控制平面和数据平面组成。对于数据平面,它使用 Envoy 代理。Envoy 本身是一个 L7 代理和通信总线,专为基于微服务的现代化体系结构而设计。关于 Envoy 代理的更多信息,有大量的文档可供查阅。关于 Istio 是什么,官方文档 也提供了一个很好的解释。

Istio服务网格路由入门

图 1:使用 Istio Pilot 把路由配置注入作为服务“挎斗(sidecar )”运行的 Envoy 代理

以请求为基准的路由

Istio 提供高级的流量管理功能。以请求为基准的路由特性允许我们定义针对传入请求的复杂规则,并决定如何处理请求。以下是可能的用例:

  1. 金丝雀测试——将一小部分用户流量重定向到新的服务版本;

  2. 向不同的用户提供不同的版本——不同价格计划或来自不同地区的用户可能由不同的环境提供服务(例如,这可能是实现 GDPR 要求的一部分);

  3. A/B 测试;

  4. 逐步滚动。

本教程将介绍如何逐步滚动。

步骤 0:安装一个 Kubernetes 集群

为了创建一个集群,你可以使用任何 Kubernetes 解决方案。在本教程中,我们将使用免费的 Kublr 演示程序部署一个集群。

步骤 1:安装 Istio 控制平面

一种选择是遵照官方的 Istio 快速入门教程 ,在 Kubernetes 集群中安装控制平面。安装步骤取决于你本地的机器类型(Mac、Linux、Windows),因此我们不会在这里重复安装本地 istioctl 应用程序和 kubectl 的标准步骤,这两个 CLI 工具将用于管理 Kubernetes 和 Istio。

下面是为已经熟悉 Kubernetes 的读者做的一个不那么详细的说明(如果这些信息不够,那么我们建议你遵照官方指南按步骤完成):

  1. 安装 Kubernetes 集群(使用上面列出的其中一种方法,或者使用已有的测试 / 开发集群) ;

  2. 在本地安装 kubectl https://kubernetes.io/docs/tasks/tools/install-kubectl/ (我们将使用它管理 Kubernetes 集群);

  3. 从 GitHub 发布页面安装 istioctl (用于把 Envoy 代理注入到 pod 以及设置路由规则和策略),安装很简单:

    a. 对于 Mac 或 Linux,运行 curl -L https://git.io/getLatestIstio | sh -;

    b. 对于 Windows,只要从 zip 压缩包中提取文件,并把二进制文件复制到 PATH(可以简单地复制到 c:\windows\system32\)或者从 /bin/ 目录下运行所有的 istioctl.exe 命令;

    c. 切换到提取出的文件所在的文件夹,使用 kubectl apply -f install/kubernetes/istio-demo.yaml 进行安装。

你需要一个 Kubernetes 客户端配置文件以及访问集群仪表板。创建集群的方法不同,获取它们的方式也有所不同。由于我们的示例集群是用 Kublr 部署的,你可以在 Kublr 仪表板中找到以下链接,并将配置文件下载到~/.kube/config (在 Windows 上是 %USERPROFILE%/.kube/config),然后导航到 Kubernetes 仪表板:

Istio服务网格路由入门

使用配置文件中的凭据(找到“username: admin”,并使用该用户及其列出的密码登录到仪表板)。你应该会看到如下所示的仪表板,单击侧边栏中的“NAMESPACES”将显示以下 3 个默认名称空间:

Istio服务网格路由入门

Istio 组件将安装到它们自己的名称空间中。导航到你下载的 Istio 发布存档,提取并运行:kubectl apply -f install/kubernetes/ Istio -demo.yaml。

你会看到创建了许多组件,每个组件在 Istio 官方文档中都有介绍,或者,你可以打开 yaml 文件查看注释—每个资源都记录在该文件中。然后我们可以浏览命名空间,并检查是否一切都创建成功:

Istio服务网格路由入门

点击 istio-system 命名空间,确保在组件创建过程中没有错误或问题。它看起来应该是下面这个样子:

Istio服务网格路由入门

大约有 50 个事件;你可以滚动查看“成功”状态,并注意是否有错误。如果出现错误,你可以在 Istio GitHub 问题页面上发布 Bug 报告,向开发人员指出问题。

我们需要找到“istio-ingress”服务的入口点,以便知道将流量发送到哪里。导航到侧栏中的“istia-system”命名空间。如果在创建后没有看到这个命名空间,只需刷新浏览器页面,然后选择该命名空间,单击“Services”,找到外部端点,如下图所示:

Istio服务网格路由入门

在我们的例子中,它是一个 AWS 弹性负载均衡器,但是,你可能会看到一个 IP 地址,这取决于集群设置。我们将使用这个端点地址访问我们的演示用 Web 服务。

步骤 2:使用 Envoy Proxy Sidecar 部署演示用 Web 服务

现在我们终于到了本教程最有趣的部分。让我们研究下该服务网格的路由功能。首先,我们将部署两个演示用 Web 服务:“blue”和“green”,就像我们在前一个教程中所做的那样。

把以下内容复制到名为 my-websites.yaml 的文件中:

复制代码
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: web-v1
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
app: website
version: website-version-1
spec:
containers:
- name: website-version-1
image: kublr/kublr-tutorial-images:v1
resources:
requests:
cpu: 0.1
memory: 200
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: web-v2
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
app: website
version: website-version-2
spec:
containers:
- name: website-version-2
image: kublr/kublr-tutorial-images:v2
resources:
requests:
cpu: 0.1
memory: 200
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: web-v3
namespace: default
spec:
replicas: 1
template:
metadata:
labels:
app: website
version: website-version-3
spec:
containers:
- name: website-version-3
image: kublr/kublr-tutorial-images:v3
resources:
requests:
cpu: 0.1
memory: 200
---
apiVersion: v1
kind: Service
metadata:
name: website
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
selector:
app: website

请注意,当你想要把 Envoy sidecar 和 pod 一起使用时,应提供“app”标签(供请求跟踪特性使用),而且服务定义中的“ spec.ports.name ”必须正确命名(http、http2、grpc、redis、mongo),否则,Envoy 将把该服务流量作为普通的 TCP 服务对待,你将无法在那些服务中使用 7 层特性!

此外,pod 只能作为集群中单个“服务”的目标。正如你上面看到的那样,定义文件有三个简单的部署,每个部署使用 Web 服务的不同版本(v1/v2/v3),而这三个简单的服务,每个都指向相应的部署。

现在,我们将使用“ istioctl ku -inject”命令 将所需的 Envoy 代理配置添加到这个文件中的 pod 定义中。它将生成一个新的 yaml 文件,其中包含已经准备好使用 kubectl 部署的 Envoy sidecar 的其他组件,运行:istioctl kube-inject -f my-websites。yaml - o my-websites-with-proxy.yaml。

输出文件将包含额外的配置,你可以查看“my-websites-with-proxy.yaml”文件。这个命令使用预定义的 ConfigMap “isti -sidecar-injector”(在我们之前安装 Istio 时安装了它),并将所需的 sidecar 配置和参数添加到部署定义中。当我们部署新文件“my-websites-with-proxy.yaml”时,每个 pod 将有两个容器,一个是演示应用程序和一个是 Envoy 代理。在这个新文件上运行创建命令:kubectl apply -f my-websites-with-proxy.yaml。

按照预期,你将看到以下输出:

复制代码
deployment "web-v1" created
deployment "web-v2" created
deployment "web-v3" created
service "website" created

让我们检查一下这些 pod,看看 Envoy sidecar 是否已经存在:kubectl get pods。

可以看到,每个 pod 有两个容器,一个是网站容器,另一个是代理 sidecar:

Istio服务网格路由入门

此外,你还可以检查 Envoy 代理的日志,运行:kubectl logs -c istio-proxy。

你会看到许多输出,最后几行类似下面这样:

复制代码
add/update cluster outbound|80|version 1|website.default.svc.cluster.local starting warming
add/update cluster outbound|80|version-2|website.default.svc.cluster.local starting warming
add/update cluster outbound|80|version-3|website.default.svc.cluster.local starting warming
warming cluster outbound|80|version-3|website.default.svc.cluster.local complete
warming cluster outbound|80|version-2|website.default.svc.cluster.local complete
warming cluster outbound|80|version-1|website.default.svc.cluster.local complete

这表明,代理 sidecar 健康状况良好,正在那个 pod 中运行。

现在,我们需要部署最小的 Istio 配置资源,将流量路由到我们的服务和 pod,将以下清单保存到一个名为“website-routing.yaml”的文件中:

复制代码
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: website-gateway
spec:
selector:
# 我们希望把哪个 pod 暴露为 Istio 路由器
# 该标签指向从 istio-demo.yaml 文件安装时默认的那个
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
# 我们在这里指定 Kubernetes 服务名
# 我们希望使用这个 Gateway 提供服务
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: website-virtual-service
spec:
hosts:
- "*"
gateways:
- website-gateway
http:
- route:
- destination:
host: website
subset: version-1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: website
spec:
host: website
subsets:
- name: version-1
labels:
version: website-version-1
- name: version-2
labels:
version: website-version-2
- name: version-3
labels:
version: website-version-3

这些是 Gateway、VirtualService 和 DestinationRule。这些自定义的 Istio 资源用于管理和配置 Istio -ingressgateway pod 的 Ingress 行为。我们将在下一个教程中更深入地描述它们,并介绍 Istio 配置的技术细节。现在,部署这些资源来访问我们的示例站点:kubectl create -f website-routing.yaml。

下一步是访问我们的演示网站。我们部署了三个“版本”,每个版本显示不同的页面文本和颜色,但是,目前我们只能通过 Istio Ingress 到达版本 1。让我们访问端点,确保 Web 服务已经部署。

查找外部端点,运行:kubectl get services istio-ingressgateway -n istio-system。

或者通过浏览 istio-ingressgateway 服务找到它,如下所示(我们在本教程的开头已经看到过):

Istio服务网格路由入门

点击它可以访问外部端点。你可能会看到几个链接,因为一个链接指向 HTTPS,另一个链接指向负载均衡器的 HTTP 端口。

使我们的“website” Kubernetes 服务仅指向单个部署的确切配置是我们为网站创建的 Istio VirtualService。它告诉 Envoy 代理仅把对“website”服务的请求路由到标签为“version: website-version-1”的 pod(你可能已经注意到,“website”服务的清单只从 pod 中选择一个标签“app: website”,但没有指定从哪个“version”标签选择,所以,如果没有 Envoy 逻辑,则 Kubernetes 服务本身会轮循所有标签为“app: website”的 pod,包括版本 1、2 和 3)。

要更改我们看到的网站版本,你可以更改 VirtualService 清单的以下部分并重新部署:

复制代码
http:
- route:
- destination:
host: website
subset: version-1

“subset”是我们从 DestinationRule 中选出的、要路由到的正确目标,我们将在下一个教程中深入学习这些资源。

步骤 3: 逐步滚动

通常,当应用程序的新版本需要使用小部分流量进行测试(金丝雀部署)时,普通的 Kubernetes 方法是使用一个新的、但具有相同 pod 标签的 Docker 镜像创建第二个部署,这会导致向这个 pod 标签发送流量的“服务”也会在第二个部署时新插入的 pod 之间进行平衡。然而,你无法轻易将 10% 的流量路由到新部署(要精确达到 10%,你得根据所需的百分比保持两个部署之间的 pod 副本比率, 如 9 个“v1 pods”和 1 个“v2 pod”,或者 18 个“v1 pods”和 2 个“v2 pods”),而且不能使用 HTTP 头将请求路由到特定的版本。

Istio 通过其灵活的 VirtualService 配置解决了这一限制。例如,如果你想使用 90/10 规则来路由流量,很简单,如下所示:

复制代码
---
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: website-gateway
spec:
selector:
# 我们希望把哪个 pod 暴露为 Istio 路由器
# 该标签指向从 istio-demo.yaml 文件安装时默认的那个
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
# 我们在这里指定 Kubernetes 服务名
# 我们希望使用这个 Gateway 提供服务
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: website-virtual-service
spec:
hosts:
- "*"
gateways:
- website-gateway
http:
- route:
- destination:
host: website
subset: version-1
weight: 90
- destination:
host: website
subset: version-2
weight: 10
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: website
spec:
host: website
subsets:
- name: version-1
labels:
version: website-version-1
- name: version-2
labels:
version: website-version-2
- name: version-3
labels:
version: website-version-3

GitHub https://github.com/kublr/istio-blog-sample 上提供了本文的源代码。

小结

我们希望本教程可以让对 Istio、它是如何工作的以及如何利用它进行比较复杂的网络路由有一个良好的高层视角。Istio 简化了那些需要花费更多时间和资源的场景的实现。这是一项任何人在研究服务网格时都应该考虑的强大技术。

关于作者

Istio服务网格路由入门

Oleg Chunikhin 是 Kublr 的首席技术官。他拥有 20 年的软件架构和开发经验。作为 Kublr 的 CTO,他负责制定 Kublr 的技术战略和标准。他在 Kublr 的所有工作中倡导 DevOps 标准,并致力于推动容器技术和自动化应用。Oleg 拥有新西伯利亚州立大学数学学士学位以及应用数学和计算机科学硕士学位,并且是 AWS 认证的软件架构师。

Istio服务网格路由入门

Oleg Atamanenko 是 Kublr 的高级软件架构师,拥有与许多不同技术平台打交道的丰富经验。自 2016 年以来,他一直在使用 Kubernetes,他是一名经过认证的 Kubernetes 管理员,也是 Azure 集群自动伸缩器支持的作者。作为一名软件架构师,他已经工作了超过 13 年,熟悉 Docker、Kubernetes、Amazon Web Services (AWS)、敏捷方法论(Scrum、看板),精通 DevOps 语言:Go lang、Java/Scala、bash、Javascript/TypeScript。Atamanenko 有广泛的原生云环境经验,并在开发分布式系统、容器化遗留系统和在 AWS 上实现无服务器项目方面有丰富的经验。

查看英文原文:
https://www.infoq.com/articles/istio-service-mesh-tutorial

评论

发布
用户头像
1
2018 年 12 月 04 日 14:40
回复
1
2018 年 12 月 04 日 14:40
回复
1
2018 年 12 月 04 日 14:40
回复
1
2018 年 12 月 04 日 14:40
回复
查看更多
没有更多了