1 典型的數(shù)據(jù)傳輸流程圖· 一個外部的business-manager請求,,首先進入集群的入口(ingress),,ingress反向代理后負載到business-manager的service。Service層再負載到某個node下的具體的business-manager pod · Business-manager pod再將請求發(fā)往data-product的service,,同理,service層繼續(xù)隨機選擇一個data-product的Pod來接收請求 · 上面這個請求,,涉及到容器的網(wǎng)絡(luò)-docker0、跨主機通訊-flannel網(wǎng)絡(luò)方案,、ingress和service組件,以及DNS等,,下面我會挨個介紹它們的基本原理。 2 3種ip說明寫這個文檔的同時,,我在虛擬機上搭建了一個K8S環(huán)境,,集群內(nèi)包含2臺主機,ip分別為192.168.0.21和192.168.0.22,,主要組件為ingress->nginx,、service->kube-proxy,、網(wǎng)絡(luò)->flannel,,我們以這個集群為例進行分析。 在深入之前,,我們先科普一下K8S集群內(nèi)常見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,,可以看到現(xiàn)在集群內(nèi)2臺主機都有分配容器,。 Pod ip:被docker0網(wǎng)橋隔離的pod子網(wǎng)的ip。K8s在每個Node里虛擬出的局域網(wǎng),。上圖的IP列,,就是每個pod ip,可以看到同一宿主機下Pod在同網(wǎng)段(后面我會介紹不同的node下的Pod,,是如何借助flannel來實現(xiàn)跨主機通訊的) # 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沒有掛接到網(wǎng)絡(luò)設(shè)備,,不能直接訪問,。(后面會介紹這個ip的用處) 除了上面的3個主要ip,集群里還有其他的一些特定的ip和網(wǎng)段: · DNS服務(wù)器:這里配置的是10.254.0.2:53 · 10.254.0.0/16網(wǎng)段,,是可配置的當前集群的網(wǎng)段,,DNS和service的虛擬Ip正是處在這個網(wǎng)段里,。 3 Docker0網(wǎng)橋和flannel網(wǎng)絡(luò)方案在介紹Ingress和service這兩個組件之前,我們先簡單了解一下k8s節(jié)點之間的底層網(wǎng)絡(luò)原理及典型的flannel-VXLAN方案,。后面的章節(jié),,默認在節(jié)點之間的傳輸,都會有docker0網(wǎng)橋和flannel插件的功勞,。(有資料提到K8S采用cni0網(wǎng)橋替代了docker0網(wǎng)橋,,兩者的原理是一樣的,我搭建的環(huán)境里只有docker0網(wǎng)橋,,所以我們按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
大家注意到?jīng)]有,每個pod具備不同的Ip(這里指k8s集群內(nèi)可訪問的虛擬ip),,不同node下的pod甚至在不同的網(wǎng)段,。那么問題來了,集群內(nèi)不同IP,、不同網(wǎng)段的節(jié)點是怎么實現(xiàn)通訊的呢,?這樣歸功于docker0和flannel.1這兩個虛擬網(wǎng)絡(luò)設(shè)備,我們先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后,,會在宿主機上創(chuàng)建上述兩個網(wǎng)絡(luò)設(shè)備,。接下來我們通過一個示意圖來了解這兩個設(shè)備的工作:
· K8s在每個宿主機(node)上創(chuàng)建了cni0網(wǎng)橋(這篇文檔對應(yīng)的集群環(huán)境采用的是docker0網(wǎng)橋,原理一樣):容器的網(wǎng)關(guān),,實際指向的是這個網(wǎng)橋,。 · Flannel則在每個宿主機上創(chuàng)建了一個VTEP(虛擬隧道端點)設(shè)備flannel.1。 現(xiàn)在我們來分析下docker0和flannel.1是怎么實現(xiàn)跨主機通訊的(由node1的business-manager:172.30.76.7發(fā)往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行表示凡是發(fā)往172.30.0.0/16網(wǎng)段的包均交給node1-flannel.1設(shè)備處理,;第3行表示凡是發(fā)往172.30.76.0/8網(wǎng)段的包均交給node1-docker0網(wǎng)橋處理,。 于是business- manager的請求,首先到達node1-docker0網(wǎng)橋,,目的地址是172.30.9.2,,只能匹配第2條規(guī)則,請求被交給node1-flannel.1設(shè)備,。 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和對應(yīng)節(jié)點上的flannel.1設(shè)備mac的映射,。于是發(fā)往172.30.9.2匹配到了上述第1條規(guī)則,,需要發(fā)往mac地址為96:8f:2d:49:c5:31的設(shè)備。
# 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設(shè)備又扮演一個網(wǎng)橋的角色,,上圖為node1上查詢出的橋接規(guī)則,,96:8f:2d:49:c5:31的目的ip對應(yīng)于192.168.0.22,這正是我們這個例子里node2的宿主機Ip,。于是這個請求被轉(zhuǎn)發(fā)給了node2,。 不難理解,,node2也有一個像第1步那樣的路由表,于是來自node1-business-manager:172.30.76.7的請求最終經(jīng)node2-docker0送達node2-data-product:172.30.9.2,。
· 隨著node和pod加入和退出集群,,flannel進程會從ETCD感知相應(yīng)的變化,并及時更新上面的規(guī)則,。 · 現(xiàn)在我們已實現(xiàn)通過ip訪問pod,,但pod的ip隨著k8s調(diào)度會變化,不可能隔三差五的去人工更新每個ip配置吧,,這就需要service這個組件了,,請看下一章。 4 Service和DNS4.1 servicepod的ip不是固定的,,而且同一服務(wù)的多個pod需要有負載均衡,,這正是創(chuàng)建service的目的。 Service是由kube-proxy組件和iptables來共同實現(xiàn)的,。 分析service原理前,,大家可以先帶上這個問題:service的ip為什么ping不通? OK,,我們現(xiàn)在直接上圖,,隨便一個node的iptables(內(nèi)容比較豐富,我隨便截了幾段,,下文會挑幾個重要的規(guī)則展開分析): # 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
...
現(xiàn)在可以回答service ip ping不通的問題了,,因為service不是真實存在的(沒有掛接具體的網(wǎng)絡(luò)設(shè)備),而是由上圖這些iptables規(guī)則組成的一個虛擬的服務(wù),。 · Iptables是linux內(nèi)核提供給用戶的可配置的網(wǎng)絡(luò)層防火墻規(guī)則,,內(nèi)核在解析網(wǎng)絡(luò)層ip數(shù)據(jù)包時,會加入相應(yīng)的檢查點,,匹配iptables定義的規(guī)則,。 # 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)發(fā)送請求,。每個service對象被創(chuàng)建時,k8s均會分配一個集群內(nèi)唯一的ip給它,,并且該ip伴隨service的生命周期不會變化,,這就解決了本節(jié)開篇的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表里存在上面這條規(guī)則,,表示發(fā)往10.254.116.224:50051的數(shù)據(jù)包,,跳轉(zhuǎn)到KUBE-SVC-45TXGSBX3LGQQRTB規(guī)則。 -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:這條規(guī)則,,實際上是一條規(guī)則鏈,,data-product我建了3個pod,,所以這條規(guī)則鏈對應(yīng)的正是這3個pod。這里是service負載均衡的關(guān)鍵實現(xiàn),,第1條規(guī)則表示采用隨機模式,,有1/3(33%)的概率跳轉(zhuǎn)到KUBE-SEP-DGXT5Z3WOYVLBGRM;第2條規(guī)則的概率是1/2(50%),;第3條則直接跳轉(zhuǎn),。這里有個需要注意的地方,iptables是順序往下匹配的,,所以多節(jié)點隨機算法,,概率是遞增的,以data-product為例,,我配置了3個Pod,,就有3條規(guī)則,第1條被選中的概率為1/3,,第2條則為1/2,最后1條沒得挑了,,概率配置為1或直接跳轉(zhuǎn),。 -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:假設(shè)隨機到第2條KUBE-SEP-P6GCAAVN4MLBXK7I,這里又是兩條規(guī)則,。第1條是給轉(zhuǎn)發(fā)的數(shù)據(jù)包加標簽Mark,,目的是在集群多入口的場景下,保證數(shù)據(jù)包從哪進來的就從哪個node返回給客戶端,,詳細原理就不展開說了,。同時這里還涉及到一個技術(shù)點,經(jīng)過service轉(zhuǎn)發(fā)的數(shù)據(jù)包,,pod只能追查到轉(zhuǎn)發(fā)的service所在的Node,,如果有場景需要Pod明確知道外部client的源Ip,可以借用service的spec.externalTrafficPolicy=local字段實現(xiàn),。 · KUBE-SEP-xxx:第2條規(guī)則就很簡單了,,數(shù)據(jù)包轉(zhuǎn)發(fā)給172.30.76.5:50051,這里已經(jīng)拿到pod的ip和port,,可以通過第3章的docker0和flannel.1網(wǎng)絡(luò)進行通信了,。 上面是基于iptables的service方案,存在一個風險,,當pod數(shù)量很大,,幾百、幾千時,,遍歷iptables將會是性能瓶頸,。IPVS虛擬網(wǎng)卡技術(shù)在大量級的pod場景下表現(xiàn)比iptables優(yōu)秀(運維的同事反饋11版本的k8s,,官方已默認采用IPVS)。這不屬于本文檔的目的,,不展開說,。 本節(jié)開頭我們提到service是由kube-proxy和iptables共同實現(xiàn)的,所以Kube-proxy所扮演的角色就不難想象了,,kube-proxy負責感知集群的變化,,及時更新service的規(guī)則。 最后,,我們還面臨著一個小問題,,上面的過程是基于服務(wù)的VIP的訪問服務(wù)的,通過服務(wù)名的方式訪問又是怎么實現(xiàn)的呢,,請看下一節(jié):DNS 4.2 DNS本來寫這個文檔沒想到要有DNS這一章節(jié)的,,但集群搭建好之后發(fā)現(xiàn)通過服務(wù)名無法訪問服務(wù),通過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,監(jiān)聽著集群ip:10.254.0.2:53,。通過這個Ip:port(創(chuàng)建kubelet時指定DNS的ip)即可獲取到集群內(nèi)部的DNS解析服務(wù),。 現(xiàn)在我們隨便進入一個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已經(jīng)被解析出來了。 Kubenetes可以為pod提供穩(wěn)定的DNS名字,,且這個名字可通過pod名和service名拼接出來,,以上面的data-product為例,該服務(wù)的完整域名是[服務(wù)名].[命名空間].svc.[集群名稱],。相應(yīng)的,,每個pod也有類似規(guī)則的域名。 5 外部訪問集群5.1 外部訪問serviceService代理的是集群內(nèi)部的ip和端口,,出了集群這個ip:port就沒什么意義了,。所以如何在集群外部訪問到service呢? 方式一:配置service的type=NodePort,,此方式下k8s會給service做端口映射,。這種方式是最常用的,我們DEV環(huán)境下很多service做了端口映射,,可以通過宿主機Ip加映射出去的端口號直接訪問服務(wù),。這種方式的原理簡單,kube-proxy只需要在iptables里增加一條規(guī)則,,將外部端口的包導向第4章的service規(guī)則去處理即可,。(下一節(jié)要講的ingress,,正是這種方式的一種更細致的實現(xiàn)) 方式二:type=LoadBalancer,適用于公有云提供的K8s環(huán)境,,此時K8s使用一個叫作CloudProvider的轉(zhuǎn)接層與公有云的API交互,,并由公有云API來實現(xiàn)負載均衡。 方式三:type=ExternalName,,這個方式的用法我還沒搞清楚,。 按前面章節(jié)的套路,這里我們依然會面臨一個小問題,,把外部需要訪問的服務(wù)大量的通過端口映射方式暴露出去,,勢必給端口的管理帶來麻煩。所以,,接下來我們看看ingress是怎么作為集群的入口,,幫我們管理后端服務(wù)的。 5.2 ingress4.2章節(jié),,在集群內(nèi)部我們實現(xiàn)了通過域名(服務(wù)名)獲取具體的服務(wù)vip,,從而免去了管理Vip煩惱。那么從外部訪問集群的服務(wù),,又如何實現(xiàn)通過域名的方式呢,?后端的服務(wù)有很多,我們也需要一個全局的負載均衡器來管理后面服務(wù),。這就是ingress,。 # kubectl get po -n ingress-nginx
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-546bfbff9-hpwsz 1/1 Running 0 84s
· 使用ingress,,我們除了要創(chuàng)建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對象被創(chuàng)建時,nginx-ingress-controller會在這個nginx容器內(nèi)部生成一個配置文件/etc/nginx/nginx.conf(內(nèi)容比較豐富,,上圖我截了一小段,,可以看到data-product.default的主要配置),并用這個文件啟動nginx服務(wù),。當ingress對象被更新時,,nginx-ingress-controller會實現(xiàn)nginx服務(wù)的動態(tài)更新。 # 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服務(wù)的功能:隨便找一個ingress文件查看,,rules字段包含一組域名,、路徑,、后端服務(wù)名、服務(wù)端口的映射,,這就是個反向代理的配置文件,。當前我們用nginx做反向代理,以及將請求負載給后端的service,。加上證書,,nginx還可以解析https,給后端依然是http明文通信 現(xiàn)在又面臨一個小問題了,,這個nginx服務(wù)居然運行在容器里,,參考5.1章節(jié),這個服務(wù)外部還是訪問不了???所以安裝nginx-ingress-controller時還需要創(chuàng)建一個服務(wù),將這個pod里的nginx服務(wù)監(jiān)聽的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>
上面這個服務(wù),,正是ingress-nginx的SVC,它向外暴露的端口(NodePort)是30799和31522,,對應(yīng)的endpoints正是nginx容器里的nginx服務(wù)監(jiān)聽的兩個端口80和433,。這個ingress-service加上ingress-nginx容器,共同組成了ingress,。所以廣義上,,ingress提供的是集群入口服務(wù),是一個虛擬的概念,。不考慮具體的功能的話,,business層以NodePort方式運作時,就可以看作business層就是data層的ingress,。 現(xiàn)在我們可以用business-manager.default:30799/api/v1/product/list來發(fā)起請求,。 附 擴展實戰(zhàn)原理分析的再多再深入,最終還是希望能夠為我們的工作提供一些幫助,。所以下面的篇幅我記錄了在分析過程中看到或是想到的可能有助于我們實際工作的思路,,限于精力有限,這些思路我暫時還沒有完整驗證過,,同學們有興趣的話可以參與進來,。 附A 用service實現(xiàn)DB的管理當前DB的ip和端口是配置在每個應(yīng)用的configmap里的,如果出現(xiàn)DB切換,、遷移等因素導致IP或端口變更,,我們需要挨個去修改每個應(yīng)用的config。 K8s支持指定service的endpoints為一個特定的點,比如可以指定為DB的IP和端口,。這樣我們可以創(chuàng)建兩個service:service-DB-read,,和service-DB-write。由service來管理DB的IP和PORT,,變更只需要修改這兩個service的config即可,。由4.1章節(jié)的分析我們知道,應(yīng)用訪問上述兩個service,,數(shù)據(jù)包會被轉(zhuǎn)發(fā)給endpoints也就是真正的db,。 請見下圖,Endpoints指向集群外部數(shù)據(jù)庫的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>
應(yīng)用層通過訪問service-mysql,,流量最終會到達endpoints也就是集群外部的真實數(shù)據(jù)庫的ip:port,。細心的同學應(yīng)該能想到,這玩意可以用于簡單的數(shù)據(jù)庫負載均衡,,比如有多個讀庫的情況下,,我們只需要讓service-mysql的endpoints指向這幾個讀庫,流量即能被負載均衡到各個庫,。 附B 用NetworkPolicy實現(xiàn)訪問權(quán)限隔離以DB為例,,當前集群的DB對所有pod開放,那有沒有辦法限制訪問權(quán)限呢,,比如只允許data層訪問,。回想第4.1章節(jié)service的本質(zhì)是iptables規(guī)則,,那么就有可能通過iptables實現(xiàn)更細致的規(guī)則,,比如DB的訪問權(quán)限管理。這就是k8s的NetworkPolicy,,支持以pod的標簽的形式制定相應(yīng)的iptables規(guī)則,。目前flannel網(wǎng)絡(luò)插件不支持NetworkPolicy,flannel Calico插件可以實現(xiàn),。 附C 用secret對象管理賬戶密碼來源:http://www./content-4-200451.html
|