第 16 章 配置路由

16.1. 路由配置

16.1.1. 创建基于 HTTP 的路由

路由允许您通过公共 URL 托管您的应用。根据应用的网络安全配置,它可以安全或不受保护。基于 HTTP 的路由是一种不安全的路由,使用基本的 HTTP 路由协议,并在不安全的应用端口上公开服务。

以下流程描述了如何使用 hello-openshift 应用创建到 Web 应用的简单基于 HTTP 的路由。

先决条件

  • 已安装 OpenShift CLI(oc)。
  • 以管理员身份登录。
  • 您有一个 Web 应用,它公开了侦听端口上流量的端口和 TCP 端点。

流程

  1. 运行以下命令,创建名为 hello-openshift 的项目:

    $ oc new-project hello-openshift
  2. 运行以下命令在项目中创建 pod:

    $ oc create -f https://raw.githubusercontent.com/openshift/origin/master/examples/hello-openshift/hello-pod.json
  3. 运行以下命令,创建一个名 为 hello-openshift 的服务:

    $ oc expose pod/hello-openshift
  4. 运行以下命令,创建到 hello-openshift 应用的不安全路由:

    $ oc expose svc hello-openshift

    如果您检查生成的 Route 资源,它应该类似于如下:

    创建的不安全路由的 YAML 定义:

    apiVersion: route.openshift.io/v1
    kind: Route
    metadata:
      name: hello-openshift
    spec:
      host: hello-openshift-hello-openshift.<Ingress_Domain> 1
      port:
        targetPort: 8080
      to:
        kind: Service
        name: hello-openshift

    1
    <Ingress_Domain> 是默认的入口域名。
    注意

    要显示默认入口域,请运行以下命令:

    $ oc get ingresses.config/cluster -o jsonpath={.spec.domain}

16.1.2. 配置路由超时

如果您的服务需要低超时(满足服务级别可用性 (SLA) 目的)或高超时(具有慢速后端的情况),您可以为现有路由配置默认超时。

先决条件

  • 您需要在运行的集群中部署了 Ingress Controller。

流程

  1. 使用 oc annotate 命令,为路由添加超时:

    $ oc annotate route <route_name> \
        --overwrite haproxy.router.openshift.io/timeout=<timeout><time_unit> 1
    1
    支持的时间单位是微秒 (us)、毫秒 (ms)、秒钟 (s)、分钟 (m)、小时 (h)、或天 (d)。

    以下示例在名为 myroute 的路由上设置两秒的超时:

    $ oc annotate route myroute --overwrite haproxy.router.openshift.io/timeout=2s

16.1.3. 启用 HTTP 严格传输安全性

HTTP 严格传输安全性 (HSTS) 策略是一种安全增强,可确保主机上只允许 HTTPS 流量。所有 HTTP 请求都会默认丢弃。这可用于确保与网站安全交互,或提供安全应用程序让用户受益。

当 HSTS 启用时,HSTS 会添加一个 Strict Transport Security 标头到站点的 HTTPS 响应。您可以在要重定向的路由中使用 insecureEdgeTerminationPolicy 值,以将 HTTP 发送到 HTTPS。但是,当启用 HSTS 时,客户端会在发送请求前将所有来自 HTTP URL 的请求更改为 HTTPS,从而消除对重定向的需求。客户端不需要支持此功能,而且也可通过设置 max-age=0 来禁用。

重要

HSTS 仅适用于安全路由(边缘终止或重新加密)。其配置在 HTTP 或传递路由上无效。

流程

  • 要在路由上启用 HSTS,请将 haproxy.router.openshift.io/hsts_header 值添加到边缘终止或重新加密路由:

    apiVersion: v1
    kind: Route
    metadata:
      annotations:
        haproxy.router.openshift.io/hsts_header: max-age=31536000;includeSubDomains;preload 1 2 3
    1
    max-age 是唯一的必要参数。它会测量 HSTS 策略生效的时间长度,以秒为单位。每当从主机收到含有 HSTS 标头的响应时,客户端会更新 max-age。如果 max-age 超时,客户端会丢弃该策略。
    2
    includeSubDomains 是可选的。含有此参数时,它会告知客户端应像主机一样对待主机上的所有子域。
    3
    preload 是可选的。当 max-age 大于 0 时,在 haproxy.router.openshift.io/hsts_header 中包含 preload 会使外部服务将这个站点包括在 HSTS 预加载列表中。例如,Google 等站点可以构造设有 preload 的站点的列表。浏览器可以使用这些列表来决定哪些站点可通过 HTTPS 进行通信,然后再与站点交互。如果没有设置 preload,浏览器必须通过 HTTPS 与站点交互才能获取该标头。

16.1.4. 吞吐量问题错误排解

有时,通过 OpenShift Container Platform 部署的应用程序可能会导致网络吞吐量问题,如特定服务间的延迟异常高。

如果 pod 日志未能揭示造成问题的原因,请使用以下方法分析性能问题:

  • 使用 ping 或 tcpdump 等数据包分析器,分析 pod 与其节点之间的流量。

    例如,在每个 pod 上运行 tcpdump 工具,同时重现导致问题的行为。检查两端的捕获信息,以便比较发送和接收时间戳来分析与 pod 往来的流量的延迟。如果节点接口被其他 pod、存储设备或者数据平面的流量过载,则 OpenShift Container Platform 中可能会出现延迟。

    $ tcpdump -s 0 -i any -w /tmp/dump.pcap host <podip 1> && host <podip 2> 1
    1
    podip 是 pod 的 IP 地址。运行 oc get pod <pod_name> -o wide 命令来获取 pod 的 IP 地址。

    tcpdump 在 /tmp/dump.pcap 中生成一个包含这两个 pod 间所有流量的文件。最好在运行分析器后立即重现问题,并在问题重现完成后马上停止分析器,从而尽量减小文件的大小。您还可以通过以下命令,在节点之间运行数据包分析器(从考量范围中剔除 SDN):

    $ tcpdump -s 0 -i any -w /tmp/dump.pcap port 4789
  • 使用 iperf 等带宽测量工具来测量数据流吞吐量和 UDP 吞吐量。先从 pod 运行该工具,再从节点运行,以此来查找瓶颈。

16.1.5. 使用 Cookie 来保持路由有状态性

OpenShift Container Platform 提供粘性会话,通过确保所有流量都到达同一端点来实现有状态应用程序流量。但是,如果端点 pod 以重启、扩展或更改配置的方式被终止,这种有状态性可能会消失。

OpenShift Container Platform 可以使用 Cookie 来配置会话持久性。Ingress Controller 选择一个端点来处理任何用户请求,并为会话创建一个 Cookie。Cookie 在响应请求时返回,用户则通过会话中的下一请求发回 Cookie。Cookie 告知 Ingress Controller 哪个端点正在处理会话,确保客户端请求使用这个 Cookie 使请求路由到同一个 pod。

注意

Cookie 无法在直通路由上设置,因为无法看到 HTTP 流量。相反,数字根据源 IP 地址计算,后者决定了后端。

如果后端有变化,流量可以定向到错误的服务器,使其更少粘性。如果您使用隐藏源 IP 的负载均衡器,则会为所有连接设置相同的数字,并将流量发送到同一 pod。

16.1.6. 基于路径的路由

基于路径的路由指定了一个路径组件,可以与 URL 进行比较,该 URL 需要基于 HTTP 的路由流量。因此,可以使用同一主机名提供多个路由,每个主机名都有不同的路径。路由器应该匹配基于最具体路径的路由。不过,这还取决于路由器的实现。

下表显示了路由及其可访问性示例:

表 16.1. 路由可用性

Route当比较到可访问

www.example.com/test

www.example.com/test

www.example.com

www.example.com/testwww.example.com

www.example.com/test

www.example.com

www.example.com

www.example.com/text

yes(由主机匹配,而不是路由)

www.example.com

带有路径的未安全路由

apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: route-unsecured
spec:
  host: www.example.com
  path: "/test" 1
  to:
    kind: Service
    name: service-name

1
该路径是基于路径的路由的唯一添加属性。
注意

使用 passthrough TLS 时,基于路径的路由不可用,因为路由器不会在这种情况下终止 TLS,且无法读取请求的内容。

16.1.7. 特定于路由的注解

Ingress Controller 可以为它公开的所有路由设置默认选项。单个路由可以通过在其注解中提供特定配置来覆盖这些默认设置。红帽不支持在 Operator 管理的路由中添加路由注解。

重要

要创建带有多个源 IP 或子网的白名单,请使用以空格分隔的列表。任何其他限定类型会导致忽略列表,而不发出警告或错误消息。

表 16.2. 路由注解

变量描述默认的环境变量

haproxy.router.openshift.io/balance

设置负载平衡算法。可用选项包括 sourceroundrobinleastconn

passthrough 路由 使用 ROUTER_TCP_BALANCE_SCHEME 。否则,使用 ROUTER_LOAD_BALANCE_algorithm

haproxy.router.openshift.io/disable_cookies

禁用使用 cookie 来跟踪相关连接。如果设置为 "true""TRUE",则使用平衡算法来为每个传入的 HTTP 请求选择后端服务连接。

 

router.openshift.io/cookie_name

指定一个可选的、用于此路由的 cookie。名称只能包含大写字母和小写字母、数字、"_" 和 "-"。默认为路由的内部密钥进行哈希处理。

 

haproxy.router.openshift.io/pod-concurrent-connections

设置路由器支持的 pod 允许的最大连接数。
注: 如果有多个 pod,每个 pod 都有这些数量的连接。如果有多个路由器,它们之间没有协调关系,每个路由器都可能会多次连接。如果没有设置,或者将其设定为 0,则没有限制。

 

haproxy.router.openshift.io/rate-limit-connections

设置 'true' 或 'TRUE' 可 启用速率限制功能,该功能通过每个路由的特定后端上的粘滞位来实现。
注:使用此注解可提供基本保护,防止分布式拒绝服务 (DDoS) 攻击。

 

haproxy.router.openshift.io/rate-limit-connections.concurrent-tcp

限制通过同一源 IP 地址进行的并发 TCP 连接数。它接受一个数字值。
注:使用此注解可提供基本保护,防止分布式拒绝服务 (DDoS) 攻击。

 

haproxy.router.openshift.io/rate-limit-connections.rate-http

限制具有相同源 IP 地址的客户端可以发出 HTTP 请求的速率。它接受一个数字值。
注:使用此注解可提供基本保护,防止分布式拒绝服务 (DDoS) 攻击。

 

haproxy.router.openshift.io/rate-limit-connections.rate-tcp

限制具有相同源 IP 地址的客户端可以进行 TCP 连接的速率。它接受一个数字值。
注:使用此注解可提供基本保护,防止分布式拒绝服务 (DDoS) 攻击。

 

haproxy.router.openshift.io/timeout

为路由设定服务器端超时。(TimeUnits)

ROUTER_DEFAULT_SERVER_TIMEOUT

haproxy.router.openshift.io/timeout-tunnel

这个超时适用于隧道连接,如 WebSocket over cleartext、edge、reencrypt 或 passthrough 路由。使用 cleartext、边缘或 reencrypt 路由类型时,此注解会作为带有现有超时值的超时隧道应用。对于 passthrough 路由类型,注解优先于任何设定的现有超时值。

ROUTER_DEFAULT_TUNNEL_TIMEOUT

ingresses.config/cluster ingress.operator.openshift.io/hard-stop-after

您可以设置 IngressController 或 ingress 配置。此注释重新部署路由器并将 HA 代理配置为发出 haproxy hard-stop-after global 选项,该选项定义执行清洁软停止的最长时间。

ROUTER_HARD_STOP_AFTER

router.openshift.io/haproxy.health.check.interval

为后端健康检查设定间隔。(TimeUnits)

ROUTER_BACKEND_CHECK_INTERVAL

haproxy.router.openshift.io/ip_whitelist

为路由设置白名单。白名单是以空格分开的 IP 地址和 CIDR 范围列表,用来代表批准的源地址。来自白名单以外的 IP 地址的请求会被丢弃。

白名单中允许的最大 IP 地址和 CIDR 范围数为 61。

 

haproxy.router.openshift.io/hsts_header

为 edge terminated 或 re-encrypt 路由设置 Strict-Transport-Security 标头。

 

haproxy.router.openshift.io/log-send-hostname

在 Syslog 标头中设置 hostname 字段。使用系统的主机名。如果路由器启用了任何 Ingress API 日志记录方法(如 sidecar 或 Syslog 工具),则默认启用 log-send-hostname

 

haproxy.router.openshift.io/rewrite-target

在后端中设置请求的重写路径。

 

router.openshift.io/cookie-same-site

设置一个值来限制 cookies。数值是:

Lax:cookies 在访问的站点和第三方站点间进行传输。

Strict:cookies 仅限于访问的站点。

None:cookies 仅限于指定的站点。

这个值仅适用于重新加密和边缘路由。如需更多信息,请参阅 SameSite cookies 文档

 

haproxy.router.openshift.io/set-forwarded-headers

设置用于处理每个路由的 ForwardedX-Forwarded-For HTTP 标头的策略。数值是:

Append附加标头,保留任何现有的标头。这是默认值。

replace:设置标头,删除任何现有的标头。

Never:不设置标头,而是保留任何现有的标头。

if-none:如果没有设置标头,则设置它。

ROUTER_SET_FORWARDED_HEADERS

注意

环境变量不能编辑。

路由器超时变量

TimeUnits 由一个数字及一个时间单位表示:us *(microseconds), ms(毫秒,默认)、s(秒)、m (分钟)、h *(小时) 、d (天)。

正则表达式是: [1-9][0-9]*(us\|ms\|s\|m\|h\|d)。

变量默认描述

ROUTER_BACKEND_CHECK_INTERVAL

5000ms

后端上后续存活度检查之间的时长。

ROUTER_CLIENT_FIN_TIMEOUT

1s

控制连接到路由的客户端的 TCP FIN 超时周期。如果发送到关闭连接的 FIN 在给定时间内没有回答,HAProxy 会关闭连接。如果设置为较低值,并且在路由器上使用较少的资源,则这不会产生任何损害。

ROUTER_DEFAULT_CLIENT_TIMEOUT

30s

客户端必须确认或发送数据的时长。

ROUTER_DEFAULT_CONNECT_TIMEOUT

5s

最长连接时间。

ROUTER_DEFAULT_SERVER_FIN_TIMEOUT

1s

控制路由器到支持路由的 pod 的 TCP FIN 超时。

ROUTER_DEFAULT_SERVER_TIMEOUT

30s

服务器必须确认或发送数据的时长。

ROUTER_DEFAULT_TUNNEL_TIMEOUT

1h

TCP 或 WebSocket 连接保持打开的时长。每当 HAProxy 重新加载时,这个超时期限都会重置。

ROUTER_SLOWLORIS_HTTP_KEEPALIVE

300s

设置等待出现新 HTTP 请求的最长时间。如果设置得太低,可能会导致浏览器和应用程序无法期望较小的 keepalive 值。

某些有效的超时值可以是某些变量的总和,而不是特定的预期超时。例如: ROUTER_SLOWLORIS_HTTP_KEEPALIVE 调整 timeout http-keep-alive。默认情况下,它设置为 300s,但 HAProxy 也会在 tcp-request inspect-delay 上等待,它被设置为 5s。在这种情况下,整个超时时间将是 300s5s

ROUTER_SLOWLORIS_TIMEOUT

10s

HTTP 请求传输可以花费的时间长度。

RELOAD_INTERVAL

5s

允许路由器至少执行重新加载和接受新更改的频率。

ROUTER_METRICS_HAPROXY_TIMEOUT

5s

收集 HAProxy 指标的超时时间。

设置自定义超时的路由

apiVersion: route.openshift.io/v1
kind: Route
metadata:
  annotations:
    haproxy.router.openshift.io/timeout: 5500ms 1
...

1
使用 HAProxy 支持的时间单位(us, ms, s, m, h, d)指定新的超时时间。如果没有提供时间单位,ms 会被默认使用。
注意

如果为 passthrough 路由设置的服务器端的超时值太低,则会导致 WebSocket 连接在那个路由上经常出现超时的情况。

只允许一个特定 IP 地址的路由

metadata:
  annotations:
    haproxy.router.openshift.io/ip_whitelist: 192.168.1.10

允许多个 IP 地址的路由

metadata:
  annotations:
    haproxy.router.openshift.io/ip_whitelist: 192.168.1.10 192.168.1.11 192.168.1.12

允许 IP 地址 CIDR 网络的路由

metadata:
  annotations:
    haproxy.router.openshift.io/ip_whitelist: 192.168.1.0/24

允许 IP 地址和 IP 地址 CIDR 网络的路由

metadata:
  annotations:
    haproxy.router.openshift.io/ip_whitelist: 180.5.61.153 192.168.1.0/24 10.0.0.0/8

指定重写对象的路由

apiVersion: route.openshift.io/v1
kind: Route
metadata:
  annotations:
    haproxy.router.openshift.io/rewrite-target: / 1
...

1
/ 设为后端请求的重写路径。

在路由上设置 haproxy.router.openshift.io/rewrite-target 注解,指定 Ingress Controller 在将请求转发到后端应用程序之前,应该使用此路由在 HTTP 请求中重写路径。与 spec.path 中指定的路径匹配的请求路径部分将替换为注解中指定的重写对象。

下表提供了在 spec.path、请求路径和重写对象的各种组合中重写行为的路径示例。

表 16.3. rewrite-target 示例:

Route.spec.path请求路径重写目标转发请求路径

/foo

/foo

/

/

/foo

/foo/

/

/

/foo

/foo/bar

/

/bar

/foo

/foo/bar/

/

/bar/

/foo

/foo

/bar

/bar

/foo

/foo/

/bar

/bar/

/foo

/foo/bar

/baz

/baz/bar

/foo

/foo/bar/

/baz

/baz/bar/

/foo/

/foo

/

不适用(请求路径不匹配路由路径)

/foo/

/foo/

/

/

/foo/

/foo/bar

/

/bar

16.1.8. 配置路由准入策略

管理员和应用程序开发人员可在多个命名空间中运行具有相同域名的应用程序。这是针对多个团队开发的、在同一个主机名上公开的微服务的机构。

警告

只有在命名空间间有信任的集群才会启用跨命名空间之间的声明,否则恶意用户可能会接管主机名。因此,默认的准入策略不允许在命名空间间声明主机名。

先决条件

  • 必须具有集群管理员权限。

流程

  • 使用以下命令编辑 ingresscontroller 资源变量的.spec. routeAdmission 字段:

    $ oc -n openshift-ingress-operator patch ingresscontroller/default --patch '{"spec":{"routeAdmission":{"namespaceOwnership":"InterNamespaceAllowed"}}}' --type=merge

    Ingress 控制器配置参数

    spec:
      routeAdmission:
        namespaceOwnership: InterNamespaceAllowed
    ...

16.1.9. 通过 Ingress 对象创建路由

一些生态系统组件与 Ingress 资源集成,但与路由资源不集成。要涵盖此问题单,OpenShift Container Platform 会在创建 Ingress 对象时自动创建受管路由对象。当相应 Ingress 对象被删除时,这些路由对象会被删除。

流程

  1. 在 OpenShift Container Platform 控制台中或通过 oc create 命令来定义 Ingress 对象:

    Ingress 的 YAML 定义

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: frontend
      annotations:
        route.openshift.io/termination: "reencrypt" 1
    spec:
      rules:
      - host: www.example.com
        http:
          paths:
          - backend:
              service:
                name: frontend
                port:
                  number: 443
            path: /
            pathType: Prefix
      tls:
      - hosts:
        - www.example.com
        secretName: example-com-tls-certificate

    1
    route.openshift.io/termination 注解可用于配置 Routespec.tls.termination 字段,因为 Ingress 没有此字段。可接受的值为 edgepassthroughreencrypt。所有其他值都会被静默忽略。当注解值未设置时,edge 是默认路由。模板文件中必须定义 TLS 证书详细信息,才能实现默认的边缘路由。
    1. 如果您在 route.openshift.io/termination 注解中指定 passthrough 值,在 spec 中将 path 设置为 '',将 pathType 设置为 ImplementationSpecific

        spec:
          rules:
          - host: www.example.com
            http:
              paths:
              - path: ''
                pathType: ImplementationSpecific
                backend:
                  service:
                    name: frontend
                    port:
                      number: 443
    $ oc apply -f ingress.yaml
  2. 列出您的路由:

    $ oc get routes

    结果包括一个自动生成的路由,其名称以 frontend- 开头:

    NAME             HOST/PORT         PATH    SERVICES    PORT    TERMINATION          WILDCARD
    frontend-gnztq   www.example.com           frontend    443     reencrypt/Redirect   None

    如果您检查这个路由,它会类似于:

    自动生成的路由的 YAML 定义

    apiVersion: route.openshift.io/v1
    kind: Route
    metadata:
      name: frontend-gnztq
      ownerReferences:
      - apiVersion: networking.k8s.io/v1
        controller: true
        kind: Ingress
        name: frontend
        uid: 4e6c59cc-704d-4f44-b390-617d879033b6
    spec:
      host: www.example.com
      path: /
      port:
        targetPort: https
      tls:
        certificate: |
          -----BEGIN CERTIFICATE-----
          [...]
          -----END CERTIFICATE-----
        insecureEdgeTerminationPolicy: Redirect
        key: |
          -----BEGIN RSA PRIVATE KEY-----
          [...]
          -----END RSA PRIVATE KEY-----
        termination: reencrypt
      to:
        kind: Service
        name: frontend