mirror of https://github.com/istio/istio.io.git
/help/ops/traffic-management/deploy-guidelines/index.md (#3508)
This commit is contained in:
parent
bd83936bf5
commit
8367005adf
|
|
@ -1,15 +1,14 @@
|
|||
---
|
||||
title: 部署和配置指南
|
||||
description: 提供特定的部署和配置指南。
|
||||
weight: 5
|
||||
weight: 20
|
||||
---
|
||||
|
||||
本节提供了特定的部署或配置指南,以避免网络或流量管理问题。
|
||||
本节提供了特定的部署或配置指南,以避免网络或流量管理出现问题。
|
||||
|
||||
## 在网关中配置多个 TLS 主机
|
||||
|
||||
如果您应用具有与另一个现有 `Gateway` 相同的 `selector` 标签的 `Gateway` 配置,那么如果它们都暴露相同的 HTTPS 端口,
|
||||
则必须确保它们具有唯一的端口名称。否则,由于在应用配置情况下没有立即的错误指示,而运行时网关配置中会忽略该配置(重名端口的配置将被忽略)。例如:
|
||||
如果您要创建一个 `Gateway`,新的 `Gateway` 与另一个现有 `Gateway` 具备相同 `selector` 配置,并且它们还开放了相同的 HTTPS 端口,这种情况下必须确保它们具有唯一的端口名称。否则,提交时候虽然不会立即看到错误提示,但运行时网关配置中会忽略该配置(重名端口的配置将被忽略)。例如:
|
||||
|
||||
{{< text yaml >}}
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
|
|
@ -52,7 +51,7 @@ spec:
|
|||
{{< /text >}}
|
||||
|
||||
使用此配置,对第二个主机 `myhost2.com` 的请求将失败,因为两个网关端口都具有 `name: https`。
|
||||
例如,_curl_ 请求将产生如下错误消息:
|
||||
例如,`curl` 请求将产生如下错误消息:
|
||||
|
||||
{{< text plain >}}
|
||||
curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to myhost2.com:443
|
||||
|
|
@ -61,11 +60,11 @@ curl: (35) LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to myhost2.com:
|
|||
您可以通过检查 Pilot 的日志以查找类似于以下内容的消息来确认是否发生了这种情况:
|
||||
|
||||
{{< text bash >}}
|
||||
$ kubectl logs -n istio-system -l istio=pilot -c discovery | grep "non unique port"
|
||||
$ kubectl logs -n istio-system $(kubectl get pod -l istio=pilot -n istio-system -o jsonpath={.items..metadata.name}) -c discovery | grep "non unique port"
|
||||
2018-09-14T19:02:31.916960Z info model skipping server on gateway mygateway2 port https.443.HTTPS: non unique port name for HTTPS port
|
||||
{{< /text >}}
|
||||
|
||||
要避免此问题,请确保对同一 `protocol: HTTPS` 端口的多次使用进行唯一命名。
|
||||
要避免此问题,请确保对同一 `protocol: HTTPS` 端口的每次使用都进行唯一命名。
|
||||
例如,将第二个更改为 `https2`:
|
||||
|
||||
{{< text yaml >}}
|
||||
|
|
@ -89,16 +88,13 @@ spec:
|
|||
- "myhost2.com"
|
||||
{{< /text >}}
|
||||
|
||||
## 同一主机的多个 `VirtualServices` 和 `DestinationRules`
|
||||
## 为同一主机名配置多个 `VirtualService` 和 `DestinationRule`
|
||||
|
||||
在以下情况下中最好为指定主机以增量的方式配置多个资源。
|
||||
1. 不方便定义完整的路由规则
|
||||
1. 单个 `VirtualService` 或 `DestinationRule` 资源中特定主机策略,
|
||||
有的情况下可能不方便在单一的 `VirtualService` 或者 `DestinationRule` 资源中定义完整的策略或路由规则。如果能够用渐进的方式,在多个资源中为一个主机名完成定义配置,可能会很有帮助。
|
||||
|
||||
从 Istio 1.0.1 开始,添加了一个实验性功能,在绑定到网关时来合并这些 `VirtualService` 的目标规则。
|
||||
从 Istio 1.0.1 开始,添加了一个实验性功能,在**绑定到网关时**对 `VirtualService` 或 `DestinationRule` 进行合并。
|
||||
|
||||
考虑绑定到 ingress gateway 的 `VirtualService` 情况,该 ingress gateway 暴露了一个应用程序主机,
|
||||
该主机使用基于路径的委托的多个实现服务,如下所示:
|
||||
例如一个绑定到 Ingress网关的 `VirtualService`,它用主机名对外提供服务,使用基于路径的路由来为多个应用来提供转发服务:
|
||||
|
||||
{{< text yaml >}}
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
|
|
@ -127,9 +123,9 @@ spec:
|
|||
...
|
||||
{{< /text >}}
|
||||
|
||||
这种配置的缺点是,任何底层微服务的其他配置(例如,路由规则)也需要包含在该配置文件中,
|
||||
这种配置的缺点是,任何底层微服务的其他配置(例如路由规则)也需要包含在该配置文件中,
|
||||
而不是包含在与之相关联并且可能由各个服务团队拥有的单独配置文件中。有关详细信息,
|
||||
请参阅[路由规则对 ingress gateway 请求不生效](#路由规则对-ingress-gateway-请求不生效)。
|
||||
在运维指南中的[“路由规则对 Ingress网关请求中无效”](/zh/help/ops/traffic-management/troubleshooting/#路由规则在-ingress-gateway-请求中无效)一节中提供了介绍。
|
||||
|
||||
为了避免这个问题,可能最好将 `myapp.com` 的配置分解为几个 `VirtualService` 片段,每个后端服务一个。例如:
|
||||
|
||||
|
|
@ -174,223 +170,68 @@ metadata:
|
|||
name: myapp-...
|
||||
{{< /text >}}
|
||||
|
||||
当应用现有主机的第二个和后续的 `VirtualService` 时,`istio-pilot` 会将其他路由规则合并到主机的现有配置中。但是,有一些注意事项,使用时必须仔细考虑。
|
||||
当把第二个和后续的 `VirtualService` 应用到现有主机名上的时候,`istio-pilot` 会将其他路由规则合并到主机的现有配置中。但是,有一些注意事项,使用时必须仔细考虑。
|
||||
|
||||
1. 虽然将保留任何给定源 `VirtualService` 中规则的评估顺序,但跨资源顺序是 UNDEFINED。换句话说,
|
||||
对于片段配置中的规则没有保证的评估顺序,因此只有在跨资源的规则资源之间没有规则冲突或顺序依赖的情况下,
|
||||
合并后的行为才是可预测的。
|
||||
1. 片段中应该只有一个“全部捕获”规则(即,匹配任何请求路径或 header 的规则)。所有这些“全部捕获”规则会被移动到合并配置列表的末尾,由于它们捕获所有请求,
|
||||
最先应用的规则会覆盖和禁用其他所有的规则
|
||||
1. sidecar 不支持主机合并,只有绑定到网关支持 `VirtualService` 分段方式。
|
||||
1. 单一 `VirtualService` 中的规则评估顺序是固定的,然而跨资源的情况下就不可预料了。换句话说,在这种碎片化的配置之中,规则的评估顺序是没有保障的,因此应该对分片资源进行预测,防止其中出现冲突或者顺序依赖,这样才能保障工作正常进行。
|
||||
|
||||
1. 多个配置片段中,应该只有一个“全部捕获”规则(即,匹配任何请求路径或 Header 的规则)。配置合并时,所有这些“全部捕获”规则会被移动到列表的末尾。(如果这类规则不止一个)由于它们会匹配所有请求,所以最先应用的规则会覆盖和禁用其它所有的同类规则
|
||||
|
||||
1. Sidecar 不支持主机合并,只有绑定到网关支持 `VirtualService` 分段方式。
|
||||
|
||||
`DestinationRule` 也可以使用类似的合并语义和限制进行分段。
|
||||
|
||||
1. 对于同一主机,跨多个目标规则应该只有一个给定子集的定义。如果存在多个具有相同名称的定义,则使用第一个定义,其他重复项将失效。不支持合并子集内容。
|
||||
1. 对于同一主机,应该只有一个顶级的 `trafficPolicy`。在多个目标规则中定义顶级流量策略时,将使用第一个。任何以下顶级 `trafficPolicy` 配置都将失效。
|
||||
1. 不同于 `VirtualService` 的合并,目标规则合并在 sidecar 和网关中都有效。
|
||||
|
||||
## 设置目标规则后 503 错误
|
||||
1. 对于同一主机,应该只有一个顶级的 `trafficPolicy`。在多个目标规则中定义顶级流量策略时,将使用第一个。任何其它的顶级 `trafficPolicy` 配置都将失效。
|
||||
|
||||
如果在应用 `DestinationRule` 后,对服务的请求立即开始产生 HTTP 503 错误,并且错误一直持续到删除或恢复 `DestinationRule`,
|
||||
那么 `DestinationRule` 可能是导致服务 TLS 冲突的原因。
|
||||
1. 不同于 `VirtualService` 的合并,目标规则合并在 Sidecar 和网关中都有效。
|
||||
|
||||
例如,如果在集群中配置了全局双向 TLS,则 `DestinationRule` 必须包含以下 `trafficPolicy`:
|
||||
## 重新配置服务路由后,如何避免 503 错误
|
||||
|
||||
{{< text yaml >}}
|
||||
trafficPolicy:
|
||||
tls:
|
||||
mode: ISTIO_MUTUAL
|
||||
{{< /text >}}
|
||||
为了将流量转发到服务的特定版本(子集),在配置对应的路由规则时,必须注意在路由投入使用之前,确保子集已经可用。否则对服务的调用就会返回 503 错误。
|
||||
|
||||
否则,默认模式为 `DISABLED`,会导致客户端代理 sidecar 发出 HTTP 明文请求而不是 TLS 加密请求。而服务器代理需要加密的请求,因此请求会与服务器代理产生冲突。
|
||||
使用 `kubectl` 命令一次性的创建 `VirtualService` 和 `DestinationRule` 的方式(例如 `kubectl apply -f myVirtualServiceAndDestinationRule.yaml`)无法避免这类错误,这是因为资源对象的传播(从配置服务器,例如 Kubernetes API Server)过程是最终一致的方式。如果引用子集的 `VirtualService`,先于 `DestinationRule` 完成传播,那么 Pilot 生成的 Envoy 配置中,就会出现上游服务不存在的故障。因此会出现 503 错误,直到所有配置对象都成功完成传播。
|
||||
|
||||
要确认存在冲突,请用 `istioctl authn tls-check` 命令检查输出中的 `STATUS` 字段是否为 `CONFLICT`。例如:
|
||||
在配置引用子集的 `VirtualService` 时,如果想要避免发生服务中断,应遵循下列流程,保证中断之前完成配置即可:
|
||||
|
||||
{{< text bash >}}
|
||||
$ istioctl authn tls-check httpbin.default.svc.cluster.local
|
||||
HOST:PORT STATUS SERVER CLIENT AUTHN POLICY DESTINATION RULE
|
||||
httpbin.default.svc.cluster.local:8000 CONFLICT mTLS HTTP default/ httpbin/default
|
||||
{{< /text >}}
|
||||
- 在加入新的子集时:
|
||||
|
||||
每当您应用 `DestinationRule` 时,请确保 `trafficPolicy` TLS 模式与全局服务器配置匹配。
|
||||
1. 在更新相关的 `VirtualService` 之前,首先更新 `DestinationRules`,在其中加入新的子集。用 `kubectl` 或其他平台的特定方式来应用规则。
|
||||
|
||||
## 重新配置服务路由时出现 503 错误
|
||||
1. 等候几秒钟,让 `DestinationRule` 配置传播给 Envoy sidecar。
|
||||
|
||||
在设置路由规则以将流量路由到服务的特定版本(子集)时,必须注意确保子集在路由使用之前可用。否则,
|
||||
在重新配置期间,调用服务可能返回 503 错误。
|
||||
1. 更新 `VirtualService`,允许其引用新加入的子集。
|
||||
|
||||
调用单个 `kubectl` 命令(例如,`kubectl apply -f myVirtualServiceAndDestinationRule.yaml`)来同时创建对应子集中的 `VirtualServices` 和 `DestinationRule` 是不够的,这是因为配置(从配置服务器,即 Kubernetes API 服务器)传播到 Pilot 实例是以最终一致的方式进行的。如果子集中的 `VirtualService` 在 `DestinationRule` 之前生效,Pilot 生成的 Envoy 配置将引用不存在的上游服务池。在所有配置对象都可用于 Pilot 之前,请求调用将导致 HTTP 503 错误。
|
||||
- 删除子集时:
|
||||
|
||||
要确保在使用子集配置路由时保证服务零停机时间,请按照 “make-before-break” 过程进行操作,如下所述:
|
||||
|
||||
* 添加新子集时:
|
||||
|
||||
1. 首先将 `DestinationRules` 添加到新子集,然后再更新 `VirtualServices` 配置去使用 `DestinationRules`。使用 `kubectl` 或特定于平台的工具应用规则。
|
||||
|
||||
1. 等待几秒钟,以便 `DestinationRule` 配置传播至 Envoy sidecar。
|
||||
|
||||
1. 更新 `VirtualService` 使用新添加的子集。
|
||||
|
||||
* 删除子集时:
|
||||
|
||||
1. 在将 `DestinationRule` 从子集删除之前,首先更新 `VirtualServices` 以保证其不再引用即将删除的 `DestinationRule`。
|
||||
1. 在从 `DestinationRule` 中删除子集之前,首先要更新 `VirtualServices`,移除其中对待删除子集的引用。
|
||||
|
||||
1. 等待几秒钟,以便 `VirtualService` 配置传播至 Envoy sidecar。
|
||||
|
||||
1. 在未使用的子集中删除 `DestinationRule`。
|
||||
1. 在 `DestinationRule` 中删除无用的子集。
|
||||
|
||||
## 路由规则对 ingress gateway 请求不生效
|
||||
## 多个网关共用同一个 TLS 证书时引起浏览器问题
|
||||
|
||||
假设正在使用入口 `Gateway` 和对应的 `VirtualService` 来访问内部服务。
|
||||
例如, `VirtualService` 看起来像这样:
|
||||
使用同一个 TLS 证书配置多于一个网关时,如果使用支持 [HTTP/2 连接复用](https://httpwg.org/specs/rfc7540.html#reuse)的浏览器(多数浏览器都支持这一能力)来进行访问,在和第一个主机名建立连接之后,如果继续访问另一个主机名,就会出现 404 错误。
|
||||
|
||||
{{< text yaml >}}
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
hosts:
|
||||
- "myapp.com" # 或者如果您使用入口网关 IP 进行无 DNS 验证,则可能值为"*"(例如,http://1.2.3.4/hello)
|
||||
gateways:
|
||||
- myapp-gateway
|
||||
http:
|
||||
- match:
|
||||
- uri:
|
||||
prefix: /hello
|
||||
route:
|
||||
- destination:
|
||||
host: helloworld.default.svc.cluster.local
|
||||
- match:
|
||||
...
|
||||
{{< /text >}}
|
||||
举个例子,假设有两个主机用这种方式来共享同样的 TLS 证书:
|
||||
|
||||
同时我们还有另外一个 `VirtualService`,用于将 helloworld 服务的流量路由到特定子集:
|
||||
- 安装在 `istio-ingressgateway` 上的通配符证书:`*.test.com`
|
||||
|
||||
{{< text yaml >}}
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: helloworld
|
||||
spec:
|
||||
hosts:
|
||||
- helloworld.default.svc.cluster.local
|
||||
http:
|
||||
- route:
|
||||
- destination:
|
||||
host: helloworld.default.svc.cluster.local
|
||||
subset: v1
|
||||
{{< /text >}}
|
||||
- 一个命名为 `gw1` 的 `Gateway` 对象,其主机名是 `service1.test.com`,`selector` 定义为 `istio: ingressgateway`,使用网关加载的证书来进行 TLS 认证
|
||||
|
||||
在这种情况下,通过 ingress gateway 向 helloworld 服务发出的请求不会被定向到子集 v1,而是继续使用默认的轮询路由。
|
||||
- 一个命名为 `gw2` 的 `Gateway` 对象,其主机名是 `service2.test.com`,`selector` 定义为 `istio: ingressgateway`,使用网关加载的证书来进行 TLS 认证
|
||||
|
||||
入口请求正在使用网关主机(例如,`myapp.com`),该主机将使用 myapp 中 `VirtualService` 的规则,路由请求到 helloworld 服务中的任一端点。主机 `helloworld.default.svc.cluster.local` 的内部请求将使用 helloworld 中 `VirtualService`,将流量定向到子集 v1。
|
||||
- 名为 `vs1` 的 `VirtaulService` 对象,主机名为 `service1.test.com`,网关设置为 `gw1`
|
||||
|
||||
要控制来自网关的流量,需要在 myapp 中的 `VirtualService` 中包含子集规则:
|
||||
- 名为 `vs2` 的 `VirtaulService` 对象,主机名为 `service2.test.com`,网关设置为 `gw2`
|
||||
|
||||
{{< text yaml >}}
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
hosts:
|
||||
- "myapp.com" # 或者如果您使用 ingress gateway IP 进行无 DNS 验证,则可能值为"*"(例如,http://1.2.3.4/hello)
|
||||
gateways:
|
||||
- myapp-gateway
|
||||
http:
|
||||
- match:
|
||||
- uri:
|
||||
prefix: /hello
|
||||
route:
|
||||
- destination:
|
||||
host: helloworld.default.svc.cluster.local
|
||||
subset: v1
|
||||
- match:
|
||||
...
|
||||
{{< /text >}}
|
||||
两个网关对象使用的是一组工作负载(`istio: ingressgateway`),用同样的 IP 为两个服务提供网关支持。如果首先访问了 `service1.test.com`,会返回通配符证书 `*.test.com`,这一证书是可以用于连接 `service2.test.com` 的。Chrome 或者 Firefox 这样的浏览器会复用这已经存在的连接,来发起对 `service2.test.com` 的访问,但是 `gw1` 没有到 `service2.test.com` 的路由,所以就会返回 404 错误。
|
||||
|
||||
或者,如果可能,可以将两个 `VirtualServices` 组合到一个单元中:
|
||||
要解决这一问题,可以配置一个通用的 `Gateway` 对象,而不是分别配置两个 `gw1` 和 `gw2`。例如下面的配置:
|
||||
|
||||
{{< text yaml >}}
|
||||
apiVersion: networking.istio.io/v1alpha3
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
hosts:
|
||||
- myapp.com # 这里不能使用"*",因为它与网格服务相结合
|
||||
- helloworld.default.svc.cluster.local
|
||||
gateways:
|
||||
- mesh # 适用于内部和外部
|
||||
- myapp-gateway
|
||||
http:
|
||||
- match:
|
||||
- uri:
|
||||
prefix: /hello
|
||||
gateways:
|
||||
- myapp-gateway # 此限制规则仅适用于 ingress gateway
|
||||
route:
|
||||
- destination:
|
||||
host: helloworld.default.svc.cluster.local
|
||||
subset: v1
|
||||
- match:
|
||||
- gateways:
|
||||
- mesh # 适用于网格内的所有服务
|
||||
route:
|
||||
- destination:
|
||||
host: helloworld.default.svc.cluster.local
|
||||
subset: v1
|
||||
{{< /text >}}
|
||||
- 创建一个名为 `gw` 的 `Gateway`,对应主机为 `*.test.com`,selector 仍然是 `istio: ingressgateway`,TLS 还是使用网关加载的证书。
|
||||
|
||||
## 路由规则对应用程序不生效
|
||||
- `VirtualService` 对象 `vs1` 配置主机名为 `service1.test.com`,网关设置为 `gw`
|
||||
|
||||
如果路由规则对 [Bookinfo](/zh/docs/examples/bookinfo/) 示例正常运行,但类似的版本路由规则对自己的应用程序没有生效,则可能需要更改 Kubernetes 服务。
|
||||
|
||||
Kubernetes 服务必须遵守某些限制才能利用 Istio 的 L7 路由功能。有关详细信息,请参阅 [Pod 和服务的要求](/zh/docs/setup/kubernetes/additional-setup/requirements)。
|
||||
|
||||
## Envoy 无法连接到 HTTP/1.0 服务
|
||||
|
||||
Envoy 需要使用 `HTTP/1.1` 或 `HTTP/2` 与上游服务通信。例如,当使用 [NGINX](https://www.nginx.com/) 作为 Envoy 后端提供流量服务时,需要将 NGINX 配置中的 [proxy_http_version](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_http_version) 指令设置为 “1.1”,因为 NGINX 默认值为 1.0。
|
||||
|
||||
配置样例如下:
|
||||
|
||||
{{< text plain >}}
|
||||
upstream http_backend {
|
||||
server 127.0.0.1:8080;
|
||||
|
||||
keepalive 16;
|
||||
}
|
||||
|
||||
server {
|
||||
...
|
||||
|
||||
location /http/ {
|
||||
proxy_pass http://http_backend;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
...
|
||||
}
|
||||
}
|
||||
{{< /text >}}
|
||||
|
||||
## Headless TCP 服务失去连接
|
||||
|
||||
如果部署了 `istio-citadel`,则 Envoy 每 15 分钟会进行一次重新启动来刷新证书。这会导致 TCP 连接或服务之间长连接被断开。
|
||||
|
||||
在应用程序中应为此类断开连接进行弹性处理,但如果仍希望防止断开连接发生,则需要禁用双向 TLS 和 `istio-citadel` 部署。
|
||||
|
||||
首先,编辑 `istio` 配置以禁用双向 TLS:
|
||||
|
||||
{{< text bash >}}
|
||||
$ kubectl edit configmap -n istio-system istio
|
||||
$ kubectl delete pods -n istio-system -l istio=pilot
|
||||
{{< /text >}}
|
||||
|
||||
接着,缩减 `istio-citadel` 部署来禁止 Envoy 重启:
|
||||
|
||||
{{< text bash >}}
|
||||
$ kubectl scale --replicas=0 deploy/istio-citadel -n istio-system
|
||||
{{< /text >}}
|
||||
|
||||
通过以上步骤则可以防止 Istio 重新启动 Envoy 导致的 TCP 连接断开。
|
||||
- `VirtualService` 对象 `vs2` 配置主机名为 `service2.test.com`,网关设置为 `gw`
|
||||
|
|
|
|||
Loading…
Reference in New Issue