contrail-kube-manager 会 Watch 这些 K8s resource 的变更,并转发到 TF API 请求。
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。
可以通过修改 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。
默认的,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 等等。
创建一个 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 网络增强功能。
为了保持 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:
也就是说,当你新建一个(默认)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 管理。
Isolated Namespace 拥有独立隔离的 Pod 和 Service VN/VRF。也就是说:
apiVersion: v1
kind: Namespace
metadata:
annotations:
"opencontrail.org/isolation" : "true" # The value of true indicates this is an isolated namespace.
name: ns-isolated
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。
该模式中,用户可以通过修改 Application YAML annotations 来自定义自己的 Namespace 中所使用的 Virtual Network。例如:
annotations: {
"opencontrail.org/network" : '{"domain":"default-domain", "project": "k8s-default", "name":"k8s-blue-net-pod-network"}'
}
$ cat ns-non-isolated.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ns-non-isolated
$ cat ns-isolated.yaml
apiVersion: v1
kind: Namespace
metadata:
annotations:
"opencontrail.org/isolation": "true"
name: ns-isolated
$ 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
# 验证 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 支持以下 4 种模式,还支持使用 ExternalIP。
而 TF 则主要支持了其中必要的 2 种模式,以及 ExternalIP。
TF ClusterIP Service 通过 ECMP 和 NAT 技术,实现了在 Service 和 Pods 之间进行 L4 负载均衡转发。
新建一个 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 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 中分配。
$ 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: >
TF Loadbalancer Service 的实现方式是在 TF ClusterIP Service(Native LB + Inter-FIP NAT)的基础之上,再叠加了一个 External FIP NAT。因为 Loadbalancer Service 相对于 ClusterIP Sercice 而言,是提供给 External Network 访问的。
可见,对于 Loadbalancer Service 而言拥有 3 个关键 IP:
相对的,Loadbalancer Service 中也存在着 2 种类型的 ECMP:
$ 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 依赖原生的 kube-proxy iptables NAT 技术来实现,在 TF 的场景中,通常没必要使用到。
$ cat nginx-deployment-nodeport-service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-nodeport-service
labels:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
name: nginx
template:
metadata:
labels:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
---
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 get pods -A -o wide | grep nodeport
default nginx-deployment-nodeport-service-69f7cb4f44-pjm9r 1/1 Running 0 30s 10.47.255.247 worker02
$ kubectl describe service -n default nginx-deployment-nodeport-service
Name: nginx-deployment-nodeport-service
Namespace: default
Labels: name=nginx
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"name":"nginx"},"name":"nginx-deployment-nodeport-service","nam...
Selector: name=nginx
Type: NodePort
IP: 10.98.140.244
Port: http 80/TCP
TargetPort: 80/TCP
NodePort: http 30080/TCP
Endpoints: 10.47.255.247:80
Session Affinity: None
External Traffic Policy: Cluster
Events: >
# worker02
$ curl http://172.27.10.75:30080
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)之间进行交互的桥梁。
TF Security Group 可以通过限制 Protocol、Ports 等参数来管理任意 Pods 之间、以及 Pod 与 Service 之间的访问控制,当新建一个 K8s Network Policy 就会创建一个 TF Security Group。
TF Security Group 会被转化为具体的 TF Firewall Rules。