Istio 基础

  1. 1   为什么需要 Service Mesh
  2. 2   安装
    1. 2.1   工具准备
    2. 2.2   方式1 - 快速安装
    3. 2.3   方式2 - Helm 安装
  3. 3   部署应用前准备
    1. 3.1   把 Envoy 容器注入 Pod
      1. 3.1.1   自动注入
      2. 3.1.1   手动注入
    2. 3.2   Istio 对 Pod 和服务的要求
  4. 4   部署应用
    1. 4.1   启动应用
    2. 4.2   创建目标规则和默认路由规则
    3. 4.3   访问服务
    4. 4.4   总结

我选择 Istio 而非 Service Mesh 鼻祖 Linkerd 的原因,是 Istio 有大牌厂商支持、社区生态圈优势、重点支持 Kubernetes。

1   为什么需要 Service Mesh

有了 Kubernetes 的 Service,为什么还需要 Service Mesh ?相信这是初学者最大的疑问。

微服务架构解决了单体应用的很多老问题,但同时也带来了一些新问题:

  • 对部署和运维的自动化要求更高
  • 对网络这一不可靠的基础设施依赖增强
  • 调用链路变长
  • 日志分散,跟踪和分析难度加大
  • 服务分散,受攻击面积更广
  • 跨服务控制协调能力要求更高
  • 自动伸缩、路由管理、存储共享等

为了解决微服务架构产生的一些问题,以 Kubernetes 为代表的容器云系统出现了。这类容器云系统以容器技术为基础,在进程级别为微服务提供了一致的部署、调度、伸缩、监控、日志等功能。
然而,除了进程本身的问题,微服务之间的通信和联系更加复杂,其中的观测、控制和服务质量保障等都成为微服务方案的短板,因此随着 Kubernetes 成为事实标准,Service Mesh 顺势登场。

一言蔽之:就是单体应用问题很多,用微服务架构来解决,但微服务架构实施部署难度加大,借助 Kubernetes 实现了,尔后发现 Kubernetes 只是解决了大部分问题,还有遗留的问题,于是第三方(Buoyant 公司,也就是 Linkerd 的开发商)在新的层次里(Kubernetes 层次外,也就是 Service Mesh)间接地解决。

Istio Architecture from https://istio.io/docs/concepts/what-is-istio/

2   安装

2.1   工具准备

其安装都是直接复制命令程序即可:

Istio 的安装目前有两种:快速安装和 Helm 安装。其原理都一样:

  1. 注册 crds 资源,需要生成“资源清单”后用 apply 打入 kubernetes
  2. 部署 Istio 组件,需要生成“组件清单”后用 apply 打入 kubernetes

Helm 是目前 Istio 官方推荐的安装方式,不过功能性学习时可以选择快速安装。

2.2   方式1 - 快速安装

  1. 安装 Istio 定义的资源 Custom Resource Definitions (CRDs)
    for i in install/kubernetes/helm/istio-init/files/crd*yaml; do kubectl apply -f $i; done
    我们可以看到,Istio v1.1.7 创建了 4 种 apiVersion,可以通过类似 /apis | grep 'istio.io' API 查看

    • authentication.istio.io/v1alpha1
    • rbac.istio.io/v1alpha1
    • config.istio.io/v1alpha2
    • networking.istio.io/v1alpha3

    全部 53 个 Istio CRD 被提交到 Kubernetes api-server(如果你启用了 cert-manager,那么 CRD 的数目为58个),可以使用 kubectl get crds 查看所有的 CRD。需要注意的是,v1.2.0 版本已经调整成 23 个。

  2. 部署 Istio 核心组件
    选择一个 配置文件,接着部署与你选择的配置文件相对应的 Istio 的核心组件,比如没有 tls 的 istio-demo.yaml 配置文件:
    kubectl apply -f install/kubernetes/istio-demo.yaml
    我们看到,除了常见的 Deployment、Service、Configmap、ServiceAccount 等 Kubernetes 对象,这里还创建了各种 Istio CRD 的下属资源。

  3. 卸载

    kubectl delete -f install/kubernetes/istio-demo.yaml
    for i in install/kubernetes/helm/istio-init/files/crd*yaml; do kubectl delete -f $i; done

2.3   方式2 - Helm 安装

这里我们推荐 helm template 安装。

核心资源在 install/kubernetes/helm 目录中。

  1. 为 Istio 组件创建命名空间 istio-system:
    $ kubectl create namespace istio-system

  2. 使用 kubectl apply 安装所有的 Istio CRD,命令执行之后,会隔一段时间才能被 Kubernetes API Server 收到,并查询确保全部 53个(如果你启用了 cert-manager,那么 CRD 的数目为58个,在 install/kubernetes/helm/istio-init/values.yaml 配置)Istio CRD 被提交到 Kubernetes api-server:
    $ helm template install/kubernetes/helm/istio-init --name istio-init --namespace istio-system | kubectl apply -f -
    $ kubectl get crds | grep 'istio.io\|certmanager.k8s.io' | wc -l

  3. 选择一个 配置文件,接着部署与你选择的配置文件相对应的 Istio 的核心组件,我们建议在生成环境部署中使用 default 配置文件:
    $ helm template install/kubernetes/helm/istio --name istio --namespace istio-system --values install/kubernetes/helm/istio/values-istio-demo.yaml --set gateways.istio-ingressgateway.type=NodePort | kubectl apply -f -
    你可以添加一个或多个 --set <key>=<value> 来进一步自定义 helm 命令的安装选项,另外对于缺少 LoadBalancer 支持的平台,执行下面的安装步骤时,可以在 Helm 命令中加入 –set gateways.istio-ingressgateway.type=NodePort 选项,使用 NodePort 来替代 LoadBalancer 服务类型。
    但是推荐在配置文件中进行配置。
    命令行参数解释:

    • –name istio:代表生成的部署内容的基础名称为“istio”,比如 pod “istio-grafana-post-install-1.1.7-c4n6t”;
    • –namespace istio-system:代表将 Istio 部署到命名空间 istio-system 中;
    • –values(-f) values-istio-demo.yaml:代表从 values-istio-demo.yaml 文件中获取输入的内容,一般我们不直接修改原 values.yaml 文件,而是通过新增 yaml 文件为各种场景下的关键配置提供范本。
  4. 卸载

    • 卸载组件
      $ helm template install/kubernetes/helm/istio --name istio --namespace istio-system | kubectl delete -f -
      $ kubectl delete namespace istio-system
    • 删除 CRD 和 Istio 配置
      kubectl delete -f install/kubernetes/helm/istio-init/files

3   部署应用前准备

3.1   把 Envoy 容器注入 Pod

3.1.1   自动注入

配置在 install/kubernetes/helm/istio/values.yaml 中:

autoInject: enabled
sidecarInjectorWebhook:
enabled: true
replicaCount: 1
image: sidecar_injector
enableNamespaceByDefault: false

需要同时满足以下三个条件才会开启自动注入功能:

  1. sidecarInjectorWebhook.enabled:总控制开头,为 true 表示开启自动注入特性,这里一定要设置为 true
  2. enableNamespaceByDefault:为 true 表示为所有的命令空间开启自动注入功能;为 false 表示只为标签 istio-injection: enabled 的命名空间才会开启自动注入。
  3. autoInject:命名有点歧义,它其实是跟 pod 的 sidecar.istio.io/inject 的注解(annotations,注意不是标签)有关,以下两种情况会自动注入:
    • enabled + !sidecar.istio.io/inject: false
    • disable + sidecar.istio.io/inject: true

因为 enableNamespaceByDefault 设置为 false,所以想要自动注入的命令空间都要打上 istio-injection=enabled,这样才满足条件2:
kubectl label ns default istio-injection=enabled

3.1.1   手动注入

如果目标命名空间中没有打上 istio-injection 标签, 可以使用 istioctl kube-inject 命令,在部署之前手工把 Envoy 容器注入到应用 Pod 之中

3.2   Istio 对 Pod 和服务的要求

要成为服务网格的一部分,Kubernetes 集群中的 Pod 和服务必须满足以下几个要求:

  • 需要给端口正确命名:服务端口必须进行命名。端口名称只允许是<协议>[-<后缀>-]模式,其中<协议>部分可选择范围包括 grpc、http、http2、https、mongo、redis、tcp、tls 以及 udp,Istio 可以通过对这些协议的支持来提供路由能力。例如 name: http2-foo 和 name: http 都是有效的端口名,但 name: http2foo 就是无效的。如果没有给端口进行命名,或者命名没有使用指定前缀,那么这一端口的流量就会被视为普通 TCP 流量(除非显式的用 Protocol: UDP 声明该端口是 UDP 端口)。

  • Pod 端口: Pod 必须包含每个容器将监听的明确端口列表。在每个端口的容器规范中使用 containerPort。任何未列出的端口都将绕过 Istio Proxy。

  • 关联服务:Pod 不论是否公开端口,为了满足服务发现的需要,都必须关联到至少一个 Kubernetes 服务上,如果一个 Pod 属于多个服务,这些服务不能在同一端口上使用不同协议,例如 HTTP 和 TCP。

  • Deployment 应带有 app 以及 version 标签:在使用 Kubernetes Deployment 进行 Pod 部署的时候,建议显式的为 Deployment 加上 app 以及 version 标签。每个 Deployment 都应该有一个有意义的 app 标签和一个用于标识 Deployment 版本的 version 标签。app 标签在分布式追踪的过程中会被用来加入上下文信息。Istio 还会用 app 和 version 标签来给遥测指标数据加入上下文信息。

  • Application UID:不要使用 ID(UID)值为 1337 的用户来运行应用。

  • NET_ADMIN 功能: 如果您的集群中实施了 Pod 安全策略,除非您使用 Istio CNI 插件,您的 pod 必须具有NET_ADMIN功能。请参阅必需的 Pod 功能。

4   部署应用

在 Istio 中部署业务应用时,建议做到以下几点:

  • 使用 app 标签表明应用身份
  • 使用 version 标签表明应用版本
  • 创建目标规则
  • 创建默认路由规则

4.1   启动应用

本实例在 kubernetes 资源一文中延伸,不同之处在于应用资源时需要注入 sidecar,前面我们分析过了可以是手动注入,也可以是自动注入;

  • 手动注入:istioctl kube-inject -f gorpc-kube.yaml | kubectl apply -f -
  • 自动注入:kubectl apply -f gorpc-kube.yaml

4.2   创建目标规则和默认路由规则

gorpc-istio.yaml 放在 github 项目上
配置清单内容纲目:

  • DestinationRule, goapi.default
  • DestinationRule, goapisec.default
  • VirtualService,
    goapisec.default -> v3, prefix: /sec;
    goapi.default -> v1, prefix: /;
  • Gateway, number: 443, hosts: - “*.jemper.cn”

直接部署即可:kubectl apply -f gorpc-istio.yaml,这些资源没有注入的概念。

4.3   访问服务

注意要点:

  • Service 对象中的 Port 部分必须以“协议名”为前缀,目前支持的协议名包括 http、http2、mongo、redis 和 grpc。Istio 会根据这些命名来确定为这些端口提供什么样的服务,不符合命名规范的端口会被当作 TCP 服务,其功能支持范围会大幅缩小。
    另外官方建议为 Pod 模板加入两个标签:app 和 version。
  • Istio 的注入要求:没有 Service 的 Deployment 是无法被 Istio 发现并进行操作的。为了满足服务发现的需要,所有的 Pod 都必须有关联的服务,如果没有 Service 则容器只能启动一个
  • DNS 解析是在网格内,外部流量无法解析服务名
  • Istio 用于控制网格内的访问,不能控制外部流量的访问。在容器内使用服务 IP 访问受到 Istio 控制,在宿主机使用服务 IP 进行访问不受 Istio 控制。
  • 注入只会对部分资源起作用,比如 Deployment 等,对 Service、DestinationRule、VirtualService 等没有注入操作

所以应该要创建一个在网格内的客户端应用来访问服务。
for i in seq 10; do curl http://goapi:81/index; done
for i in seq 10; do curl http://10.102.19.38:81/index; done
for i in seq 10; do curl http://35.237.188.250:30001/index; done

4.4   总结

总的来说,可以把上述两部分合成一条命令:

  • 手动注入:istioctl kube-inject -f gorpc-kube.yaml | kubectl apply -f gorpc-istio.yaml -f -
  • 自动注入:kubectl apply -f gorpc-istio.yaml -f gorpc-kube.yaml

删除应用:kubectl delete -f gorpc-istio.yaml -f gorpc-kube.yaml




参考文献
[1] 崔秀龙. 深入浅出 Istio | Service Mesh 快速入门与实践. 版次:2019年3月第1版
[2] 杨章显. Service Mesh 实战 | 基于 Linkerd 和 Kubernetes 的微服务实践. 版次:2019年1月第1版