OpenShift 虚拟化: 外部访问OpenShift虚拟机的几种方法
1 | 作者:李晓辉 |
OpenShift里有好几种服务资源类型,能搞定外部访问的事儿。
- NodePort:这玩意儿会在集群里所有节点上暴露一个网络端口,然后把进来的流量转发到服务对应的容器或者虚拟机。不过,用NodePort得允许直接连到集群节点的网络,这可有点安全隐患。
- LoadBalancer:这资源类型能指示OpenShift在云环境里搞个负载均衡器。负载均衡器会让OpenShift和集群运行的云提供商打交道,搞定一个负载均衡器,然后给应用提供一个能从外部访问的IP地址。
- 对于不在云提供商上跑的集群,MetalLB操作符就能提供负载均衡服务。后面也会讲怎么配置MetalLB负载均衡器服务。
- 非云环境里,还能通过LoadBalancer服务类型配置一个外部IP,把流量发到服务上。不过,外部IP功能默认是关着的,也存在安全风险,因为那些原本在集群里、要发给外部资源的敏感流量,可能会被截胡。
- Ingress Controller:这可是让外部能访问集群资源的常用方法。Ingress操作符管着Ingress控制器,它主要处理HTTP、HTTPS和TLS(用SNI实现)的流量,配置好之后,就能接收外部请求,然后根据设置的路由把请求转发过去。
OpenShift提供的路由资源,能让你的应用被集群外的网络访问到。路由能让HTTP、HTTPS流量,TCP应用,还有非TCP流量进来。有了路由,你可以用一个公开可访问的独特域名来访问应用。
Kubernetes也有类似路由资源的入口资源,不过路由功能更多,比如:
- TLS重新加密
- TLS直通
- 蓝绿部署的流量分割
要是你把虚拟机从别的虚拟化技术迁移到OpenShift虚拟化,你可以配置外部访问,让客户还能像以前一样访问应用。你也可以让数据库服务器被集群外运行的服务访问到。要是有些老应用你打算以后转成容器,也可以先暴露出来。等应用转成容器之后,你再重新配置外部访问,让客户能用原来的DNS名字继续访问应用。
配置OpenShift Routes
配置OpenShift路由也很简单。OpenShift路由能让HTTP、HTTPS和TLS流量进入集群里的服务。路由把一个面向公网的DNS主机名和一个面向内部的服务IP连接起来。
OpenShift是通过部署一个集群范围的路由器服务来实现路由的,这个路由器服务在OpenShift集群里以容器化应用的形式运行一个HAProxy负载均衡器。OpenShift像处理其他应用一样,对路由器Pod进行扩展和复制。
当你在OpenShift里创建一个路由的时候,它能自动给你的应用分配一个DNS条目。具体来说,OpenShift会给路由分配一个名字,格式是routename-namespace.default_domain
。这里的default_domain
是在集群安装的时候,由OpenShift管理员设置好的基础域名。举个例子,假设你的默认域名是apps.mycompany.com
,然后你在prod项目里创建了一个叫intranet
的路由,那分配到的DNS名字就是intranet-prod.apps.mycompany.com
。
不过,OpenShift管理员还得搞定一件事,就是得配置公司的DNS系统,让default_domain
对应的通配符DNS记录指向运行路由器的节点的公网IP地址。
注意一下哦,托管通配符域名的DNS服务器其实并不知道路由主机名是个啥。它只是简单地把任何名字解析到配置好的IP地址上。真正了解路由主机名的只有OpenShift路由器,它把每个主机名当做一个HTTP虚拟主机来处理。要是有无效的通配符域名主机名,和任何路由都不匹配的话,OpenShift路由器就会拦截这些请求,并且返回一个HTTP错误。
另外,路由只支持特定类型的流量,就是HTTP、支持服务器名称指示(SNI)的HTTPS,还有支持SNI的TLS。有了SNI,客户端在握手过程中就能以明文形式发送它要访问的主机名。OpenShift就是利用这个特性,在收到加密流量的时候,确定要转发到哪个服务。
要是你有其他类型的流量,比如UDP流量或者非Web的TCP流量,Red Hat建议你用LoadBalancer或者NodePort类型的服务来处理。
创建路由
首先,当你创建了一个ClusterIP类型的服务,让它指向你的容器或者虚拟机之后,就可以为你的应用创建路由了。虽然你可以用YAML或者JSON格式的资源文件来声明路由,但OpenShift提供了一个很方便的命令“oc expose service”,能简化这个创建过程。
比如,你可以这样创建一个路由:
1 | [lixiaohui@host ~]$ oc expose service/web |
这条命令会创建一个和你的服务同名的路由资源。如果你想要给路由起个不一样的名字,可以用“–name”选项来定义。
OpenShift会自动给路由分配一个DNS名字。如果你想手动定义DNS名字,可以用“–hostname”选项,后面跟着你想要的DNS名字。比如,下面这条命令会创建一个定义了web-production.apps.mycompany.com主机名的web路由:
1 | [lixiaohui@host ~]$ oc expose service/web --name web \ |
要是你想查看分配给路由的DNS名字,可以用“oc get route”命令:
1 | [lixiaohui@host ~]$ oc get route web |
从Web控制台里也可以创建路由哦。你只需要进入“Networking → Routes”,选择一个命名空间,点击“Create Route”,然后把路由的详细信息填到表单里。你得给路由起个名字,还得选择关联的服务及其端口。
创建基于路径的路由
OpenShift的路由资源定义接受path
变量,用来指定URL的路径部分。有了这个配置,你就可以用同一个DNS名字为多个服务提供服务,并且根据路径部分来转发流量。比如,你可以用http://intranet-prod.apps.mycompany.com/static
这个URL,把流量转发到提供静态网页内容的容器或者虚拟机上。对于REST API请求,你可以用http://intranet-prod.apps.mycompany.com/api
这个URL,把流量转发到应用的后端。
在使用oc expose service
命令的时候,加上--path
选项就可以配置基于路径的路由了。比如:
1 | [lixiaohui@host ~]$ oc expose service/static --path=/static \ |
你可以用oc get routes
命令来查看路由的信息:
1 | [lixiaohui@host ~]$ oc get routes |
加密路由
路由可以是加密的(TLS或HTTPS),也可以是未加密的(HTTP)。加密路由使用几种类型的TLS终止来向客户端提供证书。
加密路由会指定路由的TLS终止类型。下面这个列表描述了可用的终止类型:
- Edge:TLS终止发生在路由器处,然后OpenShift才把流量路由到容器或者虚拟机。路由器向客户端提供TLS证书。你在创建路由的时候可以提供自己的证书,或者让OpenShift使用它的证书。因为TLS是在路由器处终止的,所以路由器到端点之间的内部网络连接是没有加密的。
- Pass through:路由器直接把流量发送到目标容器或者虚拟机。在这种模式下,应用本身负责为流量提供证书。
- Re-encryption:这是Edge终止的一个变种。路由器用一个证书终止TLS,然后重新加密它和端点之间的连接,端点可能有不同的证书。因此,整个连接路径都是加密的,即使是在内部网络上也是如此。
创建加密路由
当你使用Web控制台创建路由的时候,创建路由的表单里会有一个安全部分,用来配置加密路由。表单上显示的字段会根据你选择的TLS终止类型而改变。当你选择Edge终止的时候,就会显示下面这个表单:
在Web控制台的创建路由表单里,有“Browse…”按钮,可以用它来选择证书和私钥。如果没提供证书和私钥,OpenShift就会用内部证书颁发机构(CA)的证书和私钥。表单里的“不安全流量”字段用来设置OpenShift管理不安全流量(比如HTTP)的策略。下面这个表格列出了这个字段可以选择的值:
值 | 含义 |
---|---|
None | 禁用未加密流量 |
Allow | 通过不安全的协议(比如HTTP)发送未加密流量 |
Redirect | 将不安全的协议(HTTP)重定向到安全的协议(HTTPS) |
表单在处理TLS直通和TLS重新加密时,这些字段会有一些细微的变化。
从命令行来说,oc expose
命令只能创建未加密的路由。要是想创建加密路由,就得用oc create route
命令。下面这个例子用web服务创建了一个使用Edge加密、名字相同的路由:
1 | [lixiaohui@host ~]$ oc create route edge \ |
在这个例子中,OpenShift入口控制器会提供内部CA的证书。如果你想提供自定义的私钥和签名证书,那么可以用--key
和--cert
选项来提供这些内容。
为虚拟机配置路由
要为虚拟机配置路由,你得先为虚拟机的virt-launcher
Pod创建一个服务:
- 在
.spec.template.metadata.labels
路径处给虚拟机资源添加一个标签。 - 从YAML格式的定义文件创建服务资源。用标签来选择
virt-launcher
Pod。下面这个例子假设virt-launcher
Pod有一个tier: front
标签。
1 | apiVersion: v1 |
创建好服务之后,你就可以创建路由了。
从命令行来说,用oc expose service
命令来创建路由:
1 | [lixiaohui@host ~]$ oc expose service/web |
启用来自路由器Pod的流量
当你在项目里使用网络策略的时候,你得添加一条规则来启用来自路由器Pod的流量。不然的话,路由资源就不管用了,因为路由器Pod没法到达目标Pod和虚拟机。
路由器Pod运行在openshift-ingress
命名空间里。这个命名空间已经有一个标签,你可以用它来配合你的网络策略。下面这条命令显示了标签是network.openshift.io/policy-group: ingress
:
1 | [lixiaohui@host ~]$ oc get namespace openshift-ingress -o yaml |
给你的项目添加下面这个网络策略资源,来启用来自路由器Pod的流量:
1 | kind: NetworkPolicy |
- 网络策略启用了来自
openshift-ingress
命名空间的流量,因为这个命名空间有network.openshift.io/policy-group: ingress
标签。 - 当
podSelector
参数为空时,网络策略针对当前命名空间里的所有Pod。
配置Kubernetes入口资源
路由资源是OpenShift特有的。Kubernetes提供了入口资源,有一些和路由相似的功能。不过,有些路由功能,比如TLS重新加密,在入口资源里是不可用的。
下面这个例子定义了一个名为web的入口资源:
1 | apiVersion: networking.k8s.io/v1 |
host
参数提供了要分配给应用的URL。path
参数提供了URL的路径部分。pathType
参数指定了如何匹配URL的路径部分。如果设置为Exact
,那么路径必须和path
参数完全一致。如果设置为Prefix
,那么任何以路径部分开头的路径都匹配。service
部分提供了要和入口资源关联的服务。
OpenShift用路由资源来实现入口资源。下面这个例子显示了OpenShift创建的路由资源:
1 | [lixiaohui@host ~]$ oc get ingress |
从Web控制台创建入口资源的话,进入“Networking → Ingresses”,点击“Create Ingress”,然后用入口参数完成YAML清单。