1、NetworkPolicy概述
官方說明:網絡策略(NetworkPolicy)是一種關於pod間及pod與其他網絡端點間所允許的通信規則的規范。
簡單來說,NetworkPolicy就是對pod進行網絡策略控制。用於為Kubernetes實現更為精細的流量控制,實現租戶隔離機制。Kubernetes使用標准的資源對象NetworkPolicy供管理員按需定義網絡訪問控制策略。
2、NetworkPolicy策略模型
使用network policy資源可以配置pod的網絡,networkPolicy是namespace scoped的,他只能影響某個namespace下的pod的網絡出入站規則。

metadata描述信息。podSelectorpod選擇器,選定的pod所有的出入站流量要遵循本networkpolicy的約束。policyTypes策略類型。包括了Ingress和Egress,默認情況下一個policyTypes的值一定會包含Ingress,當有egress規則時,policyTypes的值中會包含Egress。ingress入站,即由其他網絡端點發往特定Pod組的流量 ,通常由流量發出的源站點from和流量的目標端口所定義 。egress出站,即由特定的Pod組發往其他網絡端點的流量 ,通常由流量的目標網絡端點to和端口ports來進行定義 。port端口,TCP或UDP的端口號。to,from端點,流量目標和流量源相關的組件, 它可以是CIDR格式的IP地址塊ipBlock、網絡名稱空間選擇器namespaceSelector匹配的名稱空間, 或Pod選擇器podSelector匹配的Pod組。
對官方示例的說明:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978
該例子的效果如下:
1、default namespace下label包含role=db的pod,都會被隔絕,他們只能建立滿足networkPolicy的ingress和egress描述的連接。即2-5點:
2、所有屬於172.17.0.0/16網段的ip,除了172.17.1.0/24中的ip,其他的都可以與上述pod的6379端口建立tcp連接。
3、所有包含label:project=myproject的namespace中的pod可以與上述pod的6379端口建立tcp連接;
4、所有default namespace下的label包含role=frontend的pod可以與上述pod的6379端口建立tcp連接;
5、允許上述pod訪問網段為10.0.0.0/24的目的ip的5978端口。
3、NetworkPolicy默認策略
默認情況下,如果名稱空間中不存在任何策略,則所有進出該名稱空間中的Pod的流量都被允許。以下示例用於更改該名稱空間中的默認行為。
- 默認拒絕所有入口流量
通過創建選擇所有容器但不允許任何進入這些容器的入口流量的NetworkPolicy來為名稱空間創建default隔離策略。這樣可以確保即使容器沒有選擇其他任何NetworkPolicy,也仍然可以被隔離。此策略不會更改默認的出口隔離行為。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
- 默認允許所有入口流量
如果要允許所有流量進入某個命名空間中的所有Pod(即使添加了導致某些Pod被視為“隔離”的策略),則可以創建一個策略來明確允許該命名空間中的所有流量。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector: {}
ingress:
- {}
policyTypes:
- Ingress
- 默認拒絕所有出口流量
通過創建選擇所有容器但不允許來自這些容器的任何出口流量的NetworkPolicy來為名稱空間創建default egress隔離策略。這樣可以確保即使沒有被其他任何NetworkPolicy選擇的Pod也不會被允許流出流量。此策略不會更改默認的ingress隔離行為。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Egress
- 默認允許所有出口流量
如果要允許來自命名空間中所有Pod的所有流量(即使添加了導致某些Pod被視為“隔離”的策略),則可以創建一個策略,該策略明確允許該命名空間中的所有出口流量。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector: {}
egress:
- {}
policyTypes:
- Egress
- 默認拒絕所有入口和所有出口流量
為名稱空間創建default策略,以通過在該名稱空間中創建以下NetworkPolicy來阻止所有入站和出站流量。這樣可以確保即使沒有被其他任何NetworkPolicy選擇的Pod也不會被允許進入或流出流量。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
4、NetworkPolicy的實現
kubernetes的網絡策略功能本身並不支持,依賴其所使用的網絡插件實現。因此,僅在使用那些支持網絡策略功能的網絡插件時才能夠配置網絡策略,企業內部可以使用簡單的flannel、weave、kube-router等,適合公有雲的方案則有calico等。不同的網絡實現原理vethpair、bridge、macvlan等並不能統一地支持network policy。每種解決方案各有其特定的網絡策略實現方式,它們的實現或依賴於節點自身的功能,或借助於Hypervisor的特性,也可能是網絡自身的功能 。究其最終的底層實現原理,目前是基於linux iptables實現,使用類似於nf_conntrack檢查記錄網絡流量session從而決定流量是否阻斷。
5、使用flannel+canal實現k8s的NetworkPolicy
Flannel是解決容器網絡方案最為普遍和簡單的方案,Canal代表了針對雲原生應用程序的最佳網絡策略解決方案,旨在讓用戶輕松的將Calico和Flannel網絡部署在一起作為統一的網絡解決方案,將Calico的網絡策略執行和Flannel的疊加及非疊加網絡連接選項的豐富功能相結合。
在Calico的官方文檔的相應部分中描述到此種方案是:用於策略的Calico和用於網絡的Flannel相組合。官方文檔見:https://docs.projectcalico.org/v3.10/getting-started/kubernetes/installation/flannel
5.1、實驗環境說明
實驗k8s環境是kubeadm搭建的1master+2node最新版本1.16.2版本k8s,cni版本為0.3.1,flannel版本為0.11.0,flannel后端是vxlan模式並且已經開啟了Directrouting。
[root@k8s-master-01 ~]# kubectl version
Client Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.2", GitCommit:"c97fe5036ef3df2967d086711e6c0c405941e14b", GitTreeState:"clean", BuildDate:"2019-10-15T19:18:23Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"16", GitVersion:"v1.16.2", GitCommit:"c97fe5036ef3df2967d086711e6c0c405941e14b", GitTreeState:"clean", BuildDate:"2019-10-15T19:09:08Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"linux/amd64"}
[root@k8s-master-01 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master-01 Ready master 4d1h v1.16.2
k8s-node-01 Ready <none> 4d v1.16.2
k8s-node-02 Ready <none> 4d v1.16.2
[root@k8s-master-01 ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-58cc8c89f4-bd6s8 1/1 Running 2 4d1h
coredns-58cc8c89f4-bv5rl 1/1 Running 2 4d1h
etcd-k8s-master-01 1/1 Running 2 4d1h
kube-apiserver-k8s-master-01 1/1 Running 2 4d1h
kube-controller-manager-k8s-master-01 1/1 Running 2 4d1h
kube-flannel-ds-amd64-grzvh 1/1 Running 1 2d22h
kube-flannel-ds-amd64-hrd4h 1/1 Running 1 2d22h
kube-flannel-ds-amd64-l8rtk 1/1 Running 1 2d22h
kube-proxy-bp98z 1/1 Running 2 4d
kube-proxy-kvwgh 1/1 Running 2 4d
kube-proxy-n8lj6 1/1 Running 2 4d1h
kube-scheduler-k8s-master-01 1/1 Running 2 4d1h
5.2、安裝canal
按照官方文檔說明安裝:https://docs.projectcalico.org/v3.10/getting-started/kubernetes/installation/flannel
部署時canal支持將數據存儲於etcd中,支持選擇專用的etcd存儲,也能夠以kubernetes api server作為后端存儲,這里選擇以后種方式進行。
結合flannel工作時,Calico提供的默認配置清單中是以flannel默認使用的10.244.0.0/16 為Pod網絡,因此,請確保kube-controller-manager程序在啟動時通過--clustr-cidr選項設置使用了此網絡地址,並且--allocate-node-cidrs的值應設置為true。在使用kubeadm安裝的此版本集群中,此選項均已配置。
如果集群cidr網絡地址不是默認值,需要修改配置再進行部署。
[root@k8s-master-01 canal]# curl https://docs.projectcalico.org/v3.10/manifests/canal.yaml -O
[root@k8s-master-01 canal]# kubectl apply -f canal.yaml
configmap/canal-config created
customresourcedefinition.apiextensions.k8s.io/felixconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamblocks.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/blockaffinities.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamhandles.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ipamconfigs.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/bgppeers.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/bgpconfigurations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/ippools.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/hostendpoints.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/clusterinformations.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/globalnetworksets.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networkpolicies.crd.projectcalico.org created
customresourcedefinition.apiextensions.k8s.io/networksets.crd.projectcalico.org created
clusterrole.rbac.authorization.k8s.io/calico-node created
clusterrole.rbac.authorization.k8s.io/flannel configured
clusterrolebinding.rbac.authorization.k8s.io/canal-flannel created
clusterrolebinding.rbac.authorization.k8s.io/canal-calico created
daemonset.apps/canal created
serviceaccount/canal created
[root@k8s-master-01 ~]# kubectl get pods -n kube-system -o wide|grep canal
canal-rxb97 2/2 Running 0 4h25m 192.168.2.12 k8s-node-02 <none> <none>
canal-tdcgf 2/2 Running 0 4h25m 192.168.2.10 k8s-master-01 <none> <none>
canal-vll8z 2/2 Running 0 4h25m 192.168.2.11 k8s-node-01 <none> <none>
5.3、應用示例
5.3.1、創建默認服務
運行一組nginx pod並暴露80端口
[root@k8s-master-01 ~]# kubectl run nginx --image=nginx --replicas=3 --port=80 --expose
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
service/nginx created
deployment.apps/nginx created
[root@k8s-master-01 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-5578584966-8spqk 1/1 Running 0 15s
nginx-5578584966-sjlvc 1/1 Running 0 15s
nginx-5578584966-xm4pb 1/1 Running 0 15s
[root@k8s-master-01 ~]# kubectl get svc nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 10.1.8.146 <none> 80/TCP 16s
5.3.2、測試訪問
[root@k8s-master-01 ~]# kubectl run busy1 --rm -it --image=busybox /bin/sh
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
If you don't see a command prompt, try pressing enter.
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.1.8.146:80)
remote file exists ## 訪問成功
5.3.4、創建默認policy
創建默認拒絕所有入站流量的networkpolicy,測試訪問
[root@k8s-master-01 networkpolicy]# vim default-deny-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
[root@k8s-master-01 networkpolicy]# kubectl apply -f default-deny-ingress.yaml
networkpolicy.networking.k8s.io/default-deny created
[root@k8s-master-01 ~]# kubectl run busy1 --rm -it --image=busybox /bin/sh
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
If you don't see a command prompt, try pressing enter.
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.1.8.146:80)
wget: download timed out ## 訪問失敗
5.3.5、創建一個允許帶有access=true的Pod訪問nginx的網絡策略
[root@k8s-master-01 networkpolicy]# vim nginx-policy.yaml
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: access-nginx
spec:
podSelector:
matchLabels:
run: nginx
ingress:
- from:
- podSelector:
matchLabels:
access: "true"
[root@k8s-master-01 networkpolicy]# kubectl apply -f nginx-policy.yaml
networkpolicy.networking.k8s.io/access-nginx created
使用不帶access=true標簽的pod訪問服務
[root@k8s-master-01 ~]# kubectl run busy1 --rm -it --image=busybox /bin/sh
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
If you don't see a command prompt, try pressing enter.
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.1.8.146:80)
wget: download timed out ## 訪問失敗
使用帶access=true標簽的pod訪問服務
[root@k8s-master-01 ~]# kubectl run busy2 --rm -it --labels="access=true" --image=busybox /bin/sh
kubectl run --generator=deployment/apps.v1 is DEPRECATED and will be removed in a future version. Use kubectl run --generator=run-pod/v1 or kubectl create instead.
If you don't see a command prompt, try pressing enter.
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.1.8.146:80)
remote file exists ## 訪問成功
5.4、生產使用場景
5.4.1、禁止訪問指定服務
kubectl run web --image=nginx --labels app=web,env=prod --expose --port 80
網絡策略
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: web-deny-all
spec:
podSelector:
matchLabels:
app: web
env: prod
5.4.2、只允許指定pod訪問服務
kubectl run apiserver --image=nginx --labels app=bookstore,role=api --expose --port 80
網絡策略
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: api-allow
spec:
podSelector:
matchLabels:
app: bookstore
role: api
ingress:
- from:
- podSelector:
matchLabels:
app: bookstore
5.4.3、禁止 namespace 中所有 Pod 之間的相互訪問
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: default
spec:
podSelector: {}
5.4.4、禁止其他 namespace 訪問服務
kubectl create namespace secondary
kubectl run web --namespace secondary --image=nginx \
--labels=app=web --expose --port 80
網絡策略
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
namespace: secondary
name: web-deny-other-namespaces
spec:
podSelector:
matchLabels:
ingress:
- from:
- podSelector: {}
5.4.5、只允許指定namespace訪問服務
kubectl run web --image=nginx \
--labels=app=web --expose --port 80
網絡策略
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: web-allow-prod
spec:
podSelector:
matchLabels:
app: web
ingress:
- from:
- namespaceSelector:
matchLabels:
purpose: production
5.4.6、允許外網訪問服務
kubectl run web --image=nginx --labels=app=web --port 80
kubectl expose deployment/web --type=LoadBalancer
網絡策略
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: web-allow-external
spec:
podSelector:
matchLabels:
app: web
ingress:
- ports:
- port: 80
from: []
參考來源:
https://kubernetes.io/zh/docs/concepts/services-networking/network-policies/
https://docs.projectcalico.org/v3.10/getting-started/kubernetes/installation/flannel
https://github.com/ahmetb/kubernetes-network-policy-recipes
