目录
文章目录
- 目录
- Kubernetes to Contrail Object Mapping
- K8s Namespace mapping to TF Shared or single project(multi-tenancy,多租户增强)
- K8s Pod mapping to TF VRF Virtual Interface IP(network isolation,网络隔离增强)
- K8s Service mapping to TF ECMP-based native LoadBalancer(load-balancing,负载均衡增强)
- K8s Ingress mapping to TF HAProxy L7 LoadBalancer(外部网络接入增强)
- K8s Network Policy mapping to TF Security group(micro-segmentation)
Kubernetes to Contrail Object Mapping
contrail-kube-manager 会 Watch 这些 K8s resource 的变更,并转发到 TF API 请求。
K8s Namespace mapping to TF Shared or single project(multi-tenancy,多租户增强)
K8s Namespace 可以映射到 TF Shared Project 或 TF Single Project。
-
K8s Namespace mapping to TF Shared Project(TF Single Tenant,单租户集成模式):TF 对应 K8s Cluster 只有一个 Tenant。K8s Namespace 映射为 TF VN。
-
K8s Namespace mapping to TF Single Project(TF Multi Tenant,多租户集成模式):TF 对应 K8s Cluster 有多个 Tenants。K8s Namespace 映射为 TF Project。
K8s Namespace mapping to TF Shared Project
可以通过修改 kube-manager 的配置文件 /etc/contrail/contrail-kubernetes.conf 中的配置项 [KUBERNETES].cluster_project 来指定实施 “单租户集成模式”。例如:
[KUBERNETES]
cluster_project = {'domain': 'default-domain', 'project': 'kubernetes'}
...
单租户集成模式中,所有的 non-Isolated network 都会共享默认的 cluster-network VN VRF;所有的 Isolated network 都具有独立的 VN VRF。
K8s Namespace mapping to TF Single Project
默认的,contrail-ansible-deployer 会实施 “多租户集成模式”。初始状态下,存在 5 个 TF Projects 对应 5 个 K8s Namespaces。之后再新建一个 K8s Namespace 就会同时创建一个 TF Project。
每个对应 K8s Namespace 的 TF Project 下都包含了 2 个 VNs:k8s-{vn_name}-service-network 和 k8s-{vn_name}-pod-network,并且绑定了相应的 IPAM 和 Network Policies。分别用于 Pod 和 Service 资源。
默认情况下,除了 k8s-{vn_name}-pod-network 之外,其他的 VN 是无法连接到 k8s-{vn_name}-service-network 的,这由 TF Network Policy 来进行控制。
k8s-default Project 存放了大量可以被 Shared 的资源,例如:IPAM、Network Policy、Security group 等等。
- 3 个 TF IPAM:k8s-pod-ipam、k8s-service-ipam 和 k8s-ip-fabric-ipam,分别作为 K8s Pods、Services、Underlay(IP Fabric)的 Subnet IP Pool。
- 3 条 Network Policies:k8s-default-service-np、k8s-default-ip-fabric-np 和 k8s-default-pod-service-np。
- k8s-default-service-np 允许指定的 VN 可以访问 K8s service VN。
- k8s-default-pod-service-np 允许指定的 Pod VN 可以访问 K8s service VN。
- k8s-default-ip-fabric-np 允许指定的 VN 可以访问 K8s underlay(IP Fabric)VN。
- 1 条 Security Group:允许 Pod VIF 的所有 Ingress/Egress 流量。
K8s Pod mapping to TF VRF Virtual Interface IP(network isolation,网络隔离增强)
创建一个 K8s Pod 就会在相应的 TF VN 中创建一个 VIF,并挂载到 Pod 所处的 Linux Network Namespace。
Kubernetes 的基本网络模型是一个扁平的网络(Flat networking),通过 K8s Network policy 来提供 Pod-to-Pod 的安全访问控制。但 K8s Flat networking 并没有实现真正的多租户隔离,这意味着任何 Namespace 中的 Pod 都可以与任何 Other Namespace 中的 Pods 进行通信。换句话说,如果 Target Pod 的 Domain Name 或 IP address 已知,则无法阻止从一个 Namespace 中的 Pod 到 Other Namespace 中的 Pods 的通信。
可见,Kubernetes 的基本网络模型并不适用于对安全隔离性要求高的场景。针对这一需求,TF 除了为 K8s 提供 CNI 标准强制要求的 Flat Networking(Non-Isolated 网络模型)之外,还为 K8s 提供了 Network isolation 网络增强功能。
Default Mode(Non-Isolated Namespaces)
为了保持 K8s 基本的 Flat Networking(扁平网络)模型,TF 默认提供了 Non-Isolated Namespaces(非隔离命名空间)模式。
TF 为 K8s Cluster 预配置了 2 个 Default VN(虚拟网络):k8s-default-pod-network 和 k8s-default-service-network。它们分别为所有 Non-Isolated Namespaces 中的 Pods 或 Services 提供网络。使得所有的 Non-Isolated Namespaces 中的 Pods 或 Services 处于一个扁平的网络中的(包括 Default Namespace),可以跨越不同的 Namespace 互联互通。
从 TF 的角度看,这些 Non-Isolated Namespaces 对应的 Projects 共享了 2 个 Public VRF:
- k8s-default-pod-network: the pod virtual network/VRF table, with the default subnet 10.32.0.0/12
- k8s-default-service-network: the service virtual network /VRF table, with a default subnet 10.96.0.0/12
也就是说,当你新建一个(默认)Non-Isolated Namespace 时,TF 会自动为该 Project 授权这 2 个 Default VN/VRF。
NOTE:无论是 Non-Isolated Namespace 还是 Isolated Namespace 中,每个 TF virtual network 都具有独立的 VRF,所以两个不同的 virtual network 需要互通时,依旧需要配置相应的 Network Policy。例如:k8s-default-pod-network 和 k8s-default-service-network 之间就是通过 Network Policy 来实现互通的。
NOTE:kube-system namespace 是一个特殊的 underlay 网络,不在 K8s Cluster 范围内,也就是说不属于 TF 管理。
Isolation Mode(Isolated Namespaces)
Isolated Namespace 拥有独立隔离的 Pod 和 Service VN/VRF。也就是说:
- Isolated Namespace 中的 Pod 只能与同一个 Namespace 中的其他 Pods 互通,无法访问 other Namespaces 中的 Pods,但可以访问 non-Isolated Namespaces 中的 Services。创建一个 Isolated Namespace 如下。
apiVersion: v1
kind: Namespace
metadata:
annotations:
"opencontrail.org/isolation" : "true" # The value of true indicates this is an isolated namespace.
name: ns-isolated
- Isolated Namespace 中的 Service(k8s service-ip)只能与同一个 Namespace 中的其他 Pods 互通,other Namespace 中的 Pods 无法访问 Isolated Namespace 中的 Service。根据需求,如果 Isolated Namespace 中的 Service 需要被 other Namespace 中的 Pods 访问到,则可以配置 disabling service isolation。此时 other Namespace 的 Pods 可以范围该 Service,同时 Isolated Namespace 中的 Pods 依旧是隔离的。
apiVersion: v1
kind: Namespace
metadata:
annotations:
"opencontrail.org/isolation" : "true" # The value of true indicates this is an isolated namespace.
"opencontrail.org/isolation.service": "false"
name: ns-isolated
从 YAML 可以看出,contrail-kube-manager 对 K8s resources 进行了扩展。新建一个 Namespace 时,contrail-kube-manager 会 Watch K8s API Server 并读取到 opencontrail.org/isolation 注释,然后根据 Namespace 的隔离类型来进行相应的处理。当 isolation 为 true,TF 就会使用相应的 VRF 来创建该 Namespace 映射的 Project。
举例说明:假设现在具有 3 个 Namespace: default、ns-non-isolated、ns-isolated,并在每个 Namespace 中创建了 VN vn-left-1。那么你将会看见以下 VNs/VRFs,它们的隔离关系如图所示。
-
default-domain:k8s-default:k8s-default-pod-network
-
default-domain:k8s-default:k8s-default-service-network
-
default-domain:k8s-default:k8s-vn-left-1-pod-network
-
default-domain:k8s-ns-non-isolated:k8s-vn-left-1-pod-network
-
default-domain:k8s-ns-isolated:k8s-ns-isolated-pod-network
-
default-domain:k8s-ns-isolated:k8s-ns-isolated-service-network
-
default-domain:k8s-ns-isolated:k8s-vn-left-1-pod-network
NOTE:Isolated Namespaces Mode 下,如果两个 Namespaces 需要互通时,则可以对 Namespace 下属的 VN 配置相应的 Network Policy。
Custom Isolation Mode
该模式中,用户可以通过修改 Application YAML annotations 来自定义自己的 Namespace 中所使用的 Virtual Network。例如:
annotations: {
"opencontrail.org/network" : '{"domain":"default-domain", "project": "k8s-default", "name":"k8s-blue-net-pod-network"}'
}
- 如果该 annotations 配置 Pod YAML 上,则指定 Pod 启动在指定 Namespace 的 Virtual network 上。
- 如果该 annotations 配置 Namespace YAML 上,则该 Namespace 中的所有 Pods 都启动在 Virtual network 上。
操作示例:验证路由隔离是否有效
- 新建 non-Isolated Namespace
$ cat ns-non-isolated.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ns-non-isolated
- 新建 Isolated Namespace
$ cat ns-isolated.yaml
apiVersion: v1
kind: Namespace
metadata:
annotations:
"opencontrail.org/isolation": "true"
name: ns-isolated
- 创建 Pods
$ kubectl apply -f pod-busybox.yaml -n default
$ kubectl apply -f pod-busybox.yaml -n ns-non-isolated
$ kubectl apply -f pod-busybox.yaml -n ns-isolated
$ kubectl get pods -A -o wide | grep busybox
default busybox 1/1 Running 0 39s 10.47.255.248 worker02
ns-isolated busybox 1/1 Running 0 3m38s 10.47.255.250 worker02
ns-non-isolated busybox 1/1 Running 0 2m5s 10.47.255.249 worker01
- 对比验证 Pods 之间的网络隔离性
# 验证 Isolated 和 non-Isolated 之间的隔离性
kubectl exec -it -n ns-isolated busybox -- ping 10.47.255.249
# 验证 Default 和 Isolated 之间的隔离性
kubectl exec -it -n default busybox -- ping 10.47.255.250
# 验证 Default 和 non-Isolated 之间的隔离性
kubectl exec -it -n default busybox -- ping 10.47.255.249
K8s Service mapping to TF ECMP-based native LoadBalancer(load-balancing,负载均衡增强)
K8s Service 支持以下 4 种模式,还支持使用 ExternalIP。
- ClusterIP
- NodePort
- LoadBalancer
- ExternalName
而 TF 则主要支持了其中必要的 2 种模式,以及 ExternalIP。
- TF ClusterIP
- TF LoadBalancer
TF ClusterIP Service
TF ClusterIP Service 通过 ECMP 和 NAT 技术,实现了在 Service 和 Pods 之间进行 L4 负载均衡转发。
TF Native Load Balancer
新建一个 K8s ClusterIP Service 时,TF 会从同步新建一个 TF Load Balancer,LB Provider Type 为 Native,底层实现为 vRouter ECMP。所以也称为 TF Native Load Balancer。
并且 TF 还会从相应的 Service VN 的 Subnet Pool 分配一个 IP 作为 LB VIP,也就是 ClusterIP。
TF Floating IP NAT
在有了 TF Native LB VIP 作为 Front-end IP 之后,还需要将流量转发到 Backend IPs(Pods),TF 使用 NAT 技术来实现这一功能,而不是引入一个重型的 HAProxy-like 负载均衡器。
同时,由于 TF Floating IP 本身就具有 NAT 的功能特性,所以就可以直接使用 TF Floating IP 来完成这项工作。
另外,由于 ClusterIP Service 只能在 K8s Cluster Internal 被访问,所以针对 ClusterIP Service 的 FIP 实际上是一个 Inter-FIP。直接从相应的 Service VN 中的 FIP Pool 分配的,而不需要从 Public VN 中分配。
使用示例
- 创建 ClusterIP Service。
$ cat nginx-deployment-clusterip-service.yaml
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: nginx-deployment-clusterip-service
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: nginx
replicas: 2 # tells deployment to run 1 pods matching the template
template: # create pods using pod definition in this template
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-deployment-clusterip-service
namespace: default
labels:
app: nginx
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
$ kubectl get pods -A -o wide | grep nginx
default nginx-56db997f77-9qxwd 1/1 Running 0 15m 10.47.255.246 worker01
default nginx-56db997f77-thpxd 1/1 Running 0 15m 10.47.255.247 worker02
$ kubectl describe service -n default nginx
Name: nginx
Namespace: default
Labels: app=nginx
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"nginx"},"name":"nginx","namespace":"default"},"spec":{"p...
Selector: app=nginx
Type: ClusterIP
IP: 10.97.137.130
Port: http 80/TCP
TargetPort: 80/TCP
Endpoints: 10.47.255.246:80,10.47.255.247:80
Session Affinity: None
Events: <none>
-
查看 ClusterIP Service 对应的 TF LB。
-
查看 TF LB 在 vRouter 上的 ECMP Routes。
-
查看 ClusterIP 的 FIP。
TF Loadbalancer Service
TF Loadbalancer Service 的实现方式是在 TF ClusterIP Service(Native LB + Inter-FIP NAT)的基础之上,再叠加了一个 External FIP NAT。因为 Loadbalancer Service 相对于 ClusterIP Sercice 而言,是提供给 External Network 访问的。
- ClusterIP Service as a Cluster Internal LB VIP
- Loadbalancer Service as a Cluster External Floating VIP
可见,对于 Loadbalancer Service 而言拥有 3 个关键 IP:
- TF Native LB IP:从 Service VN Subnet Pool 分配,作为内部 L3-4 负载均衡 VIP。
- Inter-FIP:从 Service VN FIP Pool 分配,作为内部 L3-4 NAT Front-end IP。
- Ext-FIP:从 Public VN FIP Pool(Namespace FIP Pool 或 Global FIP Pool)分配,作为外部 L3-4 NAT Front-end IP。
相对的,Loadbalancer Service 中也存在着 2 种类型的 ECMP:
- Internal ECMP:Cluster IP 和 Pod IPs 之间的 ECMP
- External ECMP:External VIP 和 Cluster IPs(跨节点)之间的 ECMP。
使用示例
- 新建 Loadbalancer Service
$ vi service-web-lb.yaml
apiVersion: v1
kind: Service
metadata:
name: service-web-lb
spec:
ports:
- port: 8888
targetPort: 80 selector:
app: webserver
type: LoadBalancer
NodePort Service
在 TF 中的 Kubernetes NodePort Service 应用了 kube-proxy iptables NAT 技术、以及 TF InstanceIP 和 FloatingIP 资源来共同实现。
使用示例
- 创建 Nginx Deployment NodePort Service。
$ cat nginx-deployment-nodeport-service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-nodeport-service
labels:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
name: nginx
template:
metadata:
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
#nodeSelector:
# stage: node01
---
apiVersion: v1
kind: Service
metadata:
name: nginx-deployment-nodeport-service
labels:
name: nginx
spec:
type: NodePort
ports:
- port: 80
nodePort: 30080
name: http
selector:
name: nginx
$ kubectl apply -f nginx-deployment-nodeport-service.yaml
$ kubectl get pods -A -o wide | grep nodeport
default nginx-deployment-nodeport-service-65d6b7bddb-6kbl2 1/1 Running 0 6h15m 10.1.255.247 tf-node03 <none> <none>
default nginx-deployment-nodeport-service-65d6b7bddb-gp4vj 1/1 Running 0 6h15m 10.1.255.245 tf-node02 <none> <none>
default nginx-deployment-nodeport-service-65d6b7bddb-vgwpm 1/1 Running 0 6h15m 10.1.255.243 tf-node03 <none> <none>
$ kubectl describe service -n default nginx-deployment-nodeport-service
Name: nginx-deployment-nodeport-service
Namespace: default
Labels: name=nginx
Annotations: <none>
Selector: name=nginx
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.2.231.37
IPs: 10.2.231.37
Port: http 80/TCP
TargetPort: 80/TCP
NodePort: http 30080/TCP
Endpoints: 10.1.255.243:80,10.1.255.245:80,10.1.255.247:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
# Worker nodes: 172.27.10.73, 172.27.10.74, 172.27.10.75
$ curl http://172.27.10.73:30080
10.1.255.243
$ curl http://172.27.10.73:30080
10.1.255.245
$ curl http://172.27.10.73:30080
10.1.255.247
查看 NodePod Service 对应的 LB。
查看 ClusterIP 的 FIP。
查看 Host Port:
$ netstat -lpntu | grep 30080
tcp 0 0 0.0.0.0:30080 0.0.0.0:* LISTEN 6310/kube-proxy
查看 iptables chain KUBE-NODEPORTS,下属引用了其他的 Chains。
$ sudo iptables -L KUBE-NODEPORTS -t nat
Chain KUBE-NODEPORTS (1 references)
target prot opt source destination
KUBE-MARK-MASQ tcp -- anywhere anywhere /* default/nginx-deployment-nodeport-service:http */ tcp dpt:30080
KUBE-SVC-TWBRQQHIV3GNZRU4 tcp -- anywhere anywhere /* default/nginx-deployment-nodeport-service:http */ tcp dpt:30080
进入 Node Port 30080 的每个 Pkts 首先由 chain KUBE-MARK-MASQ 处理,使用 0x4000 值来标记这些 Pkts。
$ sudo iptables -L KUBE-MARK-MASQ -t nat
Chain KUBE-MARK-MASQ (20 references)
target prot opt source destination
MARK all -- anywhere anywhere MARK or 0x4000
接下来,Pkts 由 chain KUBE-SVC-TWBRQQHIV3GNZRU4 处理,下属也引用了其他的 Chains。
$ sudo iptables -L KUBE-SVC-Y4TE457BRBWMNDKG -t nat
target prot opt source destination
KUBE-SEP-GX7FJQIAKFPMFOOV all -- anywhere anywhere /* default/nginx-deployment-nodeport-service:http */ statistic mode random probability 0.33333333349
KUBE-SEP-FWPUFLMRYQKKP7DT all -- anywhere anywhere /* default/nginx-deployment-nodeport-service:http */ statistic mode random probability 0.50000000000
KUBE-SEP-5EOKRARXQQFDAN7G all -- anywhere anywhere /* default/nginx-deployment-nodeport-service:http */
检查 chain KUBE-SEP-GX7FJQIAKFPMFOOV,查看它们是否定义了指向后端 Pods 之一的路由。
$ sudo iptables -L KUBE-SEP-GX7FJQIAKFPMFOOV -t nat
Chain KUBE-SEP-GX7FJQIAKFPMFOOV (1 references)
target prot opt source destination
KUBE-MARK-MASQ all -- 10.1.255.243 anywhere /* default/nginx-deployment-nodeport-service:http */
DNAT tcp -- anywhere anywhere /* default/nginx-deployment-nodeport-service:http */ tcp to:10.1.255.243:80
$ sudo iptables -L KUBE-SEP-FWPUFLMRYQKKP7DT -t nat
Chain KUBE-SEP-FWPUFLMRYQKKP7DT (1 references)
target prot opt source destination
KUBE-MARK-MASQ all -- 10.1.255.245 anywhere /* default/nginx-deployment-nodeport-service:http */
DNAT tcp -- anywhere anywhere /* default/nginx-deployment-nodeport-service:http */ tcp to:10.1.255.245:80
$ sudo iptables -L KUBE-SEP-5EOKRARXQQFDAN7G -t nat
Chain KUBE-SEP-5EOKRARXQQFDAN7G (1 references)
target prot opt source destination
KUBE-MARK-MASQ all -- 10.1.255.247 anywhere /* default/nginx-deployment-nodeport-service:http */
DNAT tcp -- anywhere anywhere /* default/nginx-deployment-nodeport-service:http */ tcp to:10.1.255.247:80
K8s Ingress mapping to TF HAProxy L7 LoadBalancer(外部网络接入增强)
TF 提供了基于 HAProxy 的 Ingress 实现,创建 K8s Ingress 就会创建一个 TF HAProxy LoadBalancer。
其中,由 contrail-svc-monitor 执行具体的 LBaaS 任务。contrail-svc-monitor 作为 TF 内部组件(e.g. Config Node)与外部组件(e.g. Loadbalancer Provider、OpenStack API)之间进行交互的桥梁。
K8s Network Policy mapping to TF Security group(micro-segmentation)
K8s Network Policy 在 TF 中通过 TF Security group 来实现,每新建一个 K8s Network Policy 就会创建一个 TF Security Group。
TF Security Group 可以通过限制 IP 5-tuple 等参数来管理任意 Pods 之间、以及 Pods 与 Service 之间的 ACL(访问控制)规则。TF Security Group 会被转化为具体的 TF Firewall Rules。K8s Network Policy 默认 Whitelist Rules 为 Allow all,TF Security group 也同样一条 Allow all traffic 的 TF Firewall Rules。