1. 程式人生 > >Kubernetes技術分析之網路

Kubernetes技術分析之網路

概述

Docker的流行激活了一直不溫不火的PaaS,隨著而來的是各類Micro-PaaS的出現,Kubernetes是其中最具代表性的一員,它是Google多年大規模容器管理技術的開源版本。本系列文章將逐一分析Kubernetes,本文說明 Kubernetes網路模型的特點和實現方式。

Kubernetes網路

Kubernetes採用扁平化的網路模型,每個Pod都有一個全域性唯一的IP(IP-per-pod),Pod之間可以跨主機通訊,相比於Docker原生的NAT方式來說,這樣使得容器在網路層面更像虛擬機器或者物理機,複雜度整體降低,更加容易實現服務發現,遷移,負載均衡等功能。
為了實現這個目標,Kubernetes中需要解決4個問題:

容器間通訊

Pod是容器的集合,Pod包含的容器都執行在同一個Host上,並且擁有同樣的網路空間。現在建立一個Pod,包含2個Container:
web-pod.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: webpod
  labels:
    name: webpod
spec:
  containers:
    - name: webpod80
      image: jonlangemak/docker:web_container_80
      ports:
        - containerPort: 80
hostPort: 80 - name: webpod8080 image: jonlangemak/docker:web_container_8080 ports: - containerPort: 8080 hostPort: 8080

Pod執行成功後,在其所在的Node上查詢容器:

$ docker ps
CONTAINER ID        IMAGE                                      PORTS                                         
63
dc7e032ab6 jonlangemak/docker:web_container_8080 4ac1a5156a04 jonlangemak/docker:web_container_80 b77896498f8f gcr.io/google_containers/pause:0.8.0 0.0.0.0:80->80/tcp, 0.0.0.0:8080->8080/tcp

可以看到運行了3個容器,其中2個這是Pod定義好的,第3個執行的容器映象 是gcr.io/google_containers/pause,它是Netowrk Container,它不做任何事情,只是用來接管Pod的網路。
通過docker inspect檢視著幾個容器的資訊,可以看出Pod中定義的容器的網路設定都集中配置在了Netowrk Container上,然後再加入Netowrk Container的網路中。這樣的好處是避免服務容器之間產生依賴,用一個簡單的容器來統一管理網路。

Pod間通訊

Pod間通訊是使用一個內部IP,這個IP即使Netowrk Container的IP。
以web-pod為例:

$ kubectl describe pod webpod
Name:      webpod
Namespace:     default
IP:    10.1.14.51
...

$ docker inspect b77896498f8f  |grep IPAddress
        "IPAddress": "10.1.14.51",

對應用來說,這個IP是應用能看到,並且是可以對外宣稱的(服務註冊,服務發現);而NAT方式,應用能看到的IP是不能對外宣稱的(必須要使用主機IP+port方式),埠本身就是稀缺資源,並且ip+port的方式,無疑增加了複雜度,這就是IP-per-pod的優勢所在。

那麼第一個問題就是,如何保證Pod的IP是全域性唯一的。其實做法也很簡單,因為Pod的IP是docker bridge分配的,不同Node之間docker bridge配置成不同的網段。
- node1: docker -d –bip=10.1.79.1/24 …
- node2: docker -d –bip=10.1.14.1/24 …
- node3: docker -d –bip=10.1.58.1/24 …

同一個Node上的Pod原生能通訊,但是不同Node之間的Pod如何通訊的,這就需要對Docker進行增強,現有的方案有Flannel,OpenVSwitch,Weave等。本文Kubernetes環境是採用Flannel。

  • Flannel
    由CoreOS團隊針對Kubernetes設計的一個覆蓋網路工具,Flannel 通過在叢集中建立一個覆蓋網路為主機設定一個子網。通過隧道協議(支援udp,vxlan)封裝容器之間的通訊報文,實現跨主機通訊。
    這裡寫圖片描述

Pod到Service通訊

Pod本身是變化的,比如當Pod發生遷移,那麼Pod的IP是變化的, 那麼Service的就是在Pod之間起到中轉和代理的作用,Service會生成一個虛擬IP, 這個虛擬IP負載均衡到後端的Pod的IP。現在為上面的web-pod建立service:
web-service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: webservice
  labels:
    name: webservice
spec:
  ports:
   - name: web-80
     port: 80
     containerPort: 80
   - name: web-8080
     port: 8080
     containerPort: 8080
  selector:
    name: webpod

然後查詢Service的VIP和後端Pod的IP:

$ kubectl describe service webservice
Name:           webservice
Namespace:      default
Labels:         name=webservice
Selector:       name=webpod
Type:           ClusterIP
IP:             10.254.85.33
Port:           web-80  80/TCP
Endpoints:      10.1.14.51:80
Port:           web-8080    8080/TCP
Endpoints:      10.1.14.51:8080
Session Affinity:   None
No events.                                                        

那麼訪問web-pod則可以通過10.254.85.33。這主要是Kube-Proxy在其作用,在每臺Node上都會部署一個Kube-Proxy,Kube-Proxy對於每個Service會啟用埠監聽,並配合iptables定向到該埠,現在在一臺Node上查詢:

$ iptables-save
...
-A KUBE-PORTALS-HOST -d 10.254.85.33/32 -p tcp -m comment --comment "default/webservice:web-80" -m tcp --dport 80 -j DNAT --to-destination 192.168.3.146:56610
-A KUBE-PORTALS-HOST -d 10.254.85.33/32 -p tcp -m comment --comment "default/webservice:web-8080" -m tcp --dport 8080 -j DNAT --to-destination 192.168.3.146:50871  

對於Web-Service,Kube-Proxy建立2條iptables規則:
1.目的IP為10.254.85.33,目的埠為80的報文DNAT到192.168.3.146:56610
2.目的IP為10.254.85.33,目的埠為8080的報文DNAT到192.168.3.146: 50871

$ lsof -i:56610
COMMAND    PID USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
kube-prox 2537 root   16u  IPv6 26353463      0t0  TCP *:56610 (LISTEN)
$  lsof -i:50871
COMMAND    PID USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
kube-prox 2537 root   17u  IPv6 26353485      0t0  TCP *:50871 (LISTEN)

可以看到Kube-Proxy監聽在56610和50871,對於訪問的報文將轉發到後端Pod。對於Pod的變化,Kube-Proxy會及時重新整理。
這裡寫圖片描述
還需要注意的是,當前Kube-Proxy只是3層”(TCP/UDP over IP) 轉發,當後端有多個Pod的時候,Kube-Proxy預設採用輪詢方式進行選擇,也可以設定成基於CLientIP的會話保持。

外網到內網的通訊

目前為止,以上部分都是在討論Kubernetes內部網路的通訊,但是外網如何訪問到Kubernetes上的應用,因為內網的IP是無法直接訪問的(需要KubeProxy和Flannel的工作),這時候就需要一個外部路由模組來連線外網和內網。

參考

作者簡介

吳龍輝,現任網宿科技高階運營工程師,致力於雲端計算PaaS的研究和實踐,活躍於CloudFoundry,Docker,Kubernetes等開源社群,貢獻程式碼和撰寫技術文件。
郵箱:[email protected]/[email protected]