写在前面
- 参加考试,分享一些学习
OpenShift
的笔记 - 博文内容为
OpenShift
网络相关组件Service、Routes
很浅的一些认识 - 学习环境为 openshift v3 的版本,有些旧
- 这里如果专门学习 openshift ,建议学习 v4 版本
- 理解不足小伙伴帮忙指正
傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。--------王小波
软件定义网络(SDN)
SDN 即软件定义网络,一种网络架构理念,倡导网络架构与底层基础架构分离,简单讲,SDN 即使用软件方式实现传统硬件交换机和路由器完成的工作,在物理网络上实现多个虚拟的网络。
当前容器平台常用的软件定义网络解决方案或组件有开源的 Weave Net
、 flannel
、 Calico
及 Open vSwitch
。
不同软件定义网络的解决方案或组件各有特点,如 Weave 、 flannel 及 Calico 配置比较简单,功能比较基础 。 Open vSwitch 比较成熟且功能强大,配置起来相对比较复杂
容器网络
默认 docker 使用虚拟网桥,同一个主机上所有容器都连接到该网桥,这些容器利用 Linux namesacp 技术,创建了一对 虚拟网卡,一端在容器内,一端在网桥,这对虚拟网卡类似一个通道一样,两端可以直接通信,同时这些容器只能与同一台主机上的其他容器通信,无法与其他主机上容器通信。
以前 容器跨主机通信中
解决方法,Host 模式
和 端口绑定
的方式都有一定的局限的,通过 SDN 定义专门的容器网络,使网络架构更加灵活,更适用于云计算数据中心的要求.
Host模式
容器直接使用宿主机的网络,这样天生就可以支持跨主机通信。这种方式虽然可以解决跨主机通信问题,但应用场景很有限,容易出现端口冲突,也无法做到隔离网络环境
,一个容器崩溃很可能引起整个宿主机的崩溃。
端口绑定
通过绑定容器端口到宿主机端口,跨主机通信时使用“主机IP+端口的方式访问容器中的服务。显然,这种方式 仅能支持网络栈的4层及以上的应用
,·并且容器与宿主机紧耦合,很难灵活地处理问题,可扩展性不佳。
定义容器网络
使用 Open vSwitch 或 Flannel/Calico 等第三方SDN工具,为容器构建可以跨主机通信的网络环境。这类方案一般要求各个主机上的 Dockero 网桥的 cidr 不同,以避免出现IP冲突的问题,限制容器在宿主机上可获取的IP范围。并且在容器需要对集群外提供服务时,需要比较复杂的配置,对部署实施人员的网络技能要求比较高。
OpenShift 容器网络
OpenShift 3.9 版本使用 Open vSwitch
构建和维护 OpenShift 网络。 基于 Open vSwitch ,OpenShift 提供了三种不同网络方案:
ovs-subnet
插件,默认插件,提供一个 flat 网络,该网络中所有 pod 和 service 可以互相访问。ovs-multitenant
插件,用于隔离 pods 和 service ,每个 project 都会分配一个唯一的虚拟网络 ID(VNID),每个项目中的 pod 都无法与其他项目中 pod 通信。VNID 为 0 的项目中 pod 可以与其他项目中所有 pod 通信,default 项目的 VNID 是 0。ovs-networkpolicy
插件,支持管理员使用 NetworkPolicy 对象定义自己的隔离策略。
默认 master
是不允许通过集群网络访问容器,除非 master
节点同时配置为 nodes
节点。
在 OKD 默认安装环境中,每个 pod 都会获得唯一 ip 地址。一个 pod 中所有容器,就像在同一个主机上。每个 pod 分配一个 ip 意味着,可以把每个 pod 看做是一个物理机或者虚拟机。
OpenShift Service
service 是 Kubernetes 中一个核心的对象,通过 kube-proxy
或者 Ingress
为多个 pods 提供前端负载均衡。service 提供一个稳定的 IP 地址,与后端的多个 pods 通信,而客户端不需要跟踪各个 pod IP 地址。只需要知道 SVC 的地址或者 服务向外发布的地址即可。
Kubernetes 中的 Service 解决的问题
- Pod 的 IP 地址是不可靠的,当 Pod 所在的 Node 发生故障时,Pod 将被 Kubernetes 重新调度到另一个 Node,Pod 的 IP 地址将发生变化。无法被跟踪,
- 如果容器应用本身是分布式的部署方式,做水平扩展,通过多个实例共同提供服务,需要在这些实例的前端设置一个负载均衡器来实现请求的分发。
下面的配置为一个 Service 的核心部分,这里为了方便,我们使用 json 的格式展示
┌──[root@vms16.liruilongs.github.io]-[~]
└─$oc get svc hello-openshift -o json | jq .spec
{
"clusterIP": "172.30.169.91",
"ports": [
{
"name": "8080-tcp",
"port": 8080,
"protocol": "TCP",
"targetPort": 8080
},
{
"name": "8888-tcp",
"port": 8888,
"protocol": "TCP",
"targetPort": 8888
}
],
"selector": {
"app": "hello-openshift",
"deploymentconfig": "hello-openshift"
},
"sessionAffinity": "None",
"type": "ClusterIP"
}
具体的属性我们来了解下
clusterIP
: 指定当前服务发布的 IP ,这个 IP 是作为 负载均衡的 入口地址ports
: 为服务发布的端口号,这里的端口 是 Service 提供能力的具体端口,对应 Pod 暴露的 端口,可以看到这是一个多端口的 Service
┌──[root@vms16.liruilongs.github.io]-[~]
└─$oc get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-openshift ClusterIP 172.30.169.91 <none> 8080/TCP,8888/TCP 11h
┌──[root@vms16.liruilongs.github.io]-[~]
└─$
selector
: 选择器,K8s 通过标签的方式来选择对应的 后端能力提供者, 可以选择deployment,replicaset,pod,replicationcontrollerd
等。选择后会自动创建对应的Endpoint
┌──[root@vms16.liruilongs.github.io]-[~]
└─$oc get svc hello-openshift --show-labels
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE LABELS
hello-openshift ClusterIP 172.30.169.91 <none> 8080/TCP,8888/TCP 15h app=hello-openshift
┌──[root@vms16.liruilongs.github.io]-[~]
└─$oc get pods --selector=app=hello-openshift
NAME READY STATUS RESTARTS AGE
hello-openshift-1-j46gc 1/1 Running 0 15h
sessionAffinity
: 负载分发策略, 目前 K8s 提供了两个负载分发策略:RoundRobin(轮询)
和SessionAffinity(基于客户端IP进行会话保持)
, 在默认情况下,Kubernetes 采用RoundRobin
轮询模式对客户端请求进行负载分发,可以通过设置service.spec.sessionAffinity=ClientIP
来启用 SessionAffinity 策略。还有最后一个type
.
type
用于定义发布的服务类型,默认为 ClusterIP
ClusterIP
:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问NodePort
:通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求<NodeIP>:<NodePort>
,可以从集群的外部访问一个 NodePort 服务。Kubernetes master 将从给定的配置范围内(默认:30000-32767)分配端口,每个 Node 将从该端口(每个 Node 上的同一端口)代理到 Service。该端口将通过 Service 的 spec.ports[*].nodePort 字段被指定。LoadBalancer
:外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。使用支持外部负载均衡器的云提供商的服务,设置 type 的值为"LoadBalancer",将为 Service 提供负载均衡器。
关于 Service 的创建这里不做分享, OKD 中,大多数情况下会自动创建对应的 Service 资源对象。
OpenShift Routes
Router
是 OKD
所特有的,在 K8s 体系中,没有对应的API资源,包括上面我们谈到的 DC(DeploymentConfig)、IS
等。
Route 由共享的 router service
提供,以 实例方式方式运行在 pod 中,可以像普通 pod 一样水平扩展。
router service 是基于开源软件 HAProxy
,提供集群外客户端访问集群内 pod
。
[student@master ~]$ oc get route -o wide
NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD
docker-registry docker-registry-default.apps.lab.example.com docker-registry <all> passthrough None
registry-console registry-console-default.apps.lab.example.com registry-console <all> passthrough None
[student@master ~]$
route 连接公网 IP 和内部 service IP 地址 。为了提高性能和减少延迟,OpenShift 路由器直接连接 pod ,此时 service 仅仅提供查询 endpoints 功能
。管理员需要配置一个公网可以解析的主机名指向运行 route 的 node 公网 IP。典型地方式是使用 DNS wildcard 配置。
创建 Routes
yaml 文件方式创建
apiVersion: v1
kind: Route
metadata:
name: hello
spec:
host: hello.apps.lab.example.com
port:
targetPort: 8080-tcp #代表 svc 中某个 port 名称,svc 可以定义多个 port
to:
kind: Service
name: hello
直接通过命令行创建, 查看帮助文档
oc expose -h
oc expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|U
DP] [--target-port=number-or-name] [--name=name] [--external-ip=external-ip-of-s
ervice] [--type=type] [options]
一个Demo
oc expose service nginx --name www --hostname=www.apps.lab.example.com
以下是该命令及其选项的详细说明:
- oc:这是用于与 OpenShift 集群交互的命令行工具。
- expose:此子命令用于暴露服务。
- service nginx:这指定要暴露的服务的名称。在本例中,服务名为 nginx。
- –name www:这指定将用于暴露服务的路由的名称。在本例中,路由将被命名为 www。
- –hostname=www.apps.lab.example.com:这指定将用于路由的主机名。在本例中,主机名将为 www.apps.lab.example.com。
因此,当您运行此命令时,它将创建一个名为 www 的路由,其主机名为 www.apps.lab.example.com,将 nginx 服务暴露到 OpenShift 集群之外。
执行不带 --hostname
选项的 oc expose
命令创建的 routes 名称格式:
<route-name>-<project-name>.<default-domain>
- route-name 代表路由名或者参考资源名(对于 oc new-app 命令代表模板,对于 oc expose 命令代表 service)
- project-name 代表该资源所属 project 名
- default-domain 配置在 master 节点,匹配通配 DNS 域。
示例,test 项目中名称为 quote 的路由器,显示为:quote-test.cloudapps.example.com
查找默认 routing 子域
默认 routing 子域定义在 master 节点 /etc/origin/master/master-config.yaml
配置文件 routingConfig
块。
示例:
[root@master master]# cat master-config.yaml | grep -A 1 routingConfig
routingConfig:
subdomain: apps.lab.example.com
[root@master master]#
OpenShift HAProxy router
默认监听 80 和 443 端口,所以路由只能创建在那些 80 和 443 端口未使用的 node 上。否则只能更改路由监听端口,在路由部署配置文件中设置环境变量 ROUTER_SERVICE_HTTP_PORT
和 ROUTER_SERVICE_HTTPS_PORT
。
router 支持协议
- HTTP
- HTTPS with SNI
- WebSockets
- TLS with SNI
Routing 选择 和 类型
route
可以加密,也可以不加密。安全的 route
支持使用多种 TLS 加密。非安全的路由配置最简单,不需要 key 和证书
安全路由
指定路由 TLS termination
。可用的 TLS termination 类型如下:
Edge Termination
,流量到达 pod 前,在 router 上就终止了。TLS 证书由 router 提供,因此路由必须配置 TLS 证书,否则 TLS termination 使用路由默认证书。由于 TLS 是在 router 上终止的,所以 router 到 endpoints 之间内部网络是非加密的。Pass-through Termination
,加密的流量直接发送给目的 pod,不需要路由提供 TLS termination。不需要 key 和证书。目的 pod 提供证书。这也是当前唯一支持客户端证书的方法(双向认证)。Re-encryption Termination
,基于 edge termination,但是 route 与目的 pod之间通信会再次加密,可能会使用不同证书。所有路径都做了加密,包括内部网络。route 可以使用健康检查确定 host 认证。
创建安全 route
创建安全路由前,需要生产 TLS 证书。
示例,为名称是 test.apps.lab.example.com
路由创建自签名证书。
- 创建私钥。
openssl genrsa -out example.key 2048
- 使用私钥创建 certificate signing request(csr)。
openssl req -new -key example.key -out example.csr -subj "/C=US/ST=CA/L=LosAngeles/O=Example/OU=IT/CN=test.apps.lab.example.com"
- 使用 key 和 CSR 创建证书。
openssl x509 -req -days 366 -in example.csr -signkey example.key -out example.crt
- 创建路由
oc create route edge --service=test --hostname=test.apps.lab.example.com --key=example.key --cert=example.crt
访问加密路由 https://test.apps.lab.example.com
可以把证书相关的写成 shell
[root@master ~]# cat gencert.sh
#!/bin/bash
echo "Generating a private key..."
openssl genrsa -out $1.key 2048
echo
echo "Generating a CSR..."
openssl req -new -key $1.key -out $1.csr -subj "/C=US/ST=NC/L=Raleigh/O=RedHat/OU=RHT/CN=$1"
echo
echo "Generating a certificate..."
openssl x509 -req -days 366 -in $1.csr -signkey $1.key -out $1.crt
echo
echo "DONE."
echo
[root@master ~]#
Demo,创建一个支持 https 的路由
[root@master ~]# oc get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
greeter ClusterIP 172.30.106.99 <none> 8080/TCP,8888/TCP 6m
[root@master ~]# oc create route edge --service=greeter --hostname=greeter.apps.lab.example.com --key=greeter.apps.lab.example.com.key --cert=greeter.apps.lab.example.com.crt
route "greeter" created
[root@master ~]# oc get route
NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD
greeter greeter.apps.lab.example.com greeter 8080-tcp edge None
[root@master ~]# curl greeter.apps.lab.example.com
博文部分内容参考
© 文中涉及参考链接内容版权归原作者所有,如有侵权请告知,这是一个开源项目,如果你认可它,不要吝啬星星哦 😃
《OKD 3.9 DO280 Red Hat OpenShift Administration I》
《开源容器云OpenShift:构建基于Kubernetes的企业应用云平台》
https://docs.okd.io/latest/welcome/index.html
© 2018-2023 liruilonger@gmail.com, All rights reserved. 保持署名-非商用-相同方式共享(CC BY-NC-SA 4.0)