使用 Istio 优化微服务可观测性与管理
1. 用 Istio 的 Jaeger 组件替换 Zipkin 服务器
Istio 内置了对使用 Jaeger 进行分布式跟踪的支持。通过使用 Jaeger,我们可以移除之前引入的 Zipkin 服务器,从而简化 Kubernetes 中的微服务环境。同时,我们会将微服务之间跟踪和跨度 ID 的传播方式,从默认的 W3C 跟踪上下文标头改为 OpenZipkin 的 B3 标头。
以下是对源代码所做的更改:
- 依赖替换 :在所有微服务的构建文件 build.gradle 中,将以下依赖:
implementation 'io.micrometer:micrometer-tracing-bridge-otel'
implementation 'io.opentelemetry:opentelemetry-exporter-zipkin'
替换为:
implementation 'io.micrometer:micrometer-tracing-bridge-brave'
implementation 'io.zipkin.reporter2:zipkin-reporter-brave'
- 配置文件修改 :通用配置文件
config-repo/application.yml中的management.zipkin.tracing.endpoint属性指向 Istio 中的 Jaeger 组件,其主机名为jaeger-collector.istio-system。 - Docker Compose 文件 :在三个 Docker Compose 文件(
docker-compose.yml、docker-compose-partitions.yml和docker-compose-kafka.yml)中,保留了 Zipkin 服务器的定义,以便在 Kubernetes 和 Istio 之外使用分布式跟踪,但将 Zipkin 服务器的主机名设置为与 Istio 中的 Jaeger 组件相同,即jaeger-collector.istio-system。 - Helm 图表移除 :移除了 Zipkin 服务器的 Helm 图表。
2. 在 Kubernetes 集群中部署 Istio
我们将使用 Istio 的 CLI 工具 istioctl ,通过一个适合在开发环境中测试 Istio 的演示配置来安装 Istio。该配置启用了大多数功能,但配置为最小化资源使用,不适合生产环境和性能测试。其他安装选项可参考:https://istio.io/latest/docs/setup/install/。
部署 Istio 的步骤如下:
1. 确保之前的 Minikube 实例正在运行,使用命令:
minikube status
若实例正在运行,期望得到类似如下响应:
2. 运行预检查,验证 Kubernetes 集群是否准备好安装 Istio:
istioctl experimental precheck
期望得到类似如下响应:
3. 使用演示配置文件安装 Istio:
cd $BOOK_HOME/Chapter18
istioctl install --skip-confirmation \
--set profile=demo \
--set meshConfig.accessLogFile=/dev/stdout \
--set meshConfig.accessLogEncoding=JSON \
--set values.pilot.env.PILOT_JWT_PUB_KEY_REFRESH_INTERVAL=15s \
-f kubernetes/istio-tracing.yml
命令参数说明:
- accessLog 参数用于启用 Istio 代理记录处理的请求。当安装了 Istio 代理的 Pod 运行后,可以使用 kubectl logs <MY-POD> -c istio-proxy 命令检查访问日志。
- PILOT_JWT_PUB_KEY_REFRESH_INTERVAL 参数配置 Istio 的守护进程 istiod 每 15 秒刷新获取的 JWKS 公钥。
- 配置文件 kubernetes/istio-tracing.yml 启用了用于分布式跟踪的跟踪跨度创建,并配置 Istio 为所有请求创建跟踪跨度。其内容如下:
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
enableTracing: true
defaultConfig:
tracing:
sampling: 100
- 等待 Deployment 对象及其 Pod 可用:
kubectl -n istio-system wait --timeout=600s --for=condition=available deployment --all
- 安装额外组件(Kiali、Jaeger、Prometheus 和 Grafana):
istio_version=$(istioctl version --short --remote=false)
echo "Installing integrations for Istio v$istio_version"
kubectl apply -n istio-system -f https://raw.githubusercontent.com/istio/istio/${istio_version}/samples/addons/kiali.yaml
kubectl apply -n istio-system -f https://raw.githubusercontent.com/istio/istio/${istio_version}/samples/addons/jaeger.yaml
kubectl apply -n istio-system -f https://raw.githubusercontent.com/istio/istio/${istio_version}/samples/addons/prometheus.yaml
kubectl apply -n istio-system -f https://raw.githubusercontent.com/istio/istio/${istio_version}/samples/addons/grafana.yaml
- 再次等待额外组件可用:
kubectl -n istio-system wait --timeout=600s --for=condition=available deployment --all
- 查看安装的内容:
kubectl -n istio-system get deploy
期望得到类似如下输出:
3. 设置对 Istio 服务的访问
使用演示配置安装 Istio 会带来一些连接相关的问题,需要解决。Istio 入口网关被配置为负载均衡的 Kubernetes 服务(类型为 LoadBalancer ),为了能够访问网关,需要在 Kubernetes 集群前运行一个负载均衡器。
Minikube 包含一个可以模拟本地负载均衡器的命令 minikube tunnel ,该命令会为每个负载均衡的 Kubernetes 服务(包括 Istio 入口网关)分配一个外部 IP 地址。我们在测试中使用的主机名 minikube.me 需要转换为 Istio 入口网关的外部 IP 地址。为了简化对 Kiali 和 Jaeger 等组件的 Web UI 的访问,我们还会为这些服务添加专用的主机名,例如 kiali.minikube.me 。
设置 Minikube 隧道并注册主机名的步骤如下:
1. 在单独的终端窗口中运行以下命令(隧道运行时会锁定终端窗口):
minikube tunnel
隧道运行后,会将 istio-ingressgateway 列为其暴露的服务之一。
2. 配置主机名解析为 Istio 入口网关的 IP 地址。首先获取 minikube tunnel 命令为 Istio 入口网关暴露的 IP 地址,并将其保存到环境变量 INGRESS_IP 中:
INGRESS_IP=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo $INGRESS_IP
由于使用的是 Minikube 的 Docker 驱动,输出的 IP 地址始终为 127.0.0.1 。
3. 更新 /etc/hosts 文件,使所有 minikube.me 主机名使用 Istio 入口网关的 IP 地址:
MINIKUBE_HOSTS="minikube.me grafana.minikube.me kiali.minikube.me prometheus.minikube.me tracing.minikube.me kibana.minikube.me elasticsearch.minikube.me mail.minikube.me health.minikube.me"
echo 127.0.0.1 $MINIKUBE_HOSTS | sudo tee -a /etc/hosts
- 在 Windows 上,还需要更新 Windows 主机文件:
- 打开 PowerShell 终端。
- 使用以下命令在 Visual Code Studio 中打开 Windows 主机文件:
code C:\Windows\System32\drivers\etc\hosts
- 在 Windows 主机文件中添加类似的行:
127.0.0.1 minikube.me grafana.minikube.me kiali.minikube.me prometheus.minikube.me tracing.minikube.me kibana.minikube.me elasticsearch.minikube.me mail.minikube.me health.minikube.me
- 保存文件时,可能会出现权限不足的错误,点击 “Retry as Admin...” 按钮以管理员身份更新主机文件。
- 验证更新:
cat C:\Windows\System32\drivers\etc\hosts
- 移除
/etc/hosts文件中minikube.me仅指向 Minikube 实例 IP 地址(127.0.0.1)的行,验证/etc/hosts文件中只有一行将minikube.me转换为 Istio 入口网关的 IP 地址127.0.0.1。 - 验证是否可以通过隧道访问 Kiali、Jaeger、Grafana 和 Prometheus:
curl -o /dev/null -sk -L -w "%{http_code}\n" https://kiali.minikube.me/kiali/
curl -o /dev/null -sk -L -w "%{http_code}\n" https://tracing.minikube.me
curl -o /dev/null -sk -L -w "%{http_code}\n" https://grafana.minikube.me
curl -o /dev/null -sk -L -w "%{http_code}\n" https://prometheus.minikube.me/graph#/
每个命令应返回 200 (OK) 。如果发送到 Kiali 的请求未返回 200 ,通常意味着其内部初始化尚未完成,等待一分钟后再试。
4. 创建服务网格
Istio 部署完成后,我们可以创建服务网格。创建服务网格的步骤与之前的操作基本相同。为了能在 Istio 管理的服务网格中运行微服务, dev-env Helm 图表从通用图表中引入了两个新的命名模板: _istio_base.yaml 和 _istio_dr_mutual_tls.yaml 。
4.1 _istio_base.yaml 模板内容
_istio_base.yaml 定义了多个 Kubernetes 清单,供 dev-env 和 prod-env 两个环境图表使用。首先,它定义了三个特定于 Istio 的安全相关清单:
- 名为 product-composite-require-jwt 的 AuthorizationPolicy 清单。
- 名为 default 的 PeerAuthentication 清单。
- 名为 product-composite-request-authentication 的 RequestAuthentication 清单。
其余四个清单是两对 Gateway 和 VirtualService 清单,用于配置对 minikube.me 和 health.minikube.me 主机名的访问和路由。
minikube.me 的 Gateway 清单如下:
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: hands-on-gw
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- minikube.me
port:
name: https
number: 443
protocol: HTTPS
tls:
credentialName: hands-on-certificate
mode: SIMPLE
解释如下:
- 网关名为 hands-on-gw ,供下面的虚拟服务使用。
- selector 字段指定网关对象将由默认的 Istio 入口网关 ingressgateway 处理。
- hosts 和 port 字段指定网关将使用 HTTPS 通过端口 443 处理对 minikube.me 主机名的传入请求。
- tls 字段指定 Istio 入口网关可以在名为 hands-on-certificate 的 TLS Secret 中找到用于 HTTPS 通信的证书和私钥。
minikube.me 的 VirtualService 清单如下:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: hands-on-vs
spec:
gateways:
- hands-on-gw
hosts:
- minikube.me
http:
- match:
- uri:
prefix: /oauth2
route:
- destination:
host: auth-server
– match:
...
解释如下:
- gateways 和 hosts 字段指定虚拟服务将通过 hands-on-gw 网关路由发送到 minikube.me 主机名的请求。
- http 元素下的 match 和 route 块数组指定了 URL 路径如何转发到关联的 Kubernetes 服务。例如,将使用路径 /oauth2 发送到 minikube.me 的请求映射到 auth-server 服务。其余的 match 和 route 元素配置了与之前类似的路由规则:
- /login → auth-server
- /error → auth-server
- /product-composite → product-composite
- /openapi → product-composite
- /webjars → product-composite
4.2 _istio_dr_mutual_tls.yaml 模板内容
_istio_dr_mutual_tls.yaml 定义了一个用于指定多个 DestinationRule 对象的模板,用于指定在将请求路由到相应服务时应使用 mTLS。该模板如下:
{{- define "common.istio_dr_mutual_tls" -}}
{{- range $idx, $dr := .Values.destinationRules }}
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: {{ $dr.name }}
spec:
host: {{ $dr.name }}
{{- if $dr.subsets }}
{{- with $dr.subsets }}
subsets:
{{ toYaml . | indent 2 }}
{{- end }}
{{- end }}
trafficPolicy:
tls:
mode: ISTIO_MUTUAL
---
{{- end -}}
{{- end -}}
解释如下:
- range 指令遍历 destinationRules 变量中定义的元素。
- spec 部分的 host 字段用于指定此 DestinationRule 应用的 Kubernetes 服务的名称。
- 只有在 destinationRules 列表的当前元素 $dr 中找到相应元素时,才会定义 subsets 部分。
- 始终使用 trafficPolicy 来要求 mTLS。
在 dev-env Helm 图表的 values.yaml 文件中指定 destinationRules 变量来使用该模板:
destinationRules:
- name: product-composite
- name: auth-server
通过以上步骤,我们可以在 Kubernetes 集群中部署 Istio,并创建一个功能完善的服务网格,提高微服务的可观测性和管理性。
以下是部署 Istio 的流程图:
graph LR
A[确保 Minikube 运行] --> B[运行预检查]
B --> C[安装 Istio]
C --> D[等待 Deployment 可用]
D --> E[安装额外组件]
E --> F[等待额外组件可用]
F --> G[查看安装内容]
G --> H[设置访问]
H --> I[创建服务网格]
以下是主机名与服务映射的表格:
| 主机名 | 目标服务 |
| ---- | ---- |
| kiali.minikube.me | kiali:20001 |
| tracing.minikube.me | tracing:80 |
| prometheus.minikube.me | prometheus:9000 |
| grafana.minikube.me | grafana:3000 |
使用 Istio 优化微服务可观测性与管理
5. 安全相关清单详细解释
在 _istio_base.yaml 模板中定义的三个 Istio 特定安全相关清单,在保障服务网格安全方面起着重要作用,下面详细解释。
5.1 AuthorizationPolicy 清单(product-composite-require-jwt)
AuthorizationPolicy 用于控制对服务的访问权限。 product-composite-require-jwt 这个清单要求访问 product-composite 服务的请求必须携带有效的 JWT(JSON Web Token)。其基本作用是确保只有经过身份验证的用户或服务才能访问该服务,防止未授权的访问。示例配置可能如下:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: product-composite-require-jwt
spec:
selector:
matchLabels:
app: product-composite
action: ALLOW
rules:
- from:
- source:
requestPrincipals: ["*"]
when:
- key: request.auth.claims[iss]
values: ["your-issuer"]
在这个示例中, selector 部分指定了该策略应用于带有 app: product-composite 标签的服务。 action 为 ALLOW 表示允许符合规则的请求通过。 rules 部分定义了具体的访问规则,这里要求请求的主体( requestPrincipals )可以是任意主体,并且 JWT 的签发者( iss 声明)必须是 your-issuer 。
5.2 PeerAuthentication 清单(default)
PeerAuthentication 用于配置服务之间的相互认证方式。 default 这个清单通常会为整个服务网格设置默认的认证策略。例如,以下是一个简单的配置示例:
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
spec:
mtls:
mode: STRICT
这里将 mTLS(Mutual Transport Layer Security)模式设置为 STRICT ,意味着服务之间的通信必须使用双向 TLS 认证,只有通过认证的客户端和服务器才能进行通信,大大增强了通信的安全性。
5.3 RequestAuthentication 清单(product-composite-request-authentication)
RequestAuthentication 用于验证请求中的身份信息,确保请求的合法性。对于 product-composite-request-authentication 清单,示例配置如下:
apiVersion: security.istio.io/v1beta1
kind: RequestAuthentication
metadata:
name: product-composite-request-authentication
spec:
selector:
matchLabels:
app: product-composite
jwtRules:
- issuer: "your-issuer"
jwksUri: "https://your-jwks-uri"
selector 指定该策略应用于 product-composite 服务。 jwtRules 定义了 JWT 的验证规则,要求 JWT 的签发者为 your-issuer ,并从 https://your-jwks-uri 获取公钥来验证 JWT 的签名。
6. 服务网格中路由规则的深入理解
在创建服务网格时, Gateway 和 VirtualService 对象在配置访问和路由方面起着关键作用。
6.1 Gateway 对象
Gateway 对象用于定义如何接收外部流量。以 minikube.me 的 Gateway 为例,它指定了使用 HTTPS 协议通过端口 443 接收对 minikube.me 主机名的请求,并从 hands-on-certificate 这个 TLS Secret 中获取证书和私钥。其配置的作用是为服务网格设置一个入口,允许外部流量进入。
6.2 VirtualService 对象
VirtualService 对象则用于描述如何在服务网格内部路由传入的流量。对于 minikube.me 的 VirtualService ,它通过 gateways 字段指定使用 hands-on-gw 网关接收的流量,并根据 http 元素下的 match 和 route 块来进行路由。例如,将 /oauth2 路径的请求路由到 auth-server 服务。这种路由规则的配置类似于之前在 Spring Cloud Gateway 和 Ingress 对象中指定的路由规则,方便我们进行流量的管理和控制。
7. DestinationRule 对象的作用及配置
_istio_dr_mutual_tls.yaml 模板定义的 DestinationRule 对象在服务网格中用于指定流量策略。
7.1 基本作用
DestinationRule 主要用于配置服务的流量策略,包括负载均衡、熔断、mTLS 等。在这个模板中,主要是指定在将请求路由到相应服务时使用 mTLS 进行安全通信。
7.2 配置解释
模板中的 range 指令遍历 destinationRules 变量中定义的元素,为每个元素创建一个 DestinationRule 对象。 spec 部分的 host 字段指定了该规则应用的 Kubernetes 服务名称。如果当前元素中定义了 subsets ,则会在 DestinationRule 中添加 subsets 部分,用于细分服务的不同版本或子集。 trafficPolicy 始终要求使用 ISTIO_MUTUAL 模式的 mTLS,确保服务之间的通信安全。
在 dev-env Helm 图表的 values.yaml 文件中指定 destinationRules 变量,如:
destinationRules:
- name: product-composite
- name: auth-server
这样就为 product-composite 和 auth-server 服务应用了 mTLS 流量策略。
8. 总结与注意事项
通过以上步骤,我们完成了使用 Istio 优化微服务可观测性与管理的一系列操作,包括用 Jaeger 替换 Zipkin 服务器、在 Kubernetes 集群中部署 Istio、设置对 Istio 服务的访问、创建服务网格等。在整个过程中,需要注意以下几点:
- 命令执行问题 :在执行各种命令时,可能会由于时机问题出现错误。例如,Kiali 安装可能会出现
unable to recognize开头的错误信息,此时重新运行命令通常可以解决问题。 - Minikube 隧道 :
minikube tunnel命令在计算机或 Minikube 实例暂停或重启时会停止运行,需要手动重新启动。如果无法访问minikube.me主机名的 API,要检查隧道是否正在运行。 - 主机名配置 :在更新
/etc/hosts和 Windows 主机文件时,要确保配置正确,避免出现访问问题。
以下是操作步骤的总结表格:
| 操作步骤 | 命令或配置文件 | 说明 |
| ---- | ---- | ---- |
| 替换 Zipkin 服务器 | 修改 build.gradle 依赖、 application.yml 配置等 | 用 Jaeger 替换 Zipkin,简化微服务环境 |
| 部署 Istio | istioctl install 等一系列命令 | 使用演示配置在 Kubernetes 集群中安装 Istio |
| 设置访问 | minikube tunnel 、更新主机文件等 | 解决 Istio 安装的连接问题,方便访问服务 |
| 创建服务网格 | 引入 _istio_base.yaml 和 _istio_dr_mutual_tls.yaml 模板 | 配置服务网格的访问、路由和安全策略 |
以下是安全相关清单配置的流程图:
graph LR
A[AuthorizationPolicy] --> B[验证 JWT 访问权限]
C[PeerAuthentication] --> D[设置服务间 mTLS 认证模式]
E[RequestAuthentication] --> F[验证请求的 JWT 合法性]
B --> G[控制服务访问]
D --> G
F --> G
通过合理运用 Istio 的这些功能和组件,我们可以有效地提高微服务的可观测性和管理性,保障系统的安全和稳定运行。
超级会员免费看
56

被折叠的 条评论
为什么被折叠?



