1 典型的數據傳輸流程圖

• 一個外部的business-manager請求,首先進入集群的入口(ingress),ingress反向代理后負載到business-manager的service。Service層再負載到某個node下的具體的business-manager pod
• Business-manager pod再將請求發往data-product的service,同理,service層繼續隨機選擇一個data-product的Pod來接收請求
• 上面這個請求,涉及到容器的網絡-docker0、跨主機通訊-flannel網絡方案、ingress和service組件,以及DNS等,下面我會挨個介紹它們的基本原理。
2 3種ip說明
寫這個文檔的同時,我在虛擬機上搭建了一個K8S環境,集群內包含2台主機,ip分別為192.168.0.21和192.168.0.22,主要組件為ingress->nginx、service->kube-proxy、網絡->flannel,我們以這個集群為例進行分析。
在深入之前,我們先科普一下K8S集群內常見IP的含義:
# kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE
business-manager-666f454f7f-bg2bt 1/1 Running 0 153m 172.30.76.4 192.168.0.21
business-manager-666f454f7f-kvn5z 1/1 Running 0 153m 172.30.76.5 192.168.0.21
business-manager-666f454f7f-ncjp7 1/1 Running 0 153m 172.30.9.4 192.168.0.22
data-product-6664c6dcb9-7sxnz 1/1 Running 0 160m 172.30.76.2 192.168.0.21
data-product-6664c6dcb9-j2f48 1/1 Running 0 160m 172.30.76.3 192.168.0.21
data-product-6664c6dcb9-p5xkw 1/1 Running 0 160m 172.30.9.3 192.168.0.22
Node ip:宿主機的ip,由路由器分配。上圖最右邊的NODE列代表的就是容器所在的宿主機的物理ip,可以看到現在集群內2台主機都有分配容器。
Pod ip:被docker0網橋隔離的pod子網的ip。K8s在每個Node里虛擬出的局域網。上圖的IP列,就是每個pod ip,可以看到同一宿主機下Pod在同網段(后面我會介紹不同的node下的Pod,是如何借助flannel來實現跨主機通訊的)
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
business-manager ClusterIP 10.254.80.22 <none> 80/TCP 156m
data-product ClusterIP 10.254.116.224 <none> 50051/TCP 159m
kubernetes ClusterIP 10.254.0.1 <none> 443/TCP 5h8m
Cluster ip:k8s分配給每個service的全局唯一的虛擬ip,也可以叫VIP。VIP沒有掛接到網絡設備,不能直接訪問。(后面會介紹這個ip的用處)
除了上面的3個主要ip,集群里還有其他的一些特定的ip和網段:
• DNS服務器:這里配置的是10.254.0.2:53
• 10.254.0.0/16網段,是可配置的當前集群的網段,DNS和service的虛擬Ip正是處在這個網段里。
3 Docker0網橋和flannel網絡方案
在介紹Ingress和service這兩個組件之前,我們先簡單了解一下k8s節點之間的底層網絡原理及典型的flannel-VXLAN方案。后面的章節,默認在節點之間的傳輸,都會有docker0網橋和flannel插件的功勞。(有資料提到K8S采用cni0網橋替代了docker0網橋,兩者的原理是一樣的,我搭建的環境里只有docker0網橋,所以我們按docker0來分析)
# kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE
business-manager-666f454f7f-7l86b 1/1 Running 1 11m 172.30.76.7 192.168.0.21
business-manager-666f454f7f-h5tvw 1/1 Running 1 11m 172.30.76.6 192.168.0.21
business-manager-666f454f7f-zxmsx 1/1 Running 0 8s 172.30.9.3 192.168.0.22
data-product-6664c6dcb9-4zk27 1/1 Running 1 11m 172.30.76.5 192.168.0.21
data-product-6664c6dcb9-7bn7p 1/1 Running 1 11m 172.30.76.3 192.168.0.21
data-product-6664c6dcb9-tkmms 1/1 Running 0 5m39s 172.30.9.2 192.168.0.22
大家注意到沒有,每個pod具備不同的Ip(這里指k8s集群內可訪問的虛擬ip),不同node下的pod甚至在不同的網段。那么問題來了,集群內不同IP、不同網段的節點是怎么實現通訊的呢?這樣歸功於docker0和flannel.1這兩個虛擬網絡設備,我們先ifconfig查看一下:
# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450
inet 172.30.76.1 netmask 255.255.255.0 broadcast 172.30.76.255
inet6 fe80::42:67ff:fe05:b530 prefixlen 64 scopeid 0x20<link>
ether 02:42:67:05:b5:30 txqueuelen 0 (Ethernet)
RX packets 31332 bytes 2136665 (2.0 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 21146 bytes 2125957 (2.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.0.21 netmask 255.255.255.0 broadcast 192.168.0.255
inet6 fe80::d34:64ee:27c8:3713 prefixlen 64 scopeid 0x20<link>
ether 00:15:5d:02:b2:00 txqueuelen 1000 (Ethernet)
RX packets 1588685 bytes 265883182 (253.5 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1604521 bytes 211279156 (201.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
flannel.1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1450
inet 172.30.21.0 netmask 255.255.255.255 broadcast 0.0.0.0
inet6 fe80::8822:81ff:fe5e:d8b7 prefixlen 64 scopeid 0x20<link>
ether 8a:22:81:5e:d8:b7 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 8 overruns 0 carrier 0 collisions 0
...
部署flannel和docker后,會在宿主機上創建上述兩個網絡設備。接下來我們通過一個示意圖來了解這兩個設備的工作:

• K8s在每個宿主機(node)上創建了cni0網橋(這篇文檔對應的集群環境采用的是docker0網橋,原理一樣):容器的網關,實際指向的是這個網橋。
• Flannel則在每個宿主機上創建了一個VTEP(虛擬隧道端點)設備flannel.1。
現在我們來分析下docker0和flannel.1是怎么實現跨主機通訊的(由node1的business-manager:172.30.76.7發往node2的data-product:172.30.9.2):
# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default gateway 0.0.0.0 UG 100 0 0 eth0
172.30.0.0 0.0.0.0 255.255.0.0 U 0 0 0 flannel.1
172.30.76.0 0.0.0.0 255.255.255.0 U 0 0 0 docker0
192.168.0.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0
- 上圖是node1的路由表:第2行表示凡是發往172.30.0.0/16網段的包均交給node1-flannel.1設備處理;第3行表示凡是發往172.30.76.0/8網段的包均交給node1-docker0網橋處理。
- 於是business- manager的請求,首先到達node1-docker0網橋,目的地址是172.30.9.2,只能匹配第2條規則,請求被交給node1-flannel.1設備。
- node1-flannel.1又如何處理呢?請看下圖,展示的是flannel.1的ARP表:
# ip neigh show dev flannel.1
172.30.9.2 lladdr 96:8f:2d:49:c5:31 REACHABLE
172.30.9.1 lladdr 96:8f:2d:49:c5:31 REACHABLE
172.30.9.0 lladdr 96:8f:2d:49:c5:31 STALE
- node1-flannel.1的ARP表記錄的是ip和對應節點上的flannel.1設備mac的映射。於是發往172.30.9.2匹配到了上述第1條規則,需要發往mac地址為96:8f:2d:49:c5:31的設備。
# bridge fdb show flannel.1 |grep 96:8f:2d:49:c5:31
96:8f:2d:49:c5:31 dev flannel.1 dst 192.168.0.22 self permanent
- 這時候node1-flannel.1設備又扮演一個網橋的角色,上圖為node1上查詢出的橋接規則,96:8f:2d:49:c5:31的目的ip對應於192.168.0.22,這正是我們這個例子里node2的宿主機Ip。於是這個請求被轉發給了node2。
- 不難理解,node2也有一個像第1步那樣的路由表,於是來自node1-business-manager:172.30.76.7的請求最終經node2-docker0送達node2-data-product:172.30.9.2。
• 隨着node和pod加入和退出集群,flannel進程會從ETCD感知相應的變化,並及時更新上面的規則。
• 現在我們已實現通過ip訪問pod,但pod的ip隨着k8s調度會變化,不可能隔三差五的去人工更新每個ip配置吧,這就需要service這個組件了,請看下一章。
4 Service和DNS
4.1 service
pod的ip不是固定的,而且同一服務的多個pod需要有負載均衡,這正是創建service的目的。
Service是由kube-proxy組件和iptables來共同實現的。
分析service原理前,大家可以先帶上這個問題:service的ip為什么ping不通?
OK,我們現在直接上圖,隨便一個node的iptables(內容比較豐富,我隨便截了幾段,下文會挑幾個重要的規則展開分析):
# iptables-save
...
-A KUBE-FIREWALL -m comment --comment "kubernetes firewall for dropping marked packets" -m mark --mark 0x8000/0x8000 -j DROP
-A KUBE-FORWARD -m comment --comment "kubernetes forwarding rules" -m mark --mark 0x4000/0x4000 -j ACCEPT
-A KUBE-FORWARD -s 10.254.0.0/16 -m comment --comment "kubernetes forwarding conntrack pod source rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A KUBE-FORWARD -d 10.254.0.0/16 -m comment --comment "kubernetes forwarding conntrack pod destination rule" -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A KUBE-SERVICES -d 10.254.0.2/32 -p tcp -m comment --comment "kube-system/kube-dns:dns-tcp has no endpoints" -m tcp --dport 53 -j REJECT --reject-with icmp-port-unreachable
-A KUBE-SERVICES -d 10.254.0.2/32 -p udp -m comment --comment "kube-system/kube-dns:dns has no endpoints" -m udp --dport 53 -j REJECT --reject-with icmp-port-unreachable
...
-A KUBE-MARK-DROP -j MARK --set-xmark 0x8000/0x8000
-A KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE
-A KUBE-SEP-CNIAJ35IU3EJ7UR6 -s 172.30.9.3/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-CNIAJ35IU3EJ7UR6 -p tcp -m tcp -j DNAT --to-destination 172.30.9.3:8080
-A KUBE-SEP-DGXT5Z3WOYVLBGRM -s 172.30.76.3/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-DGXT5Z3WOYVLBGRM -p tcp -m tcp -j DNAT --to-destination 172.30.76.3:50051
...
-A KUBE-SERVICES -d 10.254.80.22/32 -p tcp -m comment --comment "default/business-manager:business-manager cluster IP" -m tcp --dport 80 -j KUBE-SVC-FZ5DC5B5DCQ4E7RC
-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS
-A KUBE-SVC-45TXGSBX3LGQQRTB -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-DGXT5Z3WOYVLBGRM
-A KUBE-SVC-45TXGSBX3LGQQRTB -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-P6GCAAVN4MLBXK7I
-A KUBE-SVC-45TXGSBX3LGQQRTB -j KUBE-SEP-QFJ7ESRM37V67WJQ
...
現在可以回答service ip ping不通的問題了,因為service不是真實存在的(沒有掛接具體的網絡設備),而是由上圖這些iptables規則組成的一個虛擬的服務。
• Iptables是linux內核提供給用戶的可配置的網絡層防火牆規則,內核在解析網絡層ip數據包時,會加入相應的檢查點,匹配iptables定義的規則。
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
business-manager ClusterIP 10.254.80.22 <none> 80/TCP 3h28m
data-product ClusterIP 10.254.116.224 <none> 50051/TCP 3h32m
kubernetes ClusterIP 10.254.0.1 <none> 443/TCP 6h
• 我們還是看第3章的例子,business-manager要訪問data-product,於是往service-data-product的ip和port(10.254.116.224:50051)發送請求。每個service對象被創建時,k8s均會分配一個集群內唯一的ip給它,並且該ip伴隨service的生命周期不會變化,這就解決了本節開篇的Pod ip不固定的問題。
-A KUBE-SERVICES -d 10.254.116.224/32 -p tcp -m comment --comment "default/data-product:data-product cluster IP" -m tcp --dport 50051 -j KUBE-SVC-45TXGSBX3LGQQRTB
• KUBE-SERVICES:Iptables表里存在上面這條規則,表示發往10.254.116.224:50051的數據包,跳轉到KUBE-SVC-45TXGSBX3LGQQRTB規則。
-A KUBE-SVC-45TXGSBX3LGQQRTB -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-DGXT5Z3WOYVLBGRM
-A KUBE-SVC-45TXGSBX3LGQQRTB -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-P6GCAAVN4MLBXK7I
-A KUBE-SVC-45TXGSBX3LGQQRTB -j KUBE-SEP-QFJ7ESRM37V67WJQ
• KUBE-SVC-xxx:這條規則,實際上是一條規則鏈,data-product我建了3個pod,所以這條規則鏈對應的正是這3個pod。這里是service負載均衡的關鍵實現,第1條規則表示采用隨機模式,有1/3(33%)的概率跳轉到KUBE-SEP-DGXT5Z3WOYVLBGRM;第2條規則的概率是1/2(50%);第3條則直接跳轉。這里有個需要注意的地方,iptables是順序往下匹配的,所以多節點隨機算法,概率是遞增的,以data-product為例,我配置了3個Pod,就有3條規則,第1條被選中的概率為1/3,第2條則為1/2,最后1條沒得挑了,概率配置為1或直接跳轉。
-A KUBE-SEP-P6GCAAVN4MLBXK7I -s 172.30.76.5/32 -j KUBE-MARK-MASQ
-A KUBE-SEP-P6GCAAVN4MLBXK7I -p tcp -m tcp -j DNAT --to-destination 172.30.76.5:50051
• KUBE-SEP-xxx:假設隨機到第2條KUBE-SEP-P6GCAAVN4MLBXK7I,這里又是兩條規則。第1條是給轉發的數據包加標簽Mark,目的是在集群多入口的場景下,保證數據包從哪進來的就從哪個node返回給客戶端,詳細原理就不展開說了。同時這里還涉及到一個技術點,經過service轉發的數據包,pod只能追查到轉發的service所在的Node,如果有場景需要Pod明確知道外部client的源Ip,可以借用service的spec.externalTrafficPolicy=local字段實現。
• KUBE-SEP-xxx:第2條規則就很簡單了,數據包轉發給172.30.76.5:50051,這里已經拿到pod的ip和port,可以通過第3章的docker0和flannel.1網絡進行通信了。
上面是基於iptables的service方案,存在一個風險,當pod數量很大,幾百、幾千時,遍歷iptables將會是性能瓶頸。IPVS虛擬網卡技術在大量級的pod場景下表現比iptables優秀(運維的同事反饋11版本的k8s,官方已默認采用IPVS)。這不屬於本文檔的目的,不展開說。
本節開頭我們提到service是由kube-proxy和iptables共同實現的,所以Kube-proxy所扮演的角色就不難想象了,kube-proxy負責感知集群的變化,及時更新service的規則。
最后,我們還面臨着一個小問題,上面的過程是基於服務的VIP的訪問服務的,通過服務名的方式訪問又是怎么實現的呢,請看下一節:DNS
4.2 DNS
本來寫這個文檔沒想到要有DNS這一章節的,但集群搭建好之后發現通過服務名無法訪問服務,通過VIP卻可以,才想起來集群還需要額外搭個DNS組件。
# kubectl get po -n kube-system
NAME READY STATUS RESTARTS AGE
kube-dns-7cd94476cd-kr76t 4/4 Running 0 25s
DNS組件是跑在kube-system命名空間下的一個pod,監聽着集群ip:10.254.0.2:53。通過這個Ip:port(創建kubelet時指定DNS的ip)即可獲取到集群內部的DNS解析服務。
現在我們隨便進入一個pod里,可以看到dns的信息已被k8s寫入。同時我們ping一個service:
# cat /etc/resolv.conf
nameserver 10.254.0.2
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
# ping data-product.default.svc.cluster.local
PING data-product.default.svc.cluster.local (10.254.116.224) 56(84) bytes of data.
^C
--- data-product.default.svc.cluster.local ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 1999ms
當然是ping不通的,但vip已經被解析出來了。
Kubenetes可以為pod提供穩定的DNS名字,且這個名字可通過pod名和service名拼接出來,以上面的data-product為例,該服務的完整域名是[服務名].[命名空間].svc.[集群名稱]。相應的,每個pod也有類似規則的域名。
5 外部訪問集群
5.1 外部訪問service
Service代理的是集群內部的ip和端口,出了集群這個ip:port就沒什么意義了。所以如何在集群外部訪問到service呢?
方式一:配置service的type=NodePort,此方式下k8s會給service做端口映射。這種方式是最常用的,我們DEV環境下很多service做了端口映射,可以通過宿主機Ip加映射出去的端口號直接訪問服務。這種方式的原理簡單,kube-proxy只需要在iptables里增加一條規則,將外部端口的包導向第4章的service規則去處理即可。(下一節要講的ingress,正是這種方式的一種更細致的實現)
方式二:type=LoadBalancer,適用於公有雲提供的K8s環境,此時K8s使用一個叫作CloudProvider的轉接層與公有雲的API交互,並由公有雲API來實現負載均衡。
方式三:type=ExternalName,這個方式的用法我還沒搞清楚。
按前面章節的套路,這里我們依然會面臨一個小問題,把外部需要訪問的服務大量的通過端口映射方式暴露出去,勢必給端口的管理帶來麻煩。所以,接下來我們看看ingress是怎么作為集群的入口,幫我們管理后端服務的。
5.2 ingress
4.2章節,在集群內部我們實現了通過域名(服務名)獲取具體的服務vip,從而免去了管理Vip煩惱。那么從外部訪問集群的服務,又如何實現通過域名的方式呢?后端的服務有很多,我們也需要一個全局的負載均衡器來管理后面服務。這就是ingress。
# kubectl get po -n ingress-nginx
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-546bfbff9-hpwsz 1/1 Running 0 84s
• 使用ingress,我們除了要創建ingress對象以外,還需要安裝一個ingress-controller,這里我們選擇最常用的nginx-ingress-controller。如上所示,安裝之后,會增加一個ingress-nginx命名空間,運行着nginx-ingress-controller容器。
# kubectl exec -ti nginx-ingress-controller-546bfbff9-hpwsz sh -n ingress-nginx
$ more /etc/nginx/nginx.conf
...
## start server data-product
server {
server_name data-product ;
listen 80;
set $proxy_upstream_name "-";
location / {
set $namespace "default";
set $ingress_name "data-product";
set $service_name "data-product";
set $service_port "50051";
set $location_path "/";
...
• 當Ingress對象被創建時,nginx-ingress-controller會在這個nginx容器內部生成一個配置文件/etc/nginx/nginx.conf(內容比較豐富,上圖我截了一小段,可以看到data-product.default的主要配置),並用這個文件啟動nginx服務。當ingress對象被更新時,nginx-ingress-controller會實現nginx服務的動態更新。
# cat ing.yaml
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: business-user
namespace: ns-jo
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: business-user.ns-jo
http:
paths:
- path: /
backend:
serviceName: business-user
servicePort: 80
• Nginx服務的功能:隨便找一個ingress文件查看,rules字段包含一組域名、路徑、后端服務名、服務端口的映射,這就是個反向代理的配置文件。當前我們用nginx做反向代理,以及將請求負載給后端的service。加上證書,nginx還可以解析https,給后端依然是http明文通信
現在又面臨一個小問題了,這個nginx服務居然運行在容器里,參考5.1章節,這個服務外部還是訪問不了啊?所以安裝nginx-ingress-controller時還需要創建一個服務,將這個pod里的nginx服務監聽的80和443端口暴露出去。
# kubectl describe svc ingress-nginx -n ingress-nginx
Name: ingress-nginx
Namespace: ingress-nginx
Labels: app.kubernetes.io/name=ingress-nginx
app.kubernetes.io/part-of=ingress-nginx
Annotations: <none>
Selector: app.kubernetes.io/name=ingress-nginx,app.kubernetes.io/part-of=ingress-nginx
Type: NodePort
IP: 10.254.189.164
Port: http 80/TCP
TargetPort: 80/TCP
NodePort: http 30799/TCP
Endpoints: 172.30.76.2:80
Port: https 443/TCP
TargetPort: 443/TCP
NodePort: https 31522/TCP
Endpoints: 172.30.76.2:443
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
上面這個服務,正是ingress-nginx的SVC,它向外暴露的端口(NodePort)是30799和31522,對應的endpoints正是nginx容器里的nginx服務監聽的兩個端口80和433。這個ingress-service加上ingress-nginx容器,共同組成了ingress。所以廣義上,ingress提供的是集群入口服務,是一個虛擬的概念。不考慮具體的功能的話,business層以NodePort方式運作時,就可以看作business層就是data層的ingress。
現在我們可以用business-manager.default:30799/api/v1/product/list來發起請求。
附 擴展實戰
原理分析的再多再深入,最終還是希望能夠為我們的工作提供一些幫助。所以下面的篇幅我記錄了在分析過程中看到或是想到的可能有助於我們實際工作的思路,限於精力有限,這些思路我暫時還沒有完整驗證過,同學們有興趣的話可以參與進來。
附A 用service實現DB的管理
當前DB的ip和端口是配置在每個應用的configmap里的,如果出現DB切換、遷移等因素導致IP或端口變更,我們需要挨個去修改每個應用的config。
K8s支持指定service的endpoints為一個特定的點,比如可以指定為DB的IP和端口。這樣我們可以創建兩個service:service-DB-read,和service-DB-write。由service來管理DB的IP和PORT,變更只需要修改這兩個service的config即可。由4.1章節的分析我們知道,應用訪問上述兩個service,數據包會被轉發給endpoints也就是真正的db。
請見下圖,Endpoints指向集群外部數據庫的service-mysql:
# kubectl describe svc mysql
Name: mysql
Namespace: default
Labels: <none>
Annotations: <none>
Selector: <none>
Type: ClusterIP
IP: 10.254.84.209
Port: <unset> 3306/TCP
TargetPort: 3306/TCP
Endpoints: 192.168.0.103:3306
Session Affinity: None
Events: <none>
應用層通過訪問service-mysql,流量最終會到達endpoints也就是集群外部的真實數據庫的ip:port。細心的同學應該能想到,這玩意可以用於簡單的數據庫負載均衡,比如有多個讀庫的情況下,我們只需要讓service-mysql的endpoints指向這幾個讀庫,流量即能被負載均衡到各個庫。
附B 用NetworkPolicy實現訪問權限隔離
以DB為例,當前集群的DB對所有pod開放,那有沒有辦法限制訪問權限呢,比如只允許data層訪問。回想第4.1章節service的本質是iptables規則,那么就有可能通過iptables實現更細致的規則,比如DB的訪問權限管理。這就是k8s的NetworkPolicy,支持以pod的標簽的形式制定相應的iptables規則。目前flannel網絡插件不支持NetworkPolicy,flannel + Calico插件可以實現。
