×

创建基于 HTTP 的路由

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

以下过程描述了如何使用 `hello-openshift` 应用程序为例,为 Web 应用程序创建一个简单的基于 HTTP 的路由。

先决条件
  • 您已安装 OpenShift 命令行界面 ( `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` 资源,请运行以下命令

    $ oc get routes -o yaml <name of resource> (1)
    1 在此示例中,路由名为 `hello-openshift`。
已创建的不安全路由的示例 YAML 定义
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: hello-openshift
spec:
  host: hello-openshift-hello-openshift.<Ingress_Domain> (1)
  port:
    targetPort: 8080 (2)
  to:
    kind: Service
    name: hello-openshift
1 `<Ingress_Domain>` 是默认的 Ingress 域名。`ingresses.config/cluster` 对象在安装期间创建,不能更改。如果要指定不同的域名,可以使用 `appsDomain` 选项指定备用集群域名。
2 `targetPort` 是此路由指向的服务选择的 Pod 上的目标端口。

要显示您的默认 Ingress 域名,请运行以下命令

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

为 Ingress 控制器分片创建路由

路由允许您在 URL 上托管您的应用程序。在本例中,未设置主机名,路由使用子域名。当您指定子域名时,您会自动使用公开路由的 Ingress 控制器所在的域名。对于由多个 Ingress 控制器公开路由的情况,该路由将托管在多个 URL 上。

以下步骤描述了如何使用hello-openshift应用程序为例创建用于 Ingress 控制器分片的路由。

当需要在多个 Ingress 控制器之间平衡传入流量负载以及将流量隔离到特定 Ingress 控制器时,Ingress 控制器分片非常有用。例如,公司 A 连接到一个 Ingress 控制器,而公司 B 连接到另一个。

先决条件
  • 您已安装 OpenShift 命令行界面 ( `oc` )。

  • 您已登录,身份为项目管理员。

  • 您有一个 Web 应用程序,它公开了一个端口以及一个 HTTP 或 TLS 端点,用于监听该端口上的流量。

  • 您已配置 Ingress 控制器进行分片。

步骤
  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-route.yaml的路由定义。

    为分片创建的路由的 YAML 定义
    apiVersion: route.openshift.io/v1
    kind: Route
    metadata:
      labels:
        type: sharded (1)
      name: hello-openshift-edge
      namespace: hello-openshift
    spec:
      subdomain: hello-openshift (2)
      tls:
        termination: edge
      to:
        kind: Service
        name: hello-openshift
    1 标签键及其对应的标签值必须与 Ingress 控制器中指定的标签键和值匹配。在本例中,Ingress 控制器具有标签键和值type: sharded
    2 路由将使用subdomain字段的值公开。当您指定subdomain字段时,必须将主机名留空。如果您同时指定了hostsubdomain字段,则路由将使用host字段的值,并忽略subdomain字段。
  5. 使用hello-openshift-route.yaml通过运行以下命令为hello-openshift应用程序创建路由

    $ oc -n hello-openshift create -f hello-openshift-route.yaml
验证
  • 使用以下命令获取路由的状态

    $ oc -n hello-openshift get routes/hello-openshift-edge -o yaml

    生成的Route资源应类似于以下内容

    示例输出
    apiVersion: route.openshift.io/v1
    kind: Route
    metadata:
      labels:
        type: sharded
      name: hello-openshift-edge
      namespace: hello-openshift
    spec:
      subdomain: hello-openshift
      tls:
        termination: edge
      to:
        kind: Service
        name: hello-openshift
    status:
      ingress:
      - host: hello-openshift.<apps-sharded.basedomain.example.net> (1)
        routerCanonicalHostname: router-sharded.<apps-sharded.basedomain.example.net> (2)
        routerName: sharded (3)
    1 Ingress 控制器或路由器用于公开路由的主机名。host字段的值由 Ingress 控制器自动确定,并使用其域名。在本例中,Ingress 控制器的域名是<apps-sharded.basedomain.example.net>
    2 Ingress 控制器的主机名。
    3 Ingress 控制器的名称。在本例中,Ingress 控制器的名称为sharded

配置路由超时

当您拥有需要低超时(服务级别可用性 (SLA) 所需)或高超时(后端速度慢的情况)的服务时,您可以为现有路由配置默认超时。

先决条件
  • 您需要在正在运行的集群上部署 Ingress 控制器。

步骤
  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

HTTP 严格传输安全

HTTP 严格传输安全 (HSTS) 策略是一种安全增强功能,它向浏览器客户端发出信号,表明路由主机上只允许 HTTPS 流量。HSTS 还通过发出 HTTPS 传输所需的信号来优化 Web 流量,而无需使用 HTTP 重定向。HSTS 有助于加快与网站的交互速度。

实施 HSTS 策略时,HSTS 会将严格传输安全标头添加到来自站点的 HTTP 和 HTTPS 响应中。您可以使用路由中的insecureEdgeTerminationPolicy值将 HTTP 重定向到 HTTPS。实施 HSTS 后,客户端会将所有来自 HTTP URL 的请求更改为 HTTPS,然后再发送请求,从而无需重定向。

集群管理员可以配置 HSTS 以执行以下操作

  • 每个路由启用 HSTS

  • 每个路由禁用 HSTS

  • 对一组域名强制执行每个域的 HSTS,或将命名空间标签与域名结合使用

HSTS 仅适用于安全路由,无论是边缘终止还是重新加密。此配置对 HTTP 或直通路由无效。

每个路由启用 HTTP 严格传输安全

HTTP 严格传输安全 (HSTS) 实现在 HAProxy 模板中,并应用于具有haproxy.router.openshift.io/hsts_header批注的边缘和重新加密路由。

先决条件
  • 您已使用具有项目管理员权限的用户登录到集群。

  • 您已安装 OpenShift 命令行界面 ( `oc` )。

步骤
  • 要在路由上启用 HSTS,请将haproxy.router.openshift.io/hsts_header值添加到边缘终止或重新加密路由。您可以使用oc annotate工具通过运行以下命令来执行此操作

    $ oc annotate route <route_name> -n <namespace> --overwrite=true "haproxy.router.openshift.io/hsts_header"="max-age=31536000;\ (1)
    includeSubDomains;preload"
    1 在此示例中,最大年龄设置为31536000毫秒,大约为 8.5 小时。

    在此示例中,等号 (=) 位于引号中。这是正确执行 annotate 命令所必需的。

    配置了批注的示例路由
    apiVersion: route.openshift.io/v1
    kind: Route
    metadata:
      annotations:
        haproxy.router.openshift.io/hsts_header: max-age=31536000;includeSubDomains;preload   (1) (2) (3)
    ...
    spec:
      host: def.abc.com
      tls:
        termination: "reencrypt"
        ...
      wildcardPolicy: "Subdomain"
    1 必需。max-age用于衡量 HSTS 策略生效的时间长度(以秒为单位)。如果设置为0,则会否定该策略。
    2 可选。包含时,includeSubDomains告诉客户端主机的所有子域名必须与主机具有相同的 HSTS 策略。
    3 可选。当max-age大于 0 时,您可以在haproxy.router.openshift.io/hsts_header中添加preload,以允许外部服务将其站点包含在其 HSTS 预加载列表中。例如,Google 等站点可以构建一个已设置preload的站点列表。然后,浏览器可以使用这些列表来确定它们可以在 HTTPS 上与哪些站点通信,即使在它们与站点交互之前也是如此。如果没有设置preload,浏览器必须至少与站点通过 HTTPS 交互一次才能获取标头。

每个路由禁用 HTTP 严格传输安全

要禁用每个路由的 HTTP 严格传输安全 (HSTS),您可以将路由批注中的max-age值设置为0

先决条件
  • 您已使用具有项目管理员权限的用户登录到集群。

  • 您已安装 OpenShift 命令行界面 ( `oc` )。

步骤
  • 要禁用 HSTS,请通过输入以下命令将路由批注中的max-age值设置为0

    $ oc annotate route <route_name> -n <namespace> --overwrite=true "haproxy.router.openshift.io/hsts_header"="max-age=0"

    或者,您可以应用以下 YAML 来创建配置映射

    禁用每个路由 HSTS 的示例
    metadata:
      annotations:
        haproxy.router.openshift.io/hsts_header: max-age=0
  • 要禁用命名空间中每个路由的 HSTS,请输入以下命令

    $ oc annotate route --all -n <namespace> --overwrite=true "haproxy.router.openshift.io/hsts_header"="max-age=0"
验证
  1. 要查询所有路由的批注,请输入以下命令

    $ oc get route  --all-namespaces -o go-template='{{range .items}}{{if .metadata.annotations}}{{$a := index .metadata.annotations "haproxy.router.openshift.io/hsts_header"}}{{$n := .metadata.name}}{{with $a}}Name: {{$n}} HSTS: {{$a}}{{"\n"}}{{else}}{{""}}{{end}}{{end}}{{end}}'
    示例输出
    Name: routename HSTS: max-age=0

强制执行每个域的 HTTP 严格传输安全

要对安全路由强制执行每个域的 HTTP 严格传输安全 (HSTS),请将requiredHSTSPolicies记录添加到 Ingress 规范中以捕获 HSTS 策略的配置。

如果您配置了requiredHSTSPolicy来强制执行 HSTS,则任何新创建的路由都必须配置具有符合条件的 HSTS 策略批注。

要处理具有不符合条件的 HSTS 路由的升级集群,您可以更新源代码中的清单并应用更新。

您不能使用oc expose routeoc create route命令在强制执行 HSTS 的域中添加路由,因为这些命令的 API 不接受批注。

即使全局请求对所有路由使用 HSTS,HSTS 也不能应用于不安全路由或非 TLS 路由。

先决条件
  • 您已使用具有项目管理员权限的用户登录到集群。

  • 您已安装 OpenShift 命令行界面 ( `oc` )。

步骤
  1. 通过运行以下命令并根据需要更新字段来编辑 Ingress 配置 YAML

    $ oc edit ingresses.config.openshift.io/cluster
    HSTS 策略示例
    apiVersion: config.openshift.io/v1
    kind: Ingress
    metadata:
      name: cluster
    spec:
      domain: 'hello-openshift-default.apps.username.devcluster.openshift.com'
      requiredHSTSPolicies: (1)
      - domainPatterns: (2)
        - '*hello-openshift-default.apps.username.devcluster.openshift.com'
        - '*hello-openshift-default2.apps.username.devcluster.openshift.com'
        namespaceSelector: (3)
          matchLabels:
            myPolicy: strict
        maxAge: (4)
          smallestMaxAge: 1
          largestMaxAge: 31536000
        preloadPolicy: RequirePreload (5)
        includeSubDomainsPolicy: RequireIncludeSubDomains (6)
      - domainPatterns:
        - 'abc.example.com'
        - '*xyz.example.com'
        namespaceSelector:
          matchLabels: {}
        maxAge: {}
        preloadPolicy: NoOpinion
        includeSubDomainsPolicy: RequireNoIncludeSubDomains
    1 必需。requiredHSTSPolicies按顺序验证,第一个匹配的domainPatterns将应用。
    2 必需。您必须指定至少一个domainPatterns主机名。可以列出任意数量的域名。您可以为不同的domainPatterns包含多个强制执行选项部分。
    3 可选。如果包含namespaceSelector,则必须与路由所在的项目标签匹配,以强制对路由设置 HSTS 策略。仅匹配namespaceSelector而不匹配domainPatterns的路由不会被验证。
    4 必填。max-age以秒为单位衡量 HSTS 策略生效的时长。此策略设置允许强制执行最小和最大的max-age
    • largestMaxAge值必须介于02147483647之间。可以不指定它,这意味着不强制执行上限。

    • smallestMaxAge值必须介于02147483647之间。输入0可禁用 HSTS 以进行故障排除,否则如果不想禁用 HSTS,则输入1。可以不指定它,这意味着不强制执行下限。

    5 可选。在haproxy.router.openshift.io/hsts_header中包含preload允许外部服务将其站点包含在其 HSTS 预加载列表中。浏览器随后可以使用这些列表来确定在与站点交互之前可以与哪些站点通过 HTTPS 通信。如果没有设置preload,浏览器需要至少与站点交互一次才能获取标头。preload可以使用以下其中一种方式设置
    • RequirePreloadpreloadRequiredHSTSPolicy 要求。

    • RequireNoPreloadpreloadRequiredHSTSPolicy禁止。

    • NoOpinionpreloadRequiredHSTSPolicy无关紧要。

    6 可选。includeSubDomainsPolicy可以使用以下其中一种方式设置
    • RequireIncludeSubDomainsincludeSubDomainsRequiredHSTSPolicy 要求。

    • RequireNoIncludeSubDomainsincludeSubDomainsRequiredHSTSPolicy禁止。

    • NoOpinionincludeSubDomainsRequiredHSTSPolicy无关紧要。

  2. 您可以通过输入oc annotate命令将 HSTS 应用于集群中所有路由或特定命名空间中的所有路由。

    • 要将 HSTS 应用于集群中的所有路由,请输入oc annotate命令。例如

      $ oc annotate route --all --all-namespaces --overwrite=true "haproxy.router.openshift.io/hsts_header"="max-age=31536000"
    • 要将 HSTS 应用于特定命名空间中的所有路由,请输入oc annotate命令。例如

      $ oc annotate route --all -n my-namespace --overwrite=true "haproxy.router.openshift.io/hsts_header"="max-age=31536000"
验证

您可以查看已配置的 HSTS 策略。例如

  • 要查看为必需的 HSTS 策略设置的maxAge,请输入以下命令

    $ oc get clusteroperator/ingress -n openshift-ingress-operator -o jsonpath='{range .spec.requiredHSTSPolicies[*]}{.spec.requiredHSTSPolicies.maxAgePolicy.largestMaxAge}{"\n"}{end}'
  • 要查看所有路由上的 HSTS 注解,请输入以下命令

    $ oc get route  --all-namespaces -o go-template='{{range .items}}{{if .metadata.annotations}}{{$a := index .metadata.annotations "haproxy.router.openshift.io/hsts_header"}}{{$n := .metadata.name}}{{with $a}}Name: {{$n}} HSTS: {{$a}}{{"\n"}}{{else}}{{""}}{{end}}{{end}}{{end}}'
    示例输出
    Name: <_routename_> HSTS: max-age=31536000;preload;includeSubDomains

吞吐量问题排查方法

有时,使用 OpenShift Container Platform 部署的应用程序会导致网络吞吐量问题,例如特定服务之间出现异常高的延迟。

如果 Pod 日志未显示问题的任何原因,请使用以下方法分析性能问题

  • 使用数据包分析器(例如pingtcpdump)分析 Pod 及其节点之间的流量。

    例如,在每个 Pod 上运行tcpdump工具,同时重现导致问题的行为。检查两侧的捕获结果,比较发送和接收时间戳,以分析 Pod 与 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 之间的全部流量。您可以在问题重现之前短暂运行分析器,并在问题重现之后短暂停止分析器,以最大限度地减小文件大小。您还可以在节点之间运行数据包分析器,方法是:

    $ tcpdump -s 0 -i any -w /tmp/dump.pcap port 4789
  • 使用带宽测量工具(例如iperf)来测量流式吞吐量和 UDP 吞吐量。首先从 Pod 运行该工具,然后从节点运行该工具,以找到任何瓶颈。

  • 在某些情况下,集群可能会由于延迟问题而将带有路由 Pod 的节点标记为不健康。使用工作程序延迟配置文件来调整集群在采取措施之前等待节点状态更新的频率。

  • 如果您的集群指定了低延迟和高延迟节点,请配置 Ingress Controller 中的spec.nodePlacement字段以控制路由 Pod 的放置。

使用 Cookie 保持路由状态

OpenShift Container Platform 提供粘性会话,通过确保所有流量都命中相同的端点来启用有状态应用程序流量。但是,如果端点 Pod 终止(无论是通过重启、缩放还是配置更改),这种状态可能会消失。

OpenShift Container Platform 可以使用 Cookie 来配置会话持久性。入口控制器选择一个端点来处理任何用户请求,并为会话创建一个 Cookie。Cookie 在响应请求时返回给用户,用户在会话中的下一个请求中将 Cookie 发送回。Cookie 告诉入口控制器哪个端点正在处理会话,确保客户端请求使用 Cookie,以便它们被路由到同一个 Pod。

无法在直通路由上设置 Cookie,因为无法查看 HTTP 流量。相反,将根据源 IP 地址计算出一个数字,该数字决定后端。

如果后端更改,流量可能会被定向到错误的服务器,使其粘性降低。如果使用负载均衡器(隐藏源 IP),则所有连接都设置相同的数字,并且流量被发送到同一个 Pod。

您可以设置 Cookie 名称以覆盖路由的默认自动生成的名称。这允许接收路由流量的应用程序知道 Cookie 名称。删除 Cookie 可以强制下一个请求重新选择端点。结果是,如果服务器过载,该服务器会尝试从客户端删除请求并重新分配它们。

步骤
  1. 使用指定的 Cookie 名称注解路由

    $ oc annotate route <route_name> router.openshift.io/cookie_name="<cookie_name>"

    其中

    <route_name>

    指定路由的名称。

    <cookie_name>

    指定 Cookie 的名称。

    例如,要使用 Cookie 名称my_cookie注解路由my_route

    $ oc annotate route my_route router.openshift.io/cookie_name="my_cookie"
  2. 将路由主机名捕获到变量中

    $ ROUTE_NAME=$(oc get route <route_name> -o jsonpath='{.spec.host}')

    其中

    <route_name>

    指定路由的名称。

  3. 保存 Cookie,然后访问路由

    $ curl $ROUTE_NAME -k -c /tmp/cookie_jar

    连接路由时,使用上一个命令保存的 Cookie。

    $ curl $ROUTE_NAME -k -b /tmp/cookie_jar

基于路径的路由

基于路径的路由指定一个路径组件,可以与 URL 进行比较,这要求路由的流量必须基于 HTTP。因此,可以使用相同的 hostname 提供多个路由服务,每个路由具有不同的路径。路由器应根据最具体的路径到最不具体的路径匹配路由。

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

表 1. 路由可用性
路由 与…比较时 可访问

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

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

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 路径是基于路径的路由中唯一添加的属性。

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

HTTP 头配置

OpenShift Container Platform 提供了不同的方法来处理 HTTP 头。设置或删除头时,可以使用 Ingress Controller 或单个路由中的特定字段来修改请求和响应头。您还可以使用路由注释来设置某些头。配置头的各种方法在协同工作时可能会带来挑战。

您只能在IngressControllerRoute CR 中设置或删除头,不能追加它们。如果使用某个值设置了 HTTP 头,则该值必须完整,并且将来不需要追加。在需要追加头的情况下(例如 X-Forwarded-For 头),请使用spec.httpHeaders.forwardedHeaderPolicy 字段,而不是spec.httpHeaders.actions

优先级顺序

当在 Ingress Controller 和路由中都修改了相同的 HTTP 头时,HAProxy 会根据它是请求头还是响应头以某种方式优先处理操作。

  • 对于 HTTP 响应头,Ingress Controller 中指定的操作将在路由中指定的操作之后执行。这意味着 Ingress Controller 中指定的操作具有优先级。

  • 对于 HTTP 请求头,路由中指定的操作将在 Ingress Controller 中指定的操作之后执行。这意味着路由中指定的操作具有优先级。

例如,集群管理员使用以下配置在 Ingress Controller 中使用值DENY 设置 X-Frame-Options 响应头

IngressController 示例规范
apiVersion: operator.openshift.io/v1
kind: IngressController
# ...
spec:
  httpHeaders:
    actions:
      response:
      - name: X-Frame-Options
        action:
          type: Set
          set:
            value: DENY

路由所有者设置了与集群管理员在 Ingress Controller 中设置的相同的响应头,但使用以下配置使用了值SAMEORIGIN

Route 示例规范
apiVersion: route.openshift.io/v1
kind: Route
# ...
spec:
  httpHeaders:
    actions:
      response:
      - name: X-Frame-Options
        action:
          type: Set
          set:
            value: SAMEORIGIN

IngressController 规范和Route 规范都在配置 X-Frame-Options 响应头时,即使特定路由允许框架,在 Ingress Controller 中全局级别为此头设置的值也具有优先级。对于请求头,Route 规范值会覆盖IngressController 规范值。

出现此优先级是因为haproxy.config 文件使用以下逻辑,其中 Ingress Controller 被视为前端,单个路由被视为后端。应用于前端配置的头值DENY 会覆盖在后端设置的具有值SAMEORIGIN 的相同头。

frontend public
  http-response set-header X-Frame-Options 'DENY'

frontend fe_sni
  http-response set-header X-Frame-Options 'DENY'

frontend fe_no_sni
  http-response set-header X-Frame-Options 'DENY'

backend be_secure:openshift-monitoring:alertmanager-main
  http-response set-header X-Frame-Options 'SAMEORIGIN'

此外,在 Ingress Controller 或路由中定义的任何操作都将覆盖使用路由注释设置的值。

特殊情况下的头

以下头要么完全禁止设置或删除,要么在特定情况下允许。

表 2. 特殊情况下的头配置选项
头名称 可以使用IngressController 规范配置 可以使用Route 规范配置 禁止的原因 可以使用其他方法配置

proxy

proxy HTTP 请求头可用于通过将头值注入HTTP_PROXY 环境变量来利用易受攻击的 CGI 应用程序。proxy HTTP 请求头也是非标准的,在配置过程中容易出错。

host

当使用IngressController CR 设置host HTTP 请求头时,HAProxy 在查找正确的路由时可能会失败。

strict-transport-security

strict-transport-security HTTP 响应头已使用路由注释进行处理,不需要单独的实现。

是:haproxy.router.openshift.io/hsts_header 路由注释

cookieset-cookie

HAProxy 设置的 Cookie 用于会话跟踪,以将客户端连接映射到特定的后端服务器。允许设置这些头可能会干扰 HAProxy 的会话关联并限制 HAProxy 对 Cookie 的所有权。

  • haproxy.router.openshift.io/disable_cookie 路由注释

  • haproxy.router.openshift.io/cookie_name 路由注释

在路由中设置或删除 HTTP 请求和响应头

您可以出于合规性目的或其他原因设置或删除某些 HTTP 请求和响应头。您可以为 Ingress Controller 提供服务的所有路由或特定路由设置或删除这些头。

例如,如果内容是用多种语言编写的,您可能希望启用 Web 应用程序为特定路由提供备用位置的内容,即使 Ingress Controller 提供路由服务的默认全局位置已指定。

以下步骤创建一个设置 Content-Location HTTP 请求头的路由,以便与应用程序关联的 URL(https://app.example.com)指向位置https://app.example.com/lang/en-us。将应用程序流量定向到此位置意味着任何使用该特定路由的人都正在访问用美式英语编写的 Web 内容。

先决条件
  • 您已安装 OpenShift CLI(oc)。

  • 您已以项目管理员身份登录到 OpenShift Container Platform 集群。

  • 您有一个 Web 应用程序,它公开了一个端口以及一个 HTTP 或 TLS 端点,用于监听该端口上的流量。

步骤
  1. 创建路由定义并将其保存在名为app-example-route.yaml 的文件中

    具有 HTTP 头指令的已创建路由的 YAML 定义
    apiVersion: route.openshift.io/v1
    kind: Route
    # ...
    spec:
      host: app.example.com
      tls:
        termination: edge
      to:
        kind: Service
        name: app-example
      httpHeaders:
        actions: (1)
          response: (2)
          - name: Content-Location (3)
            action:
              type: Set (4)
              set:
                value: /lang/en-us (5)
    1 您想要对 HTTP 头执行的操作列表。
    2 您想要更改的头类型。在本例中,为响应头。
    3 您想要更改的头名称。有关您可以设置或删除的可用头的列表,请参见HTTP 头配置
    4 对头执行的操作类型。此字段的值可以是SetDelete
    5 设置 HTTP 头时,必须提供value。该值可以是来自该头可用指令列表的字符串,例如DENY,也可以是将使用 HAProxy 的动态值语法解释的动态值。在本例中,该值设置为内容的相对位置。
  2. 使用新创建的路由定义创建到现有 Web 应用程序的路由

    $ oc -n app-example create -f app-example-route.yaml

对于 HTTP 请求头,路由定义中指定的操作将在 Ingress Controller 中对 HTTP 请求头执行的任何操作之后执行。这意味着在路由中为这些请求头设置的任何值都将优先于在 Ingress Controller 中设置的值。有关 HTTP 头处理顺序的更多信息,请参见HTTP 头配置

特定于路由的注释

Ingress Controller 可以为其公开的所有路由设置默认选项。单个路由可以通过在其注释中提供特定配置来覆盖其中一些默认值。Red Hat 不支持向操作员管理的路由添加路由注释。

要创建包含多个源 IP 或子网的白名单,请使用空格分隔的列表。任何其他类型的分隔符都会导致列表被忽略,不会显示警告或错误消息。

表 3. 路由注释
变量 描述 用作默认值的環境變量

haproxy.router.openshift.io/balance

设置负载均衡算法。可用选项包括randomsourceroundrobinleastconn。对于 TLS 直通路由,默认值为source。对于所有其他路由,默认值为random

对于直通路由,使用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'将启用速率限制功能,该功能是通过每个路由的特定后端的粘性表实现的。
注意:使用此注释可以提供针对拒绝服务攻击的基本保护。

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

限制通过同一源 IP 地址建立的并发 TCP 连接数。它接受数值。
注意:使用此注释可以提供针对拒绝服务攻击的基本保护。

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

限制具有相同源 IP 地址的客户端可以发出 HTTP 请求的速率。它接受数值。
注意:使用此注释可以提供针对拒绝服务攻击的基本保护。

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

限制具有相同源 IP 地址的客户端可以建立 TCP 连接的速率。它接受数值。
注意:使用此注释可以提供针对拒绝服务攻击的基本保护。

haproxy.router.openshift.io/timeout

设置路由的服务器端超时。(时间单位)

ROUTER_DEFAULT_SERVER_TIMEOUT

haproxy.router.openshift.io/timeout-tunnel

此超时适用于隧道连接,例如通过明文、边缘、重新加密或直通路由的 WebSocket。对于明文、边缘或重新加密路由类型,此注释将作为具有现有超时值的超时隧道应用。对于直通路由类型,此注释优先于任何已设置的现有超时值。

ROUTER_DEFAULT_TUNNEL_TIMEOUT

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

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

ROUTER_HARD_STOP_AFTER

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

设置后端健康检查的间隔。(时间单位)

ROUTER_BACKEND_CHECK_INTERVAL

haproxy.router.openshift.io/ip_whitelist

为路由设置允许列表。允许列表是用空格分隔的批准源地址的 IP 地址和 CIDR 范围列表。来自允许列表中不存在的 IP 地址的请求将被丢弃。

haproxy.config文件中直接可见的IP地址和CIDR范围的最大数量为61。[1]

haproxy.router.openshift.io/hsts_header

为边缘终止或重新加密路由设置 Strict-Transport-Security 标头。

haproxy.router.openshift.io/rewrite-target

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

router.openshift.io/cookie-same-site

设置一个值来限制cookie。值是

Lax:浏览器不会在跨站点请求中发送 Cookie,但在用户从外部站点导航到源站点时会发送 Cookie。当未指定SameSite值时,这是浏览器的默认行为。

Strict:浏览器仅对同站点请求发送 Cookie。

None:浏览器同时对跨站点请求和同站点请求发送 Cookie。

此值仅适用于重新加密和边缘路由。有关更多信息,请参阅SameSite Cookie 文档

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

设置每个路由处理ForwardedX-Forwarded-ForHTTP标头的策略。值是

append:追加标头,保留任何现有标头。这是默认值。

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

never:从不设置标头,但保留任何现有标头。

if-none:如果尚未设置标头,则设置标头。

ROUTER_SET_FORWARDED_HEADERS

  1. 如果允许列表中的 IP 地址和 CIDR 范围数量超过 61 个,则将其写入单独的文件,然后从haproxy.config中引用该文件。此文件存储在var/lib/haproxy/router/whitelists文件夹中。

    要确保将地址写入允许列表,请检查 Ingress Controller 配置文件中是否列出了完整的 CIDR 范围列表。etcd 对象大小限制会限制路由注释可以有多大。因此,它会为允许列表中可以包含的 IP 地址和 CIDR 范围的最大数量设置一个阈值。

环境变量无法编辑。

路由器超时变量

TimeUnits由一个数字后跟单位表示:us(微秒)、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

为直通路由设置过低的服务器端超时值可能会导致该路由上的 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 控制器应在将请求转发到后端应用程序之前,使用此路由重写 HTTP 请求中的路径。与 spec.path 中指定的路径匹配的请求路径部分将替换为注解中指定的重写目标。

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

表 4. 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

/

N/A(请求路径与路由路径不匹配)

/foo/

/foo/

/

/

/foo/

/foo/bar

/

/bar

haproxy.router.openshift.io/rewrite-target 中某些特殊字符需要特殊处理,因为必须正确转义它们。请参考下表了解如何处理这些字符。

表 5. 特殊字符处理
对于字符 使用字符 备注

#

\#

避免使用 #,因为它会终止重写表达式

%

% 或 %%

避免使用奇数序列,例如 %%%

\’

避免使用 ‘,因为它会被忽略

所有其他有效的 URL 字符无需转义即可使用。

配置路由准入策略

管理员和应用程序开发人员可以在具有相同域名但不同的命名空间中运行应用程序。这适用于多个团队开发在同一主机名上公开的微服务的组织。

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

先决条件
  • 集群管理员权限。

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

    $ oc -n openshift-ingress-operator patch ingresscontroller/default --patch '{"spec":{"routeAdmission":{"namespaceOwnership":"InterNamespaceAllowed"}}}' --type=merge
    Ingress 控制器配置示例
    spec:
      routeAdmission:
        namespaceOwnership: InterNamespaceAllowed
    ...

    或者,您可以应用以下 YAML 来配置路由准入策略

    apiVersion: operator.openshift.io/v1
    kind: IngressController
    metadata:
      name: default
      namespace: openshift-ingress-operator
    spec:
      routeAdmission:
        namespaceOwnership: InterNamespaceAllowed

通过 Ingress 对象创建路由

某些生态系统组件与 Ingress 资源集成,但与路由资源不集成。为了解决这种情况,OpenShift Container Platform 在创建 Ingress 对象时会自动创建托管路由对象。当相应的 Ingress 对象被删除时,这些路由对象也会被删除。

步骤
  1. 在 OpenShift Container Platform 控制台中定义 Ingress 对象,或输入 oc create 命令

    Ingress 的 YAML 定义
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: frontend
      annotations:
        route.openshift.io/termination: "reencrypt" (1)
        route.openshift.io/destination-ca-certificate-secret: secret-ca-cert (3)
    spec:
      rules:
      - host: www.example.com (2)
        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 证书详细信息才能实现默认 edge 路由。
    2 使用 Ingress 对象时,必须指定显式主机名,这与使用路由时不同。您可以使用 <host_name>.<cluster_ingress_domain> 语法(例如 apps.openshiftdemos.com)来利用集群的 *.<cluster_ingress_domain> 通配符 DNS 记录和服务证书。否则,您必须确保存在所选主机名的 DNS 记录。
    1. 如果在 route.openshift.io/termination 注解中指定 passthrough 值,请在规范中将 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
    3 route.openshift.io/destination-ca-certificate-secret 可用于 Ingress 对象,以定义具有自定义目标证书 (CA) 的路由。该注解引用一个 kubernetes 密钥 secret-ca-cert,该密钥将插入到生成的路由中。
    1. 要从 ingress 对象指定具有目标 CA 的路由对象,必须创建一个 kubernetes.io/tlsOpaque 类型密钥,并在密钥的 data.tls.crt 说明符中使用 PEM 编码格式的证书。

  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
        destinationCACertificate: |
          -----BEGIN CERTIFICATE-----
          [...]
          -----END CERTIFICATE-----
      to:
        kind: Service
        name: frontend

使用默认证书通过 Ingress 对象创建路由

如果您创建 Ingress 对象时未指定任何 TLS 配置,则 OpenShift Container Platform 会生成一个不安全的路由。要创建使用默认 ingress 证书生成安全、边缘终止路由的 Ingress 对象,您可以按如下方式指定空的 TLS 配置。

先决条件
  • 您有一个要公开的服务。

  • 您可以访问 OpenShift CLI (oc)。

步骤
  1. 为 Ingress 对象创建一个 YAML 文件。在此示例中,该文件名为 example-ingress.yaml

    Ingress 对象的 YAML 定义
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: frontend
      ...
    spec:
      rules:
        ...
      tls:
      - {} (1)
    1 使用此确切语法来指定 TLS,而不指定自定义证书。
  2. 通过运行以下命令来创建 Ingress 对象

    $ oc create -f example-ingress.yaml
验证
  • 通过运行以下命令验证 OpenShift Container Platform 是否已为 Ingress 对象创建预期的路由

    $ oc get routes -o yaml
    示例输出
    apiVersion: v1
    items:
    - apiVersion: route.openshift.io/v1
      kind: Route
      metadata:
        name: frontend-j9sdd (1)
        ...
      spec:
      ...
        tls: (2)
          insecureEdgeTerminationPolicy: Redirect
          termination: edge (3)
      ...
    1 路由名称包含 Ingress 对象的名称以及随机后缀。
    2 为了使用默认证书,路由不应指定 spec.certificate
    3 路由应指定 edge 终止策略。

在 Ingress 注解中使用目标 CA 证书创建路由

route.openshift.io/destination-ca-certificate-secret 注解可用于 Ingress 对象,以定义具有自定义目标 CA 证书的路由。

先决条件
  • 您可能拥有使用 PEM 编码的文件中的证书/密钥对,其中证书对于路由主机有效。

  • 您可能拥有使用 PEM 编码的单独 CA 证书,它完成证书链。

  • 您必须拥有使用 PEM 编码的单独目标 CA 证书。

  • 您必须有一个要公开的服务。

步骤
  1. route.openshift.io/destination-ca-certificate-secret 添加到 Ingress 注解

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: frontend
      annotations:
        route.openshift.io/termination: "reencrypt"
        route.openshift.io/destination-ca-certificate-secret: secret-ca-cert (1)
    ...
    1 该注解引用一个 kubernetes 密钥。
  2. 此注解中引用的密钥将插入到生成的路由中。

    示例输出
    apiVersion: route.openshift.io/v1
    kind: Route
    metadata:
      name: frontend
      annotations:
        route.openshift.io/termination: reencrypt
        route.openshift.io/destination-ca-certificate-secret: secret-ca-cert
    spec:
    ...
      tls:
        insecureEdgeTerminationPolicy: Redirect
        termination: reencrypt
        destinationCACertificate: |
          -----BEGIN CERTIFICATE-----
          [...]
          -----END CERTIFICATE-----
    ...

为双栈网络配置 OpenShift Container Platform Ingress 控制器

如果您的 OpenShift Container Platform 集群配置为 IPv4 和 IPv6 双栈网络,则您的集群可以通过 OpenShift Container Platform 路由外部访问。

Ingress 控制器会自动为同时具有 IPv4 和 IPv6 端点的服务提供服务,但您可以为单栈或双栈服务配置 Ingress 控制器。

先决条件
  • 您在裸机上部署了一个 OpenShift Container Platform 集群。

  • 您已安装 OpenShift 命令行界面 ( `oc` )。

步骤
  1. 要让 Ingress 控制器通过 IPv4/IPv6 向工作负载提供流量,您可以创建一个 service YAML 文件或修改现有的 service YAML 文件,方法是设置ipFamiliesipFamilyPolicy字段。例如:

    示例 service YAML 文件
    apiVersion: v1
    kind: Service
    metadata:
      creationTimestamp: yyyy-mm-ddT00:00:00Z
      labels:
        name: <service_name>
        manager: kubectl-create
        operation: Update
        time: yyyy-mm-ddT00:00:00Z
      name: <service_name>
      namespace: <namespace_name>
      resourceVersion: "<resource_version_number>"
      selfLink: "/api/v1/namespaces/<namespace_name>/services/<service_name>"
      uid: <uid_number>
    spec:
      clusterIP: 172.30.0.0/16
      clusterIPs: (1)
      - 172.30.0.0/16
      - <second_IP_address>
      ipFamilies: (2)
      - IPv4
      - IPv6
      ipFamilyPolicy: RequireDualStack (3)
      ports:
      - port: 8080
        protocol: TCP
        targetport: 8080
      selector:
        name: <namespace_name>
      sessionAffinity: None
      type: ClusterIP
    status:
      loadbalancer: {}
    1 在双栈实例中,会提供两个不同的clusterIPs
    2 对于单栈实例,请输入IPv4IPv6。对于双栈实例,请输入IPv4IPv6
    3 对于单栈实例,请输入SingleStack。对于双栈实例,请输入RequireDualStack

    这些资源会生成相应的endpoints。Ingress 控制器现在监控endpointslices

  2. 要查看endpoints,请输入以下命令:

    $ oc get endpoints
  3. 要查看endpointslices,请输入以下命令:

    $ oc get endpointslices