kubernetes集群網絡


Kubernetes網絡模型

Kubernetes 要求所有的網絡插件實現必須滿足如下要求:

  • 一個Pod一個IP

  • 所有的 Pod 可以與任何其他 Pod 直接通信,無需使用 NAT 映射

  • 所有節點可以與所有 Pod 直接通信,無需使用 NAT 映射

  • Pod 內部獲取到的 IP 地址與其他 Pod 或節點與其通信時的 IP 地址是同一個。

Docker容器網絡模型

先看下Linux網絡名詞:

  • 網絡的命名空間:Linux在網絡棧中引入網絡命名空間,將獨立的網絡協議棧隔離到不同的命令空間中,彼此間無法通信;Docker利用這一特性,實現不同容器間的網絡隔離。

  • Veth設備對:Veth設備對的引入是為了實現在不同網絡命名空間的通信。

  • Iptables/Netfilter:Docker使用Netfilter實現容器網絡轉發。

  • 網橋:網橋是一個二層網絡設備,通過網橋可以將Linux支持的不同的端口連接起來,並實現類似交換機那樣的多對多的通信。

  • 路由:Linux系統包含一個完整的路由功能,當IP層在處理數據發送或轉發的時候,會使用路由表來決定發往哪里。

Docker容器網絡示意圖如下:

 

Pod 網絡

問題:Pod是K8S最小調度單元,一個Pod由一個容器或多個容器組成,當多個容器時,怎么都用這一個Pod IP?

實現:k8s會在每個Pod里先啟動一個infra container小容器,然后讓其他的容器連接進來這個網絡命名空間,然后其他容器看到的網絡試圖就完全一樣了。即網絡設備、IP地址、Mac地址等。這就是解決網絡共享的一種解法。在Pod的IP地址就是infra container的IP地址。

在 Kubernetes 中,每一個 Pod 都有一個真實的 IP 地址,並且每一個 Pod 都可以使用此 IP 地址與 其他 Pod 通信。

Pod之間通信會有兩種情況:

  • 兩個Pod在同一個Node上

  • 兩個Pod在不同Node上

先看下第一種情況:兩個Pod在同一個Node上

同節點Pod之間通信道理與Docker網絡一樣的,如下圖:

 

  1. 對 Pod1 來說,eth0 通過虛擬以太網設備(veth0)連接到 root namespace;

  2. 網橋 cbr0 中為 veth0 配置了一個網段。一旦數據包到達網橋,網橋使用ARP 協議解析出其正確的目標網段 veth1;

  3. 網橋 cbr0 將數據包發送到 veth1;

  4. 數據包到達 veth1 時,被直接轉發到 Pod2 的 network namespace 中的 eth0 網絡設備。

再看下第二種情況:兩個Pod在不同Node上

K8S網絡模型要求Pod IP在整個網絡中都可訪問,這種需求是由第三方網絡組件實現。

 

CNI(容器網絡接口)

CNI(Container Network Interface,容器網絡接口):是一個容器網絡規范,Kubernetes網絡采用的就是這個CNI規范,CNI實現依賴兩種插件,一種CNI Plugin是負責容器連接到主機,另一種是IPAM負責配置容器網絡命名空間的網絡。

CNI插件默認路徑:

# ls /opt/cni/bin/

地址:https://github.com/containernetworking/cni

當你在宿主機上部署Flanneld后,flanneld 啟動后會在每台宿主機上生成它對應的CNI 配置文件(它其實是一個 ConfigMap),從而告訴Kubernetes,這個集群要使用 Flannel 作為容器網絡方案。

CNI配置文件路徑:

/etc/cni/net.d/10-flannel.conflist

當 kubelet 組件需要創建 Pod 的時候,先調用dockershim它先創建一個 Infra 容器。然后調用 CNI 插件為 Infra 容器配置網絡。

這兩個路徑在kubelet啟動參數中定義:

 --network-plugin=cni \
 --cni-conf-dir=/etc/cni/net.d \
 --cni-bin-dir=/opt/cni/bin

Kubernetes網絡組件之 Flannel

Flannel是CoreOS維護的一個網絡組件,Flannel為每個Pod提供全局唯一的IP,Flannel使用ETCD來存儲Pod子網與Node IP之間的關系。flanneld守護進程在每台主機上運行,並負責維護ETCD信息和路由數據包。

Flannel 部署

https://github.com/coreos/flannel

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
Flannel工作模式及原理

Flannel支持多種數據轉發方式:

  • UDP:最早支持的一種方式,由於性能最差,目前已經棄用。

  • VXLAN:Overlay Network方案,源數據包封裝在另一種網絡包里面進行路由轉發和通信

  • Host-GW:Flannel通過在各個節點上的Agent進程,將容器網絡的路由信息刷到主機的路由表上,這樣一來所有的主機都有整個容器網絡的路由數據了。

  • Directrouting(vxlan+host-gw)

# kubeadm部署指定Pod網段
kubeadm init --pod-network-cidr=10.244.0.0/16

# 二進制部署指定
cat /opt/kubernetes/cfg/kube-controller-manager.conf
--allocate-node-cidrs=true \
--cluster-cidr=10.244.0.0/16 \

#配置文件 kube-flannel.yml
net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
    }

為了能夠在二層網絡上打通“隧道”,VXLAN 會在宿主機上設置一個特殊的網絡設備作為“隧道”的兩端。這個設備就叫作 VTEP,即:VXLAN Tunnel End Point(虛擬隧道端點)。

 如果Pod 1訪問Pod 2,源地址10.244.2.250,目的地址10.244.1.33 ,數據包傳輸流程如下:

1、容器路由:容器根據路由表從eth0發出
# kubectl get pod -o wide
NAME                                      READY   STATUS    RESTARTS   AGE     IP            NODE          NOMINATED NODE   READINESS GATES
busybox-6cd57fd969-4n6fn                  1/1     Running   0          61s     10.244.2.50   k8s-master1   <none>           <none>
web-5675686b8-rc9bf                       1/1     Running   0          7m12s   10.244.1.33   k8s-node01    <none>           <none>
web-5675686b8-rrc6f                       1/1     Running   0          7m12s   10.244.2.49   k8s-master1   <none>           <none>
# kubectl exec -it busybox-6cd57fd969-4n6fn sh
/ # ip route
default via 10.244.2.1 dev eth0 
10.244.0.0/16 via 10.244.2.1 dev eth0 
10.244.2.0/24 dev eth0 scope link  src 10.244.2.51

2、主機路由:數據包進入到宿主機虛擬網卡cni0,根據路由表轉發到flannel.1虛擬網卡,也就是,來到了隧道的入口。
# ip route
default via 192.168.0.1 dev ens32 proto static metric 100 
10.244.0.0/24 via 10.244.0.0 dev flannel.1 onlink 
10.244.1.0/24 via 10.244.1.0 dev flannel.1 onlink 

3、VXLAN封裝:而這些VTEP設備(二層)之間組成二層網絡必須要知道目的MAC地址。這個MAC地址從哪獲取到呢?其實在flanneld進程啟動后,就會自動添加其他節點ARP記錄,可以通過ip命令查看,如下所示:
# ip neigh show dev flannel.1
10.244.0.0 lladdr 06:6a:9d:15:ac:e0 PERMANENT
10.244.1.0 lladdr 36:68:64:fb:4f:9a PERMANENT

4、二次封包:知道了目的MAC地址,封裝二層數據幀(容器源IP和目的IP)后,對於宿主機網絡來說這個幀並沒有什么實際意義。接下來,Linux內核還要把這個數據幀進一步封裝成為宿主機網絡的一個普通數據幀,好讓它載着內部數據幀,通過宿主機的eth0網卡進行傳輸。

5、封裝到UDP包發出去:現在能直接發UDP包嘛?到目前為止,我們只知道另一端的flannel.1設備的MAC地址,卻不知道對應的宿主機地址是什么。
flanneld進程也維護着一個叫做FDB的轉發數據庫,可以通過bridge fdb命令查看:
# bridge fdb show  dev flannel.1
06:6a:9d:15:ac:e0 dst 192.168.0.134 self permanent
36:68:64:fb:4f:9a dst 192.168.0.133 self permanent
可以看到,上面用的對方flannel.1的MAC地址對應宿主機IP,也就是UDP要發往的目的地。使用這個目的IP進行封裝。

6、數據包到達目的宿主機:Node1的eth0網卡發出去,發現是VXLAN數據包,把它交給flannel.1設備。flannel.1設備則會進一步拆包,取出原始二層數據幀包,發送ARP請求,經由cni0網橋轉發給container。
Host-GW

host-gw模式相比vxlan簡單了許多, 直接添加路由,將目的主機當做網關,直接路由原始封包。

# kube-flannel.yml
net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "host-gw"
      }
    }

當你設置flannel使用host-gw模式,flanneld會在宿主機上創建節點的路由表:

# ip route
default via 192.168.0.1 dev ens32 proto static metric 100
10.244.0.0/24 via 192.168.0.134 dev ens32
10.244.1.0/24 via 192.168.0.133 dev ens32
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
192.168.0.0/24 dev ens32 proto kernel scope link src 192.168.0.132 metric 100

目的 IP 地址屬於 10.244.1.0/24 網段的 IP 包,應該經過本機的 eth0 設備發出去(即:dev eth0);並且,它下一跳地址是 192.168.0.132。一旦配置了下一跳地址,那么接下來,當 IP 包從網絡層進入鏈路層封裝成幀的時候,eth0 設備就會使用下一跳地址對應的 MAC 地址,作為該數據幀的目的 MAC 地址。

而 Node 2 的內核網絡棧從二層數據幀里拿到 IP 包后,會“看到”這個 IP 包的目的 IP 地址是container-2 的 IP 地址。這時候,根據 Node 2 上的路由表,該目的地址會匹配到第二條路由規則,從而進入 cni0 網橋,進而進入到 container-2 當中。

Directrouting
# kubectl edit cm kube-flannel-cfg  -n kube-system
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "vxlan"
        "Directrouting": true
      }
    }

# kubectl get cm kube-flannel-cfg -o json -n kube-system
        "net-conf.json": "{\n  \"Network\": \"10.244.0.0/16\",\n  \"Backend\": {\n    \"Type\": \"vxlan\"\n    \"Directrouting\": true\n  }\n}\n"

小結:
1、vxlan 不受網絡環境限制,只要三層可達就行
2、vxlan 需要二層解封包,降低工作效率
3、hostgw 基於路由表轉發,效率更高
4、hostgw 只適用於二層網絡(本身網絡架構受限,節點數量也受限)

Kubernetes網絡方案之 Calico

Calico是一個純三層的數據中心網絡方案,Calico支持廣泛的平台,包括Kubernetes、OpenStack等。

Calico 在每一個計算節點利用 Linux Kernel 實現了一個高效的虛擬路由器( vRouter) 來負責數據轉發,而每個 vRouter 通過 BGP 協議負責把自己上運行的 workload 的路由信息向整個 Calico 網絡內傳播。

此外,Calico 項目還實現了 Kubernetes 網絡策略,提供ACL功能。

BGP概述

實際上,Calico項目提供的網絡解決方案,與Flannel的host-gw模式幾乎一樣。也就是說,Calico也是基於路由表實現容器數據包轉發,但不同於Flannel使用flanneld進程來維護路由信息的做法,而Calico項目使用BGP協議來自動維護整個集群的路由信息。

BGP英文全稱是Border Gateway Protocol,即邊界網關協議,它是一種自治系統間的動態路由發現協議,與其他 BGP 系統交換網絡可達信息。

為了能讓你更清楚理解BGP,舉個例子:

 

 

在這個圖中,有兩個自治系統(autonomous system,簡稱為AS):AS 1 和 AS 2。

在互聯網中,一個自治系統(AS)是一個有權自主地決定在本系統中應采用何種路由協議的小型單位。這個網絡單位可以是一個簡單的網絡也可以是一個由一個或多個普通的網絡管理員來控制的網絡群體,它是一個單獨的可管理的網絡單元(例如一所大學,一個企業或者一個公司個體)。一個自治系統有時也被稱為是一個路由選擇域(routing domain)。一個自治系統將會分配一個全局的唯一的16位號碼,有時我們把這個號碼叫做自治系統號(ASN)。

在正常情況下,自治系統之間不會有任何來往。如果兩個自治系統里的主機,要通過 IP 地址直接進行通信,我們就必須使用路由器把這兩個自治系統連接起來。BGP協議就是讓他們互聯的一種方式。

Calico BGP實現

在了解了 BGP 之后,Calico 項目的架構就非常容易理解了,Calico主要由三個部分組成:

  • Felix:以DaemonSet方式部署,運行在每一個Node節點上,主要負責維護宿主機上路由規則以及ACL規則。

  • BGP Client(BIRD):主要負責把 Felix 寫入 Kernel 的路由信息分發到集群 Calico 網絡。

  • Etcd:分布式鍵值存儲,保存Calico的策略和網絡配置狀態。

  • calicoctl:允許您從簡單的命令行界面實現高級策略和網絡。

Calico 部署
curl https://docs.projectcalico.org/v3.9/manifests/calico-etcd.yaml -o calico.yaml

下載完后還需要修改里面配置項:

具體步驟如下:

  • 配置連接etcd地址,如果使用https,還需要配置證書。(ConfigMap,Secret)

  • 根據實際網絡規划修改Pod CIDR(CALICO_IPV4POOL_CIDR)

  • 選擇工作模式(CALICO_IPV4POOL_IPIP),支持BGP(Never)IPIP(Always)CrossSubnet(開啟BGP並支持跨子網)

刪除flannel網絡

# kubectl delete -f kube-flannel.yaml
# ip link delete flannel.1
# ip link delete cni0
# ip route del 10.244.2.0/24 via 192.168.0.132 dev ens32
# ip route del 10.244.1.0/24 via 192.168.0.133 dev ens32

應用清單:

# kubectl apply -f calico.yaml
# kubectl get pods -n kube-system
Calico 管理工具

下載工具:https://github.com/projectcalico/calicoctl/releases

# wget -O /usr/local/bin/calicoctl https://github.com/projectcalico/calicoctl/releases/download/v3.9.1/calicoctl
# chmod +x /usr/local/bin/calicoctl

# mkdir /etc/calico
# vim /etc/calico/calicoctl.cfg  
apiVersion: projectcalico.org/v3
kind: CalicoAPIConfig
metadata:
spec:
  datastoreType: "etcdv3"
  etcdEndpoints: "https://192.168.0.132:2379,https://192.168.0.133:2379,https://192.168.0.134:2379"
  etcdKeyFile: "/opt/etcd/ssl/server-key.pem"
  etcdCertFile: "/opt/etcd/ssl/server.pem"
  etcdCACertFile: "/opt/etcd/ssl/ca.pem"

使用calicoctl查看服務狀態:

# calicoctl get node
NAME         
k8s-master   
k8s-node01   
k8s-node02   
# calicoctl node status
IPv4 BGP status
+---------------+-------------------+-------+----------+-------------+
| PEER ADDRESS  |     PEER TYPE     | STATE |  SINCE   |    INFO     |
+---------------+-------------------+-------+----------+-------------+
| 192.168.0.133 | node-to-node mesh | up    | 07:24:45 | Established |
| 192.168.0.134 | node-to-node mesh | up    | 07:25:00 | Established |
+---------------+-------------------+-------+----------+-------------+
查看 IPAM的IP地址池:
# calicoctl get ippool -o wide
NAME                  CIDR            NAT    IPIPMODE   VXLANMODE   DISABLED   SELECTOR   
default-ipv4-ippool   10.244.0.0/16   true   Never      Never       false      all()
Calico BGP 原理

Pod 1 訪問 Pod 2大致流程如下:

  1. 數據包從容器1出到達Veth Pair另一端(宿主機上,以cali前綴開頭);

  2. 宿主機根據路由規則,將數據包轉發給下一跳(網關);

  3. 到達Node2,根據路由規則將數據包轉發給cali設備,從而到達容器2。

路由表:

# node1
default via 192.168.0.1 dev ens32 proto static metric 100 
10.244.0.0/24 via 192.168.0.134 dev ens32 
10.244.58.192/26 via 192.168.0.134 dev ens32 proto bird 
10.244.85.192 dev calic32fa4483b3 scope link 
blackhole 10.244.85.192/26 proto bird 
10.244.235.192/26 via 192.168.0.132 dev ens32 proto bird

# node2
default via 192.168.0.1 dev ens32 proto static metric 100 
10.244.58.192 dev calib29fd680177 scope link 
blackhole 10.244.58.192/26 proto bird 
10.244.85.192/26 via 192.168.0.133 dev ens32 proto bird 
10.244.235.192/26 via 192.168.0.132 dev ens32 proto bird

其中,這里最核心的“下一跳”路由規則,就是由 Calico 的 Felix 進程負責維護的。這些路由規則信息,則是通過 BGP Client 也就是 BIRD 組件,使用 BGP 協議傳輸而來的。

不難發現,Calico 項目實際上將集群里的所有節點,都當作是邊界路由器來處理,它們一起組成了一個全連通的網絡,互相之間通過 BGP 協議交換路由規則。這些節點,我們稱為 BGP Peer。

Route Reflector 模式(RR)

https://docs.projectcalico.org/master/networking/bgp

Calico 維護的網絡在默認是(Node-to-Node Mesh)全互聯模式,Calico集群中的節點之間都會相互建立連接,用於路由交換。但是隨着集群規模的擴大,mesh模式將形成一個巨大服務網格,連接數成倍增加。

# netstat -antp |grep bird
tcp        0      0 0.0.0.0:179             0.0.0.0:*               LISTEN      23124/bird          
tcp        0      0 192.168.0.134:44366     192.168.0.132:179       ESTABLISHED 23124/bird          
tcp        0      0 192.168.0.134:1215      192.168.0.133:179       ESTABLISHED 23124/bird

這時就需要使用 Route Reflector(路由器反射)模式解決這個問題。

確定一個或多個Calico節點充當路由反射器,讓其他節點從這個RR節點獲取路由信息。

具體步驟如下:

1、關閉 node-to-node BGP網格

添加 default BGP配置,調整 nodeToNodeMeshEnabled和asNumber:

cat << EOF | calicoctl create -f -
 apiVersion: projectcalico.org/v3
 kind: BGPConfiguration
 metadata:
   name: default
 spec:
   logSeverityScreen: Info
   nodeToNodeMeshEnabled: false  
   asNumber: 63400
EOF

ASN號可以通過獲取 # calicoctl get nodes --output=wide

2、配置指定節點充當路由反射器

為方便讓BGPPeer輕松選擇節點,通過標簽選擇器匹配。

給路由器反射器節點打標簽:

kubectl label node k8s-node01 route-reflector=true

然后配置路由器反射器節點routeReflectorClusterID:

# calicoctl get node k8s-node01 -o yaml > rr-node.yaml
# vim rr-node.yaml 
apiVersion: projectcalico.org/v3
kind: Node
apiVersion: projectcalico.org/v3
kind: Node
metadata:
  annotations:
    projectcalico.org/kube-labels: '{"beta.kubernetes.io/arch":"amd64","beta.kubernetes.io/os":"linux","kubernetes.io/arch":"amd64","kubernetes.io/hostname":"k8s-node01","kubernetes.io/os":"linux"}'
  creationTimestamp: 2020-06-04T07:24:40Z
  labels:
    beta.kubernetes.io/arch: amd64
    beta.kubernetes.io/os: linux
    kubernetes.io/arch: amd64
    kubernetes.io/hostname: k8s-node01
    kubernetes.io/os: linux
  name: k8s-node01
  resourceVersion: "50638"
  uid: 16452357-d399-4247-bc2b-ab7e7eb52dbc
spec:
  bgp:
    ipv4Address: 192.168.0.133/24
    routeReflectorClusterID: 244.0.0.1
  orchRefs:
  - nodeName: k8s-node01
    orchestrator: k8s

# calicoctl apply -f bgppeer.yaml
Successfully applied 1 'BGPPeer' resource(s)

現在,很容易使用標簽選擇器將路由反射器節點與其他非路由反射器節點配置為對等:

# vi bgppeer.yaml
apiVersion: projectcalico.org/v3
kind: BGPPeer
metadata:
  name: peer-with-route-reflectors
spec:
  nodeSelector: all()
  peerSelector: route-reflector == 'true'

# calicoctl apply -f bgppeer.yaml
Successfully applied 1 'BGPPeer' resource(s)

查看節點的BGP連接狀態:

# calicoctl node status
Calico process is running.
IPv4 BGP status
+---------------+---------------+-------+----------+-------------+
| PEER ADDRESS  |   PEER TYPE   | STATE |  SINCE   |    INFO     |
+---------------+---------------+-------+----------+-------------+
| 192.168.0.133 | node specific | up    | 09:54:05 | Established |
+---------------+---------------+-------+----------+-------------+
IPIP模式

在前面提到過,Flannel host-gw 模式最主要的限制,就是要求集群宿主機之間是二層連通的。而這個限制對於 Calico 來說,也同樣存在。

修改為IPIP模式:

# calicoctl get ipPool -o yaml > ipip.yaml
# vim ipip.yaml
apiVersion: projectcalico.org/v3
items:
- apiVersion: projectcalico.org/v3
  kind: IPPool
  metadata:
    creationTimestamp: 2020-06-04T07:24:39Z
    name: default-ipv4-ippool
    resourceVersion: "50630"
    uid: e6515b21-44eb-4de9-8dc2-42f291da4273
  spec:
    blockSize: 26
    cidr: 10.244.0.0/16
    ipipMode: Always
    natOutgoing: true
    nodeSelector: all()
    vxlanMode: Never
kind: IPPoolList
metadata:
  resourceVersion: "76218"

# calicoctl apply -f ipip.yaml
Successfully applied 1 'IPPool' resource(s)
# calicoctl get ippool -o wide
NAME                  CIDR            NAT    IPIPMODE   VXLANMODE   DISABLED   SELECTOR   
default-ipv4-ippool   10.244.0.0/16   true   Always     Never       false      all()

Pod 1 訪問 Pod 2大致流程如下:

  1. 數據包從容器1出到達Veth Pair另一端(宿主機上,以cali前綴開頭);

  2. 進入IP隧道設備(tunl0)由Linux內核IPIP驅動封裝在宿主機網絡的IP包中(新的IP包目的地之是原IP包的下一跳地址),這樣就成了Node1 到Node2的數據包;

  3. 數據包經過路由器三層轉發到Node2;

  4. Node2收到數據包后,網絡協議棧會使用IPIP驅動進行解包,從中拿到原始IP包;

  5. 然后根據路由規則,根據路由規則將數據包轉發給cali設備,從而到達容器2。

路由表:

# node01
10.244.58.192/26 via 192.168.0.134 dev tunl0 proto bird onlink 
10.244.85.192 dev calic32fa4483b3 scope link

# node02
10.244.58.192 dev calib29fd680177 scope link 
10.244.85.192/26 via 192.168.0.133 dev tunl0 proto bird onlink

不難看到,當 Calico 使用 IPIP 模式的時候,集群的網絡性能會因為額外的封包和解包工作而下降。所以建議你將所有宿主機節點放在一個子網里,避免使用 IPIP。

CNI 網絡方案優缺點及選擇

先考慮幾個問題:

  • 需要細粒度網絡訪問控制?

  • 追求網絡性能?

  • 服務器之前是否可以跑BGP協議?

  • 集群規模多大?

  • 是否有維護能力?

網絡策略

為什么需要網絡隔離?

CNI插件插件解決了不同Node節點Pod互通問題,從而形成一個扁平化網絡,默認情況下,Kubernetes 網絡允許所有 Pod 到 Pod 的流量,在一些場景中,我們不希望Pod之間默認相互訪問,例如:

  • 應用程序間的訪問控制。例如微服務A允許訪問微服務B,微服務C不能訪問微服務A

  • 開發環境命名空間不能訪問測試環境命名空間Pod

  • 當Pod暴露到外部時,需要做Pod白名單

  • 多租戶網絡環境隔離

所以,我們需要使用network policy對Pod網絡進行隔離。支持對Pod級別和Namespace級別網絡訪問控制。

Pod網絡入口方向隔離

  • 基於Pod級網絡隔離:只允許特定對象訪問Pod(使用標簽定義),允許白名單上的IP地址或者IP段訪問Pod

  • 基於Namespace級網絡隔離:多個命名空間,A和B命名空間Pod完全隔離。

Pod網絡出口方向隔離

  • 拒絕某個Namespace上所有Pod訪問外部

  • 基於目的IP的網絡隔離:只允許Pod訪問白名單上的IP地址或者IP段

  • 基於目標端口的網絡隔離:只允許Pod訪問白名單上的端口

網絡策略概述

一個NetworkPolicy例子:

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

配置解析:

  • podSelector:用於選擇策略應用到的Pod組。

  • policyTypes:其可以包括任一Ingress,Egress或兩者。該policyTypes字段指示給定的策略用於Pod的入站流量、還是出站流量,或者兩者都應用。如果未指定任何值,則默認值為Ingress,如果網絡策略有出口規則,則設置egress。

  • Ingress:from是可以訪問的白名單,可以來自於IP段、命名空間、Pod標簽等,ports是可以訪問的端口。

  • Egress:這個Pod組可以訪問外部的IP段和端口。

入站、出站網絡流量訪問控制案例

Pod訪問限制

准備測試環境,一個web pod,兩個client pod

# kubectl create deployment web --image=nginx
# kubectl run client1 --generator=run-pod/v1 --image=busybox --command -- sleep 36000
# kubectl run client2 --generator=run-pod/v1 --image=busybox --command -- sleep 36000
# kubectl get pods --show-labels
NAME                   READY   STATUS    RESTARTS   AGE    LABELS
client1                1/1     Running   0          49s    run=client1
client2                1/1     Running   0          49s    run=client2
web-5886dfbb96-8mkg9   1/1     Running   0          136m   app=web,pod-template-hash=5886dfbb96
web-5886dfbb96-hps6t   1/1     Running   0          136m   app=web,pod-template-hash=5886dfbb96
web-5886dfbb96-lckfs   1/1     Running   0          136m   app=web,pod-template-hash=5886dfbb96

需求:將default命名空間攜帶run=web標簽的Pod隔離,只允許default命名空間攜帶run=client1標簽的Pod訪問80端口

# vim pod-acl.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: web
  policyTypes:
  - Ingress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          project: default
    - podSelector:
        matchLabels:
          run: client1
    ports:
    - protocol: TCP
      port: 80

# kubectl apply -f pod-acl.yaml

測試

# kubectl exec -it client1 sh
/ # wget 10.244.85.192
Connecting to 10.244.85.192 (10.244.85.192:80)
saving to 'index.html'
index.html           100% |**************************************************************************************************************|   612  0:00:00 ETA
'index.html' saved

# kubectl exec -it client2 sh
/ # wget 10.244.85.192
Connecting to 10.244.85.192 (10.244.85.192:80)
wget: can't connect to remote host (10.244.85.192): Connection timed out

隔離策略配置:

Pod對象:default命名空間攜帶run=web標簽的Pod

允許訪問端口:80

允許訪問對象:default命名空間攜帶run=client1標簽的Pod

拒絕訪問對象:除允許訪問對象外的所有對象

命名空間隔離

需求:default命名空間下所有pod可以互相訪問,但不能訪問其他命名空間Pod,其他命名空間也不能訪問default命名空間Pod。

# kubectl create ns test
namespace/test created
# kubectl create deployment web --image=nginx -n test
deployment.apps/web created
# kubectl run client -n test --generator=run-pod/v1 --image=busybox --command -- sleep 36000

# vim ns-acl.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-from-other-namespaces 
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector: {}

# kubectl apply -f ns-acl.yaml
# kubectl get pod -n test -o wide
NAME                  READY   STATUS    RESTARTS   AGE    IP               NODE          NOMINATED NODE   READINESS GATES
client                1/1     Running   0          119s   10.244.85.195    k8s-node01    <none>           <none>
web-d86c95cc9-gr88v   1/1     Running   0          10m    10.244.235.198   k8s-master1   <none>           <none>
[root@k8s-master ~]# kubectl get pod  -o wide
NAME                   READY   STATUS    RESTARTS   AGE    IP               NODE          NOMINATED NODE   READINESS GATES
web-5886dfbb96-8mkg9   1/1     Running   0          158m   10.244.235.193   k8s-master1   <none>           <none>
web-5886dfbb96-hps6t   1/1     Running   0          158m   10.244.85.192    k8s-node01    <none>           <none>
web-5886dfbb96-lckfs   1/1     Running   0          158m   10.244.58.192    k8s-node02    <none>           <none>
# kubectl exec -it client -n test sh
/ # wget 10.244.58.192
Connecting to 10.244.58.192 (10.244.58.192:80)
wget: can't connect to remote host (10.244.58.192): Connection timed out
/ # wget 10.244.235.198
Connecting to 10.244.235.198 (10.244.235.198:80)
saving to 'index.html'
index.html           100% |**************************************************************************************************************|   612  0:00:00 ETA
'index.html' saved

podSelector: {}:default命名空間下所有Pod

from.podSelector: {} : 如果未配置具體的規則,默認不允許


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM