contour 是基于envoy实现的kubernetes ingress controller。除了支持官方的 Ingress对象 ,Ingress对象一直没有处于beta阶段,发展比较慢,无法满足实际生产使用,社区通过注解的方式扩展,以表达HTTP路由缺少的属性。
而且还支持了 HTTPProxy
。 HTTPProxy
是通过自定义资源定义(CRD)的方式扩展Ingress API的功能,以提供更丰富的用户体验,并解决后者在多租户环境中使用的限制。
有如下的优势:
此外contour 已经可以代替istio,成为knative 网络管理组件。非常值得投入。具体参见 Knative Install using Contour on a Kubernetes Cluster 。
下面主要我们介绍一下HTTPProxy API规范
与Ingress相似,HTTPProxy支持基于名称的虚拟Host。基于名称的虚拟Host使用具有相同IP地址的多个Host名。
foo.bar.com --| |-> foo.bar.com s1:80 | 178.91.123.132 | bar.foo.com --| |-> bar.foo.com s2:80
与Ingress不同,每个HTTPProxy对象仅支持一个根域。例如,此Ingress对象:
# ingress-name.yaml apiVersion: extensions/v1beta1 kind: Ingress metadata: name: name-example spec: rules: - host: foo1.bar.com http: paths: - backend: serviceName: s1 servicePort: 80 - host: bar1.bar.com http: paths: - backend: serviceName: s2 servicePort: 80
必须由两个不同的 HTTPProxy
对象表示:
# httpproxy-name.yaml apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: name-example-foo namespace: default spec: virtualhost: fqdn: foo1.bar.com routes: - services: - name: s1 port: 80 --- apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: name-example-bar namespace: default spec: virtualhost: fqdn: bar1.bar.com routes: - services: - name: s2 port: 80
HTTPProxy遵循与Ingress类似的模式来配置TLS secret。
您可以通过指定包含TLS私钥和证书信息的Secret来保护HTTPProxy。Contour(通过Envoy)使用SNI TLS扩展来处理此行为。如果多个HTTPProxy使用同一secret,则证书必须为每个fqdn包括必要的Subject Authority Name(SAN)。
Contour也遵循“安全第一”的方法。为虚拟Host启用TLS后,对不安全端口的任何请求都将使用301重定向重定向到安全接口。通过启用Route上的 spec.routes.permitInsecure
参数,可以将特定的路由配置为覆盖此行为并处理不安全的请求。
TLS密钥必须包含名为tls.crt和tls.key的密钥,其中包含要用于TLS的证书和私钥,例如:
# ingress-tls.secret.yaml apiVersion: v1 data: tls.crt: base64 encoded cert tls.key: base64 encoded key kind: Secret metadata: name: testsecret namespace: default type: kubernetes.io/tls
可以使用 tls.secretName
属性将HTTPProxy配置为使用此secret:
# httpproxy-tls.yaml apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: tls-example namespace: default spec: virtualhost: fqdn: foo2.bar.com tls: secretName: testsecret routes: - services: - name: s1 port: 80
如果 tls.secretName
属性包含斜杠,例如。然后,根据TLS证书委派,将从somenamespace中的somesecret读取TLS证书。有关更多信息,请参见下面的TLS证书委派。
可以通过设置 spec.virtualhost.tls.minimumProtocolVersion
来指定vhost应使用的TLS最低协议版本:
HTTPProxy可以通过首先使用以下内容注释上游Kubernetes服务来代理上游TLS连接:projectcontour.io/upstream-protocol.tls:"443,https“。此注释告诉Contour TLS连接应使用哪个端口。在此示例中,上游服务名为https,并且使用端口443。此外,Envoy可以验证后端服务的证书。 HTTPProxy的服务可以选择指定一个验证结构,该结构具有强制的caSecret密钥和强制的subjectName。
注意:如果存在 spec.routes.services [].validation
,则 spec.routes.services[].{name,port}
必须指向具有匹配projectcontour.io/upstream-protocol.tls服务注释的服务。
apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: secure-backend spec: virtualhost: fqdn: www.example.com routes: - services: - name: service port: 8443 validation: caSecret: my-certificate-authority subjectName: backend.example.com
如果验证规范是在服务上定义的,但是它所引用的secret不存在,则Contour将拒绝更新并相应地设置HTTPProxy对象的状态。这有助于防止代理到请求验证但尚不可用的上游的情况。
Status: Current Status: invalid Description: route "/": service "tls-nginx": upstreamValidation requested but secret not found or misconfigured
为了支持通配符证书,*.somedomain.com的TLS证书(存储在群集管理员控制的名称空间中),Contour支持一种称为TLS证书委派的功能。此功能允许TLS证书的所有者委派(为了引用TLS证书)许可Contour从另一个名称空间读取Secret对象。
TLSCertificateDelegation
资源在规范中定义了一组委托。每个委托都从创建 TLSCertificateDelegation
的名称空间引用一个secretName,并描述一组可以引用证书的targetNamespaces。如果所有名称空间都能够引用该secret,则将“*”设置为targetNamespaces的值(请参见下面的示例)。
apiVersion: projectcontour.io/v1 kind: TLSCertificateDelegation metadata: name: example-com-wildcard namespace: www-admin spec: delegations: - secretName: example-com-wildcard targetNamespaces: - example-com - secretName: another-com-wildcard targetNamespaces: - "\*" --- apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: www namespace: example-com spec: virtualhost: fqdn: foo2.bar.com tls: secretName: www-admin/example-com-wildcard routes: - services: - name: s1
在此示例中,Contour在admin名称空间中引用Secret example-com-wildcard的权限已委派给example-com名称空间中的HTTPProxy对象。另外,Contour引用所有命名空间中的Secret another-com-wildcard的权限已委派给群集中的所有HTTPProxy对象。
HTTPProxy中的每个Route条目可能包含一个或多个条件。这些条件在传递给Envoy的路线上与AND运算符结合在一起。
条件可以是 prefix
或 header
条件。
对于 prefix
,这将添加 path prefix。
任何条件块中最多可以存在一个 prefix
条件。
prefix
条件必须以/开头(如果存在)。
对于 header
条件,有一个必填字段, name
和五个运算符字段: present
, contains
, notcontains
, exact
, 和 notexact
。
present
是一个布尔值,并检查header是否存在。
contains
是一个字符串,并检查header是否包含该字符串。 notcontains
同样检查header不包含字符串。
exact
是一个字符串,并检查标题是否与整个字符串完全匹配。 notexact
检查标头与整个字符串不完全匹配。
HTTPProxy必须至少具有一条路由或包括在内。使用 prefix
条件匹配定义的路径。在此示例中,对multi-path.bar.com/blog或multi-path.bar.com/blog/*的任何请求都将被路由到Service s2。对host 为multi-path.bar.com的所有其他请求将被路由到服务s1。
# httpproxy-multiple-paths.yaml apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: multiple-paths namespace: default spec: virtualhost: fqdn: multi-path.bar.com routes: - conditions: - prefix: / # matches everything else services: - name: s1 port: 80 - conditions: - prefix: /blog # matches \`multi-path.bar.com/blog\` or \`multi-path.bar.com/blog/\*\` services: - name: s2 port: 80
在以下示例中,我们匹配header并发送到不同的服务,如果不匹配,则使用默认路由。
# httpproxy-multiple-headers.yaml apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: multiple-paths namespace: default spec: virtualhost: fqdn: multi-path.bar.com routes: - conditions: - header: name: x-os contains: ios services: - name: s1 port: 80 - conditions: - header: name: x-os contains: android services: - name: s2 port: 80 - services: - name: s3 port: 80
HTTPProxy的主要功能之一是能够针对一个固定的path支持多个服务:
# httpproxy-multiple-upstreams.yaml apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: multiple-upstreams namespace: default spec: virtualhost: fqdn: multi.bar.com routes: - services: - name: s1 port: 80 - name: s2 port: 80
在此示例中,对multi.bar.com/的请求将在两个Kubernetes服务s1和s2之间进行负载平衡。当您需要在两个不同版本的应用程序之间分配给定URL的流量时,这很有用。
在多个上游构建的功能是可以定义上游服务的相对权重。当您要将少量流量发送到特定服务时,通常用于对应用程序新版本进行金丝雀测试。
# httpproxy-weight-shfiting.yaml apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: weight-shifting namespace: default spec: virtualhost: fqdn: weights.bar.com routes: - services: - name: s1 port: 80 weight: 10 - name: s2 port: 80 weight: 90
在此示例中,我们向服务s1发送10%的流量,而服务s2接收其余90%的流量。
HTTPProxy加权遵循一些特定规则:
每个服务或每个路由还支持操纵header。可以如下设置header或从请求或响应中删除header:
per-Service:
apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: header-manipulation namespace: default spec: virtualhost: fqdn: headers.bar.com routes: - services: - name: s1 port: 80 requestHeadersPolicy: set: - name: X-Foo value: bar remove: - X-Baz responseHeaderPolicy: set: - name: X-Service-Name value: s1 remove: - X-Internal-Secret
per-Route:
apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: header-manipulation namespace: default spec: virtualhost: fqdn: headers.bar.com routes: - services: - name: s1 port: 80 requestHeadersPolicy: set: - name: X-Foo value: bar remove: - X-Baz responseHeadersPolicy: set: - name: X-Service-Name value: s1 remove: - X-Internal-Secret
在这些示例中,我们为请求设置头X-Foo的值baz并删除X-Baz。然后,我们在响应上将X-Service-Name设置为值s1,并删除X-Internal-Secret。
每个路由都可以将服务指定为镜像。镜像服务将接收发送到任何非镜像服务的读取流量的副本。镜像流量被视为只读,镜像的任何响应都将被丢弃。
该服务对于记录流量以供以后重播或对新部署进行烟雾测试很有用。
apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: traffic-mirror namespace: default spec: virtualhost: fqdn: www.example.com routes: - conditions: - prefix: / services: - name: www port: 80 - name: www-mirror port: 80 mirror: true
可以将每个路由配置为具有超时策略和重试策略,如下所示:
# httpproxy-response-timeout.yaml apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: response-timeout namespace: default spec: virtualhost: fqdn: timeout.bar.com routes: - timeoutPolicy: response: 1s idle: 10s retryPolicy: count: 3 perTryTimeout: 150ms services: - name: s1 port: 80
在此示例中,对timeout.bar.com/的请求的响应超时策略为1s。这是指从代理处理完完整的客户端请求到服务器的响应被完全处理之间的时间。
timeoutPolicy.response timeoutPolicy.idle
TimeoutPolicy持续时间按照ParseDuration文档中指定的格式表示。输入值示例:“ 300ms”,“ 5s”,“ 1m”。有效时间单位为“ ns”,“ us”(或“ µs”),“ ms”,“ s”,“ m”,“ h”。字符串'infinity'也是有效输入,没有指定超时。
可以在Envoy的文档中找到更多信息。
retryPolicy:如果服务器返回5xx范围内的错误代码,或者服务器花费多于retryPolicy.perTryTimeout来处理请求,则将尝试重试。
每个路由都可以应用负载平衡策略来确定为请求选择了哪个端点。以下列表是可供选择的选项:
# httpproxy-lb-strategy.yaml apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: lb-strategy namespace: default spec: virtualhost: fqdn: strategy.bar.com routes: - conditions: - prefix: / services: - name: s1-strategy port: 80 - name: s2-strategy port: 80 loadBalancerPolicy: strategy: WeightedLeastRequest
会话亲缘关系(也称为粘性会话)是一种负载平衡策略,通过该策略,来自单个客户端的一系列请求将始终路由到同一应用程序后端。 Contour通过loadBalancerPolicy策略:COOKIE支持基于路由的会话亲缘关系。
# httpproxy-sticky-sessions.yaml apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: httpbin namespace: default spec: virtualhost: fqdn: httpbin.davecheney.com routes: - services: - name: httpbin port: 8080 loadBalancerPolicy: strategy: COOKIE
可以使用enableWebsockets字段在特定路由上启用WebSocket支持:
# httpproxy-websockets.yaml apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: chat namespace: default spec: virtualhost: fqdn: chat.example.com routes: - services: - name: chat-app port: 80 - conditions: - prefix: /websocket enableWebsockets: true # Setting this to true enables websocket for all paths that match /websocket services: - name: chat-app port: 80
HTTPProxy支持在将请求传递到后端服务之前重写HTTP请求URL路径。重写是在做出路由决定之后执行的,并且永远不会更改请求目的地。
pathRewritePolicy
字段指定应如何重写路径前缀。 pathRewritePolicy
为HTTP请求路径前缀匹配指定替换字符串。存在此字段时,将用替换字段中指定的文本替换请求匹配的路径前缀。如果HTTP请求路径长于匹配的前缀,则路径的其余部分保持不变。
apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: rewrite-example namespace: default spec: virtualhost: fqdn: rewrite.bar.com routes: - services: - name: s1 port: 80 pathRewritePolicy: replacePrefix: - replacement: /new/prefix
replacePrefix
字段接受一系列可能的替换。如果存在多个 replacePrefix
数组元素,则前缀字段可用于消除要应用的替换的歧义。 如果不存在前缀字段,则替换将应用于对路由进行的所有前缀匹配。如果存在前缀字段,则替换仅应用于具有完全匹配的前缀条件的路由。当一个HTTPProxy文档包含在多个父文档中时,指定一个以上的replacePrefix条目主要有用。
apiVersion: projectcontour.io/v1 kind: HTTPProxy metadata: name: rewrite-example namespace: default spec: virtualhost: fqdn: rewrite.bar.com routes: - services: - name: s1 port: 80 conditions: - prefix: /v1/api pathRewritePolicy: replacePrefix: - prefix: /v1/api replacement: /app/api/v1 - prefix: / replacement: /app
上面介绍了contour支持的ingress若干重要特性。此外还支持路由监控检测,Header策略等特性。如果需要更详细的介绍,可以阅读官方文档。
新版本的contour部署相对旧的版本,更加健壮。官方建议通过deployment部署contour(2个副本),然后通过daemonset的方式部署envoy。contour组件是contour ingress controller的控制层,而envoy为数据层。
如果是在公有云上,可以设置公有云的负载均衡器将流量打到边缘envoy上。如下图:
如果是私有云,则需要通过lvs集群。
随着企业容器化的深入,官方的ingress往往不能满足需求。将contour 引入现在的技术栈中,可以很好的解决痛点。而且contour 基于envoy实现,envoy社区非常活跃,相应contour也会很快将新版本的envoy的特性集成到ingress中。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 我们