Kubernetes之網絡策略(Network Policy)
概述
Kubernetes要求集群中所有pod,無論是節點內還是跨節點,都可以直接通信,或者說所有pod工作在同一跨節點網絡,此網絡一般是二層虛擬網絡,稱為pod網絡。在安裝引導kubernetes時,由選擇並安裝的network plugin實現。默認情況下,集群中所有pod之間、pod與節點之間可以互通。
網絡主要解決兩個問題,一個是連通性,實體之間能夠通過網絡互通。另一個是隔離性,出於安全、限制網絡流量的目的,又要控制實體之間的連通性。Network Policy用來實現隔離性,只有匹配規則的流量才能進入pod,同理只有匹配規則的流量才可以離開pod。
但請注意,kubernetes支持的用以實現pod網絡的network plugin有很多種,並不是全部都支持Network Policy,為kubernetes選擇network plugin時需要考慮到這點,是否需要隔離?可用network plugin及是否支持Network Policy請參考這里。
基本原理
Network Policy是kubernetes中的一種資源類型,它從屬於某個namespace。其內容從邏輯上看包含兩個關鍵部分,一是pod選擇器,基於標簽選擇相同namespace下的pod,將其中定義的規則作用於選中的pod。另一個就是規則了,就是網絡流量進出pod的規則,其采用的是白名單模式,符合規則的通過,不符合規則的拒絕。
Network Policy對象Spec說明
首先給出示例Spec,結合示例說明Spec中的關鍵字段與邏輯,關於Spec完全說明參考這里。示例如下:
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
對象創建方法與其它如ReplicaSet相同。apiVersion、kind、metadata與其它類型對象含義相同,不詳細描述。
.spec.PodSelector
顧名思義,它是pod選擇器,基於標簽選擇與Network Policy處於同一namespace下的pod,如果pod被選中,則對其應用Network Policy中定義的規則。此為可選字段,當沒有此字段時,表示選中所有pod。
.spec.PolicyTypes
Network Policy定義的規則可以分成兩種,一種是入pod的Ingress規則,一種是出pod的Egress規則。本字段可以看作是一個開關,如果其中包含Ingress,則Ingress部分定義的規則生效,如果是Egress則Egress部分定義的規則生效,如果都包含則全部生效。當然此字段也可選,如果沒有指定的話,則默認Ingress生效,如果Egress部分有定義的話,Egress才生效。怎么理解這句話,下文會提到,沒有明確定義Ingress、Egress部分,它也是一種規則,默認規則而非沒有規則。
.spec.ingress與.spec.egress
前者定義入pod規則,后者定義出pod規則,詳細參考這里,這里只講一下重點。上例中ingress與egress都只包含一條規則,兩者都是數組,可以包含多條規則。當包含多條時,條目之間的邏輯關系是“或”,只要匹配其中一條就可以。.spec.ingress[].from
也是數組,數組成員對訪問pod的外部source進行描述,符合條件的source才可以訪問pod,有多種方法,如示例中的ip地址塊、名稱空間、pod標簽等,數組中的成員也是邏輯或的關系。spec.ingress[].from.prots表示允許通過的協議及端口號。
.spec.egress.to定義的是pod想要訪問的外部destination,其它與ingress相同。
默認規則
不定義規則並非沒有規則,此時默認規則生效,以下展示默認規則用法。
默認禁止所有入pod流量(Default deny all ingress traffic)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
上例中沒有定義pod選擇器,表示如果namespace下的某個pod沒有被任何Network Policy對象選中,則應用此對象,如果被其它Network Policy先中則不應用此對象。
policyTypes的值為Ingress,表示本例啟用Ingress規則。但是本例沒有定義具體的Ingress,那就應用默認規則。默認規則禁止所有入pod流量,但例外情況是如果source就是pod運行的節點,則允許通過。
默認允許所有入pod流量(Default allow all ingress traffic)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector: {}
ingress:
- {}
同樣沒有定義pod選擇器,意義與上例同。注意ingress的定義,這個是有規則的,只是規則中的條目為空,與默認規則不同,表示全部允許通過。
默認禁止所有出pod流量(Default deny all egress traffic)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Egress
與默認禁止所有入pod流量(Default deny all ingress traffic)同,只是流量由入變成出
默認允許所有出pod流量(Default allow all egress traffic)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector: {}
egress:
- {}
policyTypes:
- Egress
與默認允許所有入pod流量(Default allow all ingress traffic)同,只是流量由入變成出。
默認禁止所有入出pod流量(Default deny all ingress and all egress traffic)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
無需詳解,但請注意,pod與所運行節點之間流量不受Network Policy限制。
真實用例
下面通過一個真實示例展示Network Policy普通用法
用Deployment創建nginx pod實例並用service暴露
$ kubectl run nginx --image=nginx --replicas=2 deployment "nginx" created
$ kubectl expose deployment nginx --port=80
service "nginx" exposed
確認創建結果
$ kubectl get svc,pod
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/kubernetes 10.100.0.1 <none> 443/TCP 46m
svc/nginx 10.100.0.16 <none> 80/TCP 33s
NAME READY STATUS RESTARTS AGE
po/nginx-701339712-e0qfq 1/1 Running 0 35s
po/nginx-701339712-o00ef 1/1 Running 0 35s
測試nginx服務連通性
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false
Hit enter for command prompt
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.100.0.16:80)
/ #
通過創建Network Policy對象添加隔離性
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: access-nginx
spec:
podSelector:
matchLabels:
run: nginx
ingress:
- from:
- podSelector:
matchLabels:
access: "true"
只允許包含access: "true"標簽的pod訪問nginx服務。
創建Network Policy
$ kubectl create -f nginx-policy.yaml
networkpolicy "access-nginx" created
測試隔離性
$ kubectl run busybox --rm -ti --image=busybox /bin/sh
Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false
Hit enter for command prompt
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.100.0.16:80)
wget: download timed out
/ #
為pod添加access: "true"標簽測試連通性
$ kubectl run busybox --rm -ti --labels="access=true" --image=busybox /bin/sh
Waiting for pod default/busybox-472357175-y0m47 to be running, status is Pending, pod ready: false
Hit enter for command prompt
/ # wget --spider --timeout=1 nginx
Connecting to nginx (10.100.0.16:80)
/ #