理解OpenShift(1):网络之 Router 和 Route

发布时间:2020-07-19 12:14:29 作者:我是SammyLiu
来源:网络 阅读:981


** 本文基于 OpenShift 3.11,Kubernetes 1.11 进行测试 ***

 

1. OpenShift 为什么需要 Router 和 Route?

顾名思义,Router 是路由器,Route 是路由器中配置的路由。OpenShift 中的这两个概念是为了解决从集群外部(就是从除了集群节点以外的其它地方)访问服务的需求。不晓得为什么OpenShift 要将Kubernetes 中的 Ingress 改为 Router,我倒是觉得 Ingress 名字更贴切。

从外部通过 router 和从内部通过 servide 访问 pod 中的应用两个过程的简单的示意图如下:

理解OpenShift(1):网络之 Router 和 Route

上图中,某个应用的三个pod 分别位于 node1,node2 和 node3 上。OpenShift 中有三层IP地址概念:

因此,要从集群外部访问 pod 中的应用,无非两种方式:

2. OpenShift 如何利用 HAProxy 实现 router 和 route?

2.1 Router 部署

使用 ansible 采用默认配置部署 OpenShift 集群时,在集群 Infra 节点上,会以 Host networking 方式运行一个 HAProxy 的 pod,它会在所有网卡的 80 和 443 端口上进行监听。

[root@infra-node3 cloud-user]# netstat -lntp | grep haproxy
tcp        0      0 127.0.0.1:10443         0.0.0.0:*               LISTEN      583/haproxy         
tcp        0      0 127.0.0.1:10444         0.0.0.0:*               LISTEN      583/haproxy         
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      583/haproxy         
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      583/haproxy

其中,172.0.0.1 上的 10443 和 10444 是HAproxy 自己使用的。下文会有解释。

因此,在每个 infra 节点上,只能有一个 HAProxy pod,因为这些端口只能被占用一次。如果调度器找不到满足要求的节点,则router 服务的调度就会失败:

0/7 nodes are available: 2 node(s) didn't have free ports for the requested pod ports, 5 node(s) didn't match node selector

OpenShift HAProxy Router 支持两种部署方式:

OpenShift 提供了 oc adm router 命令来创建 router 服务。

创建router:

[root@master1 cloud-user]# oc adm router router2 --replicas=1 --service-account=routerinfo: password for stats user admin has been set to J3YyPjlbqf--> Creating router router2 ...
    warning: serviceaccounts "router" already exists
    clusterrolebinding.authorization.openshift.io "router-router2-role" created
    deploymentconfig.apps.openshift.io "router2" created
    service "router2" created--> Success

详细的部署方法请参见官方文档 https://docs.openshift.com/container-platform/3.11/install_config/router/default_haproxy_router.html。

2.2 Router pod 中的 HAProxy 进程

在 Router 服务的每个 pod 之中,openshift-router 进程启动了一个 haproy 进程:

UID        PID  PPID  C STIME TTY          TIME CMD1000000+     1     0  0 Nov21 ?        00:14:27 /usr/bin/openshift-router1000000+ 16011     1  0 12:42 ?        00:00:00 /usr/sbin/haproxy -f /var/lib/haproxy/conf/haproxy.config -p /var/lib/haproxy/run/haproxy.pid -x /var/lib/haproxy/run/haproxy.sock -sf 16004

查看 haproxy 使用的配置文件(只是部分):

-base /etc/-base /etc/-forwarded-.: /var/lib/haproxy/conf/error-page---keep--request inspect--request content accept -uri /
  http-request del- insensitive (RFC ), we need to convert the -request set-header Host % we need to redirect//var/lib/haproxy/conf/os_route_http_redirect.map) -%[base,map_reg(/var/lib/haproxy/conf/# determined by the next backend  the chain -request  inspect--request content accept  { req_ssl_hello_type  the connection is SNI and the route is a passthrough don
  #  the SNI , we also need to compare it  -insensitive mode (by converting it to lowercase) as RFC -/var/lib/haproxy/conf/os_sni_passthrough.map) -%[req.ssl_sni,lower,map_reg(/var/lib/haproxy/conf/os_tcp_be.map)] -request set-header X-Forwarded-Host %-request set-header X-Forwarded-Port %-request set-header X-Forwarded-Proto http  !-request set-header X-Forwarded-Proto https -request set-header X-Forwarded-Proto-Version h3  { ssl_fc_alpn --request add-header Forwarded =%[src];host=%[req.hdr(host)];proto=%[req.hdr(X-Forwarded-Proto)];proto-version=%[req.hdr(X-Forwarded-Proto---84nrt:jenkins:.: .: cookie 8669a19afc9f0fed6824feb9fb1cf4ac weight

为了简单期间,上面只是配置文件的部分内容,它主要包括三种类型:

因此,OpenShift 的路由器功能需要能对这三部分进行管理和控制。

关于负载均衡器和 HAProxy 的详细介绍,可以参考 Neutron 理解 (7): Neutron 是如何实现负载均衡器虚拟化的 这篇文章。

2.3 全局配置管理

要指定或修改 HAProxy 的全局配置,OpenShift 有提供两种方式:

(1)第一种是使用 oc adm router 命令在创建 router 时候指定各种参数,比如 --max-connections 用于设置最大连接数。比如:

oc adm router --max-connections=200000 --ports='81:80,444:443' router3

创建出来的HAProxy 的 maxconn 将是 20000,router3 这个服务对外暴露出来的端口是 81 和 444,但是 HAProxy pod 的端口依然是 80 和 443.

(2)通过设置 dc/<dc router名> 的环境变量来设置 router 的全局配置。

在官方文档 https://docs.openshift.com/container-platform/3.4/architecture/core_concepts/routes.html#haproxy-template-router 中有完整的环境变量列表。比如运行以下命令后,

 oc set env dc/router3 ROUTER_SERVICE_HTTPS_PORT=444 ROUTER_SERVICE_HTTP_PORT=81 STATS_PORT=1937

router3 会重新部署,新部署的HAProxy 的 https 监听端口是 444,http 监听端口是 80,统计端口是 1937.

 2.4 OpenShift passthrough 类型的 route 与 HAProxy backend

(1)通过OpenShift Console 或者 oc 命令创建一条 route,它将 sit 项目的 jenkins 服务暴露到域名 sitjenkins.com.cn:

在界面上创建 route:

理解OpenShift(1):网络之 Router 和 Route

理解OpenShift(1):网络之 Router 和 Route

结果:

Name:                   sitjenkins.com.cn
Namespace:              sitLabels:                 app=jenkins-ephemeral
                        template=jenkins-ephemeral-template
Annotations:            <none>Requested Host:         sitjenkins.com.cnPath:                   <none>TLS Termination:        passthroughEndpoint Port:          web

Service:        jenkins
Weight:         100 (100%)
Endpoints:      10.128.2.15:8080, 10.131.0.10:8080

这里,service name 起了一个中介作用,把 route 和服务的端点(也就是pod)连接了起来。

(2)router 服务的两个 pod 中的 HAProxy 进程的配置文件中多了一个backend:

# Secure backend, pass through
backend be_tcp:sit:sitjenkins.com.cn
  balance source

  hash-type consistent
  timeout check 5000ms}
  server pod:jenkins-1-bqhfj:jenkins:10.128.2.15:8080 10.128.2.15:8080 weight 256 check inter 5000ms
  server pod:jenkins-1-h3fff:jenkins:10.131.0.10:8080 10.131.0.10:8080 weight 256 check inter 5000ms

其中,这些后端 server 其实就是 pod,它们是 openshift 通过步骤(1)中的 service name 找到的。balance 是负载均衡策略,后文会解释。

(3)文件 /var/lib/haproxy/conf/os_sni_passthrough.map 中多了一条记录

sh-4.2$ cat /var/lib/haproxy/conf/os_sni_passthrough.map^sitjenkins\.com\.cn(:[0-9]+)?(/.*)?$ 1

(4)文件 /var/lib/haproxy/conf/os_tcp_be.map 中多了一条记录

sh-4.2$ cat /var/lib/haproxy/conf/os_tcp_be.map^sitjenkins\.com\.cn(:[0-9]+)?(/.*)?$ be_tcp:sit:sitjenkins.com.cn

(5)HAProxy 根据上面的 map 文件为该条 route 选择第(2)步中增加的 backend的逻辑如下

frontend public_ssl  #解释:前端协议 https,

  bind :443  ##前端端口 443
  tcp-request  inspect-delay 5s
  tcp-request content accept if { req_ssl_hello_type 1 }

  # if the connection is SNI and the route is a passthrough don't use the termination backend, just use the tcp backend
  # for the SNI case, we also need to compare it in case-insensitive mode (by converting it to lowercase) as RFC 4343 says
  acl sni req.ssl_sni -m found ##检查 https request 支持 sni
  acl sni_passthrough req.ssl_sni,lower,map_reg(/var/lib/haproxy/conf/os_sni_passthrough.map) -m found ##检查通过 sni 传来的 hostname 在 os_sni_patthrough.map 文件中
  use_backend %[req.ssl_sni,lower,map_reg(/var/lib/haproxy/conf/os_tcp_be.map)] if sni sni_passthrough ##从 oc_tcp_be.map 中根据 sni hostname 获取 backend name

  # if the route is SNI and NOT passthrough enter the termination flow
  use_backend be_sni if sni

  # non SNI requests should enter a default termination backend rather than the custom cert SNI backend since it
  # will not be able to match a cert to an SNI host
  default_backend be_no_sni

(6)HAPorxy 进程会重启,从而应用修改了的配置文件。

理解(5)中的脚本需要的一些背景知识:

从上面的蓝色注释中,我们能看到 HAProxy 进程通过 https 请求中通过 SNI 传入的域名 sitjenkins.com.cn ,在 os_tcp_be.map 文件中获取到了 backend 名称 be_tcp:sit:sitjenkins.com.cn,这样就和(2)步骤中的 backend 对应上了。

OpenShift 的 router 使用的 HAProxy 采用基于域名的负载均衡路由方式,示例如下,具体说明请参加官方文档。

理解OpenShift(1):网络之 Router 和 Route

2.5 OpenShift edge 和 re-encrypt 类型的 route 与 HAProxy

HAProxy 前端:前端依然是在 443 端口监听外部 HTTPS 请求

 sni

但是,当 TLS 终止类型不是 passthrough (edge 或者 re-encrypt)时,会使用backend be_sni。

backend be_sni
  server fe_sni 127.0.0.1:10444 weight 1 send-prox

而这个后端是由本机的 127.0.0.1:10444 提供服务,因此又转到了前端 fe_sni:

frontend fe_sni
  # terminate ssl on edge
  bind 127.0.0.1:10444 ssl no-sslv3 crt /var/lib/haproxy/router/certs/default.pem crt-list /var/lib/haproxy/conf/cert_config.map accept-proxy
  mode http。。。。。。

  # map to backend
  # Search from most specific to general path (host case).
  # Note: If no match, haproxy uses the default_backend, no other
  #       use_backend directives below this will be processed.
  use_backend %[base,map_reg(/var/lib/haproxy/conf/os_edge_reencrypt_be.map)]

  default_backend openshift_default

map 映射文件:

sh-4.2$ cat /var/lib/haproxy/conf/os_edge_reencrypt_be.map^edgejenkins\.com\.cn(:[0-9]+)?(/.*)?$ be_edge_http:sit:jenkins-edge

Edge 类型 route 的 HAProxy 后端:

backend be_edge_http:sit:jenkins-edge
  mode http
  option redispatch
  option forwardfor
  balance leastconn

  timeout check 5000ms
  .....
  server pod:jenkins-1-bqhfj:jenkins:10.128.2.15:8080 10.128.2.15:8080 cookie 71c6bd03732fa7da2f1b497b1e4c7993 weight 256 check inter 5000ms
  server pod:jenkins-1-h3fff:jenkins:10.131.0.10:8080 10.131.0.10:8080 cookie fa8d7fb72a46958a7add1406e6d26cc8 weight 256 check inter 5000ms

Re-encrypt 类型 route 的 HAProxy 后端:

-

    http-request set-header X-Forwarded-Host %[req.hdr(host)]
    http-request set-header X-Forwarded-Port %[dst_port]
    http-request set-header X-Forwarded-Proto http if !{ ssl_fc }
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    http-request set-header X-Forwarded-Proto-Version h3 if { ssl_fc_alpn -i h3 }

  server pod:jenkins-1-bqhfj:jenkins:10.128.2.15:8080 10.128.2.15:8080 cookie ... weight 256 ssl verifyhost jenkins.sit.svc verify required ca-file /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt check inter 5000ms #与后端的链路采用 ssl 加密,并且要检查hostname
  server pod:jenkins-1-h3fff:jenkins:10.131.0.10:8080 10.131.0.10:8080 cookie ... weight 256 ssl verifyhost jenkins.sit.svc verify required ca-file /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt check inter 5000ms

这里可以看出来重新使用密钥对连接进行加密,但是不知道为何 mode 依然是 http,而不是 https。

 2.6 设置和修改 route 配置

route 配置主要有以下几个比较重要的:

(1)SSL 终结方式。共三种:

设置:

(2)负载均衡策略。也有三种:

设置:

 举例:

2.7 一个 route 将流量分给多个后端服务

该功能常用于一些开发测试流程,比如做A/B 测试。

在下面的配置中,有一个应用三个版本的部署,前端一个 route,各服务使用不同的权重。

理解OpenShift(1):网络之 Router 和 Route

下面是 HAProxy 配置文件中的 backend 配置,采用 roundrobin 负载均衡模式:

理解OpenShift(1):网络之 Router 和 Route

3. OpenShift router 服务如何实现高可用?

OpenShift router 服务支持两种高可用模式。

3.1 单 router 服务多副本,并利用和DNS/LB 实现高可用

这种模式只部署一个 router 服务,它支持集群的所有对外暴露的服务。要实现HA,需要设置副本数(replicas)大于1,使得会在超过一台服务器上创建pod,然后再通过DNS轮询或者四层负载均衡。 

理解OpenShift(1):网络之 Router 和 Route

因为 router/pod 中的 HAProxy 要实现本地配置文件,因此实际上它们是有状态容器。OpenShift 采用 etcd 作为配置的统一存储,openshift-router 进程应该是采取某种机制(被通知或定时拉取)从 etcd 中获取 router 和 route 的配置,然后再修改本地的配置文件,再重启 HAPorxy 进程来应用新修改了的配置文件。 要深入了解这里面的工作原理,可以去看源代码。

3.2 多 router 服务通过分片(sharding)实现高可用

这种模式下,管理员需要创建和部署多个 router 服务,每个router 服务支持一个或几个 project/namespace。router 和 project/namespace 之间的映射使用标签(label)来实现。具体的配置请参考官网 https://docs.openshift.com/container-platform/3.11/install_config/router/default_haproxy_router.html。实际上,和一些产品(比如mysql,memedcache)的分片功能类似,该功能更多地是为了解决性能问题,而无法完全解决高可用问题。

理解OpenShift(1):网络之 Router 和 Route

4. 常见问题如何排查?

从上面的分析可以看出,要使得 router 和 route 都正常工作,至少要确保以下几个环节都是没问题的:

  1. 客户端使用 route 中配置的域名和端口来访问服务。

  2. DNS 能将域名解析到目标 router 所在的服务器(在使用分片配置时比较复杂,尤其需要注意)。

  3. 如有采用另外的四层负载均衡器的话,它得配置正确、工作正常。

  4. HAProxy 能通过域名匹配到正确的backend。

  5. router 和 route 的配置被正确地反映到了 HAProxy 的配置文件中了。

  6. HAProxy 进程重启了,从而读取了新修改的配置文件。

  7. 后端 pod 列表正确,并且至少有一个 pod 正常工作。

如果您看到如下的错误页面,则说明上面的第3到7点至少有一处不能正常功能。此时,进行有针对性的排查即可。

理解OpenShift(1):网络之 Router 和 Route

 

感谢您的阅读,欢迎关注我的微信公众号:

理解OpenShift(1):网络之 Router 和 Route


推荐阅读:
  1. OpenShift 4预览
  2. OSPF网络出现Router ID重复导致网络故障的解决方法

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

openshift 网络路由 原理

上一篇:部署Lync Server DNS负载平衡

下一篇:针对敲诈病毒(WanaCrypt0r2.0)的应对方案

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》