注:本文基于K8S v1.21.2版本编写
k8s的网络能力主要表现在两个方面,一个是连通性,保证pod之间能够互通,另一个就是隔离性,考虑安全、流量限制等业务需求。
而默认情况下,k8s集群的网络没任何限制,集群中的所有pod都是互通的,这对于一些业务来说是不符合安全需求的。同时如果考虑多租户的场景,这就更不能接受了,因此需要有方法能对集群网络进行限制,这就有了Network Policy。
但有一点,并不是所有网络插件都支持Network Policy,比如flannel就不支持网络策略,calico是支持的,因此我们将基于calico来测试和说明网络策略的使用。
虽然是基于calico网络插件,但我们现在要使用的是k8s网络策略,当然也有calico网络策略,这两者是不同的。k8s网络策略提供的是一套基础和标准的规范,而calico则是基于k8s做了一些扩展,功能也更强大。
从易到难,我们先了解下基础的k8s网络策略。
因为默认情况下所有pod都是互通的,而在K8S网络策略中,我们无法显式设置deny动作,因此为了能验证我们的策略是生效的,就需要先要创建一个默认deny所有流量的策略。
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: default-deny
namespace: default
spec:
podSelector:
matchLabels: {}
policyTypes:
- Ingress
- Egress
我们以default这个namespace为例,选择该namespace下所有pod,并将流入和流出策略置空,也就实现了deny-all的目的。
首先在集群中创建两个测试pod,
[root@master network-policy]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
centos-6dc54 1/1 Running 1 24d 10.244.166.179 node1 <none> <none>
centos-tsh95 1/1 Running 1 24d 10.244.104.29 node2 <none> <none>
由于上一个步骤应用了deny-all的策略,因此两个pod是无法通信的,
[root@master home]# kubectl exec -ti centos-tsh95 -- /bin/bash
[root@centos-tsh95 /]# ping 10.244.166.179
PING 10.244.166.179 (10.244.166.179) 56(84) bytes of data.
^C
--- 10.244.166.179 ping statistics ---
6 packets transmitted, 0 received, 100% packet loss, time 5003ms
然后我们针对这个pod开放access。
为了能够识别这两个pod,我们需要给它打上标签,设置color=green和color=yellow
[root@master network-policy]# kubectl label pod centos-6dc54 color=green
pod/centos-6dc54 labeled
[root@master network-policy]# kubectl label pod centos-tsh95 color=yellow
pod/centos-tsh95 labeled
[root@master network-policy]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
centos-6dc54 1/1 Running 1 24d app=centos,color=green,controller-revision-hash=69f7b95f44,pod-template-generation=1
centos-tsh95 1/1 Running 1 24d app=centos,color=yellow,controller-revision-hash=69f7b95f44,pod-template-generation=1
然后我们就能通过这个label,在网络策略中匹配对应的pod,并允许它们之间的通信,
[root@master network-policy]# cat allow-same-namespace-green.yml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: allow-same-namespace-green
namespace: default
spec:
podSelector:
matchLabels:
color: green
egress:
- to:
- podSelector:
matchLabels:
color: yellow
ingress:
- from:
- podSelector:
matchLabels:
color: yellow
root@master network-policy]# cat allow-same-namespace-yellow.yml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: allow-same-namespace-yellow
namespace: default
spec:
podSelector:
matchLabels:
color: yellow
egress:
- to:
- podSelector:
matchLabels:
color: green
ingress:
- from:
- podSelector:
matchLabels:
color: green
需要注意的是,因为这两个pod都在default namespace中,因此要分别为这两个pod配置网络策略。同时因为我们有设置默认deny的策略,因此egress也需要配置,不然出去的包就会被默认策略丢弃。
策略应用后,这两个pod之间的通信就OK了。
[root@master network-policy]# kubectl get networkpolicy
NAME POD-SELECTOR AGE
allow-same-namespace-green color=green 6m52s
allow-same-namespace-yellow color=yellow 5m39s
default-deny <none> 7m7s
[root@centos-tsh95 /]# ping 10.244.166.187
PING 10.244.166.187 (10.244.166.187) 56(84) bytes of data.
64 bytes from 10.244.166.187: icmp_seq=1 ttl=62 time=1.38 ms
^C
--- 10.244.166.187 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.382/1.382/1.382/0.000 ms
除了针对整个pod开放流量,还可以针对具体的port和protocol,
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: allow-same-namespace-green
namespace: default
spec:
podSelector:
matchLabels:
color: green
ingress:
- from:
- podSelector:
matchLabels:
color: yellow
ports:
- protocol: UDP
port: 9999
egress:
- to:
- podSelector:
matchLabels:
color: yellow
以上策略表示其他pod只能通过9999号端口,以UDP方式连接到该pod。
参考文档