Istio 基础
我选择 Istio 而非 Service Mesh 鼻祖 Linkerd 的原因,是 Istio 有大牌厂商支持、社区生态圈优势、重点支持 Kubernetes。
1 为什么需要 Service Mesh
有了 Kubernetes 的 Service,为什么还需要 Service Mesh ?相信这是初学者最大的疑问。
微服务架构解决了单体应用的很多老问题,但同时也带来了一些新问题:
- 对部署和运维的自动化要求更高
- 对网络这一不可靠的基础设施依赖增强
- 调用链路变长
- 日志分散,跟踪和分析难度加大
- 服务分散,受攻击面积更广
- 跨服务控制协调能力要求更高
- 自动伸缩、路由管理、存储共享等
为了解决微服务架构产生的一些问题,以 Kubernetes 为代表的容器云系统出现了。这类容器云系统以容器技术为基础,在进程级别为微服务提供了一致的部署、调度、伸缩、监控、日志等功能。 然而,除了进程本身的问题,微服务之间的通信和联系更加复杂,其中的观测、控制和服务质量保障等都成为微服务方案的短板,因此随着 Kubernetes 成为事实标准,Service Mesh 顺势登场。
一言蔽之:就是单体应用问题很多,用微服务架构来解决,但微服务架构实施部署难度加大,借助 Kubernetes 实现了,尔后发现 Kubernetes 只是解决了大部分问题,还有遗留的问题,于是第三方(Buoyant 公司,也就是 Linkerd 的开发商)在新的层次里(Kubernetes 层次外,也就是 Service Mesh)间接地解决。
2 安装
2.1 工具准备
其安装都是直接复制命令程序即可:
Istio 的安装目前有两种:快速安装和 Helm 安装。其原理都一样:
- 注册 crds 资源,需要生成“资源清单”后用 apply 打入 kubernetes
- 部署 Istio 组件,需要生成“组件清单”后用 apply 打入 kubernetes
Helm 是目前 Istio 官方推荐的安装方式,不过功能性学习时可以选择快速安装。
2.2 方式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 个。
-
部署 Istio 核心组件 选择一个 配置文件,接着部署与你选择的配置文件相对应的 Istio 的核心组件,比如没有 tls 的 istio-demo.yaml 配置文件:
kubectl apply -f install/kubernetes/istio-demo.yaml我们看到,除了常见的 Deployment、Service、Configmap、ServiceAccount 等 Kubernetes 对象,这里还创建了各种 Istio CRD 的下属资源。 -
卸载
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 目录中。
-
为 Istio 组件创建命名空间 istio-system:
$ kubectl create namespace istio-system -
使用 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 -
选择一个 配置文件,接着部署与你选择的配置文件相对应的 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 文件为各种场景下的关键配置提供范本。
- 卸载
- 卸载组件
$ 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
需要同时满足以下三个条件才会开启自动注入功能:
- sidecarInjectorWebhook.enabled:总控制开头,为 true 表示开启自动注入特性,这里一定要设置为 true
- enableNamespaceByDefault:为 true 表示为所有的命令空间开启自动注入功能;为 false 表示只为标签 istio-injection: enabled 的命名空间才会开启自动注入。
- 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版