Kubernetes:網(wǎng)絡(luò)

Kubernetest網(wǎng)絡(luò)

各容器之間的網(wǎng)絡(luò)交互

一個(gè)容器想要與外界做到互通就需要一套網(wǎng)絡(luò)棧也就是它發(fā)出、響應(yīng)網(wǎng)絡(luò)請(qǐng)求的基本環(huán)境,這其中就包括網(wǎng)卡、回環(huán)設(shè)備、路由表和iptables規(guī)則。

交互方式

本機(jī)容器通信

  1. Docker容器通過在宿主機(jī)上創(chuàng)建一個(gè)名字是docker0的網(wǎng)橋,來使連接到網(wǎng)橋上的容器進(jìn)行通信
    1. 主要是通過一個(gè)叫Veth Pair的虛擬設(shè)備實(shí)現(xiàn)(這個(gè)虛擬設(shè)備總是成對(duì)出現(xiàn)的,當(dāng)其中一個(gè)網(wǎng)卡發(fā)出請(qǐng)求時(shí),另外一個(gè)就能接受到請(qǐng)求)
    2. 無論這兩個(gè)設(shè)備是否在同一個(gè)network space,就相當(dāng)于網(wǎng)線連接
    3. 原理無外乎使用etho網(wǎng)卡做ARP廣播,從而通過IP找到Mac地址

跨主通信

  1. 本機(jī)交互通信不過是讓宿主機(jī)作媒介連接多個(gè)容器網(wǎng)絡(luò),那跨多個(gè)宿主機(jī)呢?
  2. 很容易想到的是在容器網(wǎng)絡(luò)的再搭建一層網(wǎng)絡(luò),只要實(shí)現(xiàn)這層網(wǎng)絡(luò)的相互通信也就解決了各個(gè)宿主機(jī)容器間的網(wǎng)絡(luò)通信問題。
跨主通信實(shí)現(xiàn)方式
  1. 舉個(gè)例子比如當(dāng)前宿主機(jī)A上有容器C1想要訪問到宿主機(jī)B上的容器C2
  2. 首先C1發(fā)出請(qǐng)求,需要訪問IP為1.1.1.2的C2容器
  3. 請(qǐng)求先是到達(dá)A,A上的docker0網(wǎng)橋沒有這個(gè)網(wǎng)段,從而把這個(gè)請(qǐng)求的選擇權(quán)交給宿主機(jī)A的iptables
  4. 這個(gè)時(shí)候 我們在iptables中預(yù)先創(chuàng)建好一系列路由規(guī)則然后將這個(gè)請(qǐng)求發(fā)往C2所在的宿主機(jī)就好了
  5. 那么如何預(yù)先創(chuàng)建好路由規(guī)則呢?,在K8s中所有容器其實(shí)都是其宿主機(jī)的一個(gè)子網(wǎng),比如A的子網(wǎng)是1.1.2.0/24,C1的IP就是1.1.2.1這樣子,所以就可以通過IP找到宿主機(jī)B,從而找到對(duì)應(yīng)的C2容器
  6. 而這個(gè)關(guān)系又保存在Etcd中,我們只需要監(jiān)聽Etcd中IP規(guī)則的變化,實(shí)時(shí)更新iptables就好了
下面是 Flannel UDP模式的跨主通信的原理圖
image
  • 雖然UDP方案的跨主通信因?yàn)樾阅軉栴}已經(jīng)被拋棄(用戶態(tài)內(nèi)核態(tài)切換過多、需要三次數(shù)據(jù)來回拷貝),但卻值得學(xué)習(xí)
    1. 除此之外Flannel項(xiàng)目還有兩個(gè)跨主通信的解決方案VXLAN(virtual Extensible LAN)、host-gw(host-gateway)

K8s網(wǎng)絡(luò)模型與CNI

  1. K8s中使用CNI網(wǎng)橋來替代了docker0網(wǎng)橋,替換的原因有兩點(diǎn):
    1. K8s沒有使用Docker的網(wǎng)絡(luò)模型,也就沒有docker0網(wǎng)橋
    2. CNI與K8s配置pod的網(wǎng)絡(luò)環(huán)境密切相關(guān)(即Infra 容器的 network namespace)
  2. 通過CNI樣式的插件構(gòu)建K8s網(wǎng)絡(luò)能實(shí)現(xiàn)各個(gè)容器、宿主機(jī)之間直接使用IP通信,實(shí)現(xiàn)的效果是在容器內(nèi)訪問容器的IP與其他容器訪問容器的IP都是一模一樣的,總之實(shí)現(xiàn)的就是實(shí)現(xiàn) 互通。

容器之間的網(wǎng)絡(luò)隔離 - NetworkPolicy

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default
spec:
  # 定義NetworkPolicy限制范圍 --黑名單,所有role是xxx1的Pod都被拒絕,如果留空就是這個(gè)ns下的所有Pod
  podSelector:
    matchLabels:
      role: xxx1
  # 限制類型是流入或流出,下面定義的都是白名單
  policyTypes:
  - Ingress
  - Egress
  # 接受下面定義流入的ip比如1.1.0.0/16,拒絕1.1.1.0/24以及其他所有請(qǐng)求
  # 流入
  ingress:
  - from:
    - ipBlock:
        cidr: 1.1.0.0/16
        except:
        - 1.1.1.0/24
    - namespaceSelector:
        matchLabels:
          project: testPro
    - podSelector:  
        matchLabels:
          role: test
    ports:
    - protocol: TCP
      port: 6379
  # 流入
  egress:
  - to:
    - ipBlock:
        cidr: 100.0.0.0/24
    ports:
    - protocol: TCP
      port: 5978
NetworkPolicy實(shí)現(xiàn)原理
  1. 實(shí)際上就是在宿主機(jī)上生成一系列特定iptables規(guī)則。這和安全組非常類似
  2. 一般來說,我們哪些地方需要NetworkPolicy,比如:job,cronjob這種計(jì)算型Pod不需要也不應(yīng)該對(duì)外提供服務(wù),所以就需要拒絕掉所有訪問它們的流量,從而提升系統(tǒng)安全。

Service實(shí)現(xiàn)原理

kube-proxy + iptables
  1. 當(dāng)Service被添加到K8s時(shí),kube-proxy就會(huì)在宿主機(jī)上創(chuàng)建一條iptables規(guī)則集合
  2. 這個(gè)集合中就包含了Service所代理的所有Pod
  3. 同樣Service的負(fù)載均衡也是在這里實(shí)現(xiàn)的
  4. 在訪問Service的請(qǐng)求到來后,路由前,K8s會(huì)將流入的IP和端口通過iptables上的信息改成真是的目的IP與端口,也就是真是Pod的IP與Port
ipvs
  1. iptables維護(hù)路由規(guī)則的方式實(shí)際上有很大的性能開銷,當(dāng)有大量Pod的時(shí)候,需要去維護(hù)很多的iptables規(guī)則,不斷刷新這些規(guī)則
  2. ipvc則不需要維護(hù)如此多的iptables規(guī)則,而是將規(guī)則的處理移動(dòng)到了內(nèi)核態(tài),從而降低了開銷
  3. 雖然其也需要iptables來做包過濾等操作,但所需的規(guī)則數(shù)量都是有限的,而不是隨著Pod增加而增加。時(shí)刻保持訪問Pod iptables規(guī)則的最新狀態(tài)

如何訪問Service - NodePort、LoadBalancer service、ExternalName

NodePort
apiVersion: v1
kind: Service
metadata:
  name: test
  labels:
    run: test
spec:
  type: NodePort
  ports:
  # 聲明8080代理Pod的80端口
  - nodePort: 8080
    targetPort: 80
    protocol: TCP
    name: http
  - nodePort: 443
    protocol: TCP
    name: https
  selector:
    run: test-pod
  1. 這個(gè)時(shí)候使用 宿主機(jī)IP + 8080就可以訪問了
  2. 當(dāng)定義了這樣一個(gè)文件后,kube-proxy同樣也是生成一條iptables規(guī)則,讓它能路由到具體Service上
  3. 這里需要注意的是在請(qǐng)求結(jié)束后,kube-proxy會(huì)給這個(gè)IP包進(jìn)行一次SNAT操作,他會(huì)將這個(gè)IP包的源地址替換成當(dāng)前宿主機(jī)的CNI網(wǎng)橋地址
  4. 這里為什么會(huì)有這一次SNAT操作呢?比如外部請(qǐng)求訪問了node1,然后這個(gè)請(qǐng)求又被路由到node2上,當(dāng)node2處理完成后開始進(jìn)行回復(fù),那回復(fù)肯定要先回復(fù)到1上,然后1在回復(fù)到客戶端(收到回復(fù)是不同主機(jī),客戶端可能會(huì)報(bào)錯(cuò))
LoadBalancer類型的 Service
kind: Service
apiVersion: v1
metadata:
  name: test-service
spec:
  ports:
  - port: 8765
    targetPort: 9376
  selector:
    app: test-app
  type: LoadBalancer

對(duì)于LoadBalancer類型的 Service,Kubernetes 會(huì)調(diào)用 CloudProvider 在公有云上創(chuàng)建一個(gè)負(fù)載均衡服務(wù),并且把被代理的 Pod 的 IP 地址配置給負(fù)載均衡服務(wù)做后端。

ExternalName
kind: Service
apiVersion: v1
metadata:
  name: test-service
spec:
  type: ExternalName
  externalName: my.test.com

這個(gè)時(shí)候訪問test-service.default.svc.cluster.local的時(shí)候返回的就是my.test.com

萬變不離其宗

  1. Service其實(shí)就是 Kubernetes 為 Pod 分配的、固定的、基于 iptables(或者 IPVS)的訪問入口。而這些訪問入口代理的 Pod 信息,則來自于 Etcd,由 kube-proxy 通過控制循環(huán)來維護(hù)。
  2. 所以通過分析Service在宿主機(jī)上的iptables就能解決大多數(shù)問題(比如當(dāng)service沒法通過DNS訪問時(shí),就可以檢查K8smaster節(jié)點(diǎn)和Service DNS是否異常)

訪問Service的Service - Ingress

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-ingress
spec:
  tls:
  - hosts:
    - test.com
    secretName: test-secret
  rules:
  - host: test.com
    http:
      paths:
      - path: /path1
        backend:
          serviceName: svc1
          servicePort: 80
      - path: /path2
        backend:
          serviceName: svc2
          servicePort: 80
  1. 其實(shí)Ingress就是對(duì)K8s做的一個(gè)反向代理。
  2. 上面的Ingress定義的文件就把 svc1svc2進(jìn)行了代理,當(dāng)訪問path1時(shí),能路由到svc1
  3. 比如常用的nginx,官方維護(hù)的nginx-ingress-controller能根據(jù)Ingress與service的變化動(dòng)態(tài)更新Nginx負(fù)載均衡器
  4. 當(dāng)然請(qǐng)求的時(shí)候,如果沒有任何一個(gè)IngressRule被匹配到,拿nginx-ingress-controller來說就會(huì)返回一個(gè)Nginx的404頁面(也可以自己配置,比如專門啟一個(gè)Pod用來返回404頁面)
參考:

《深入剖析Kubernetes》 - 張磊

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容