在實際生產環境中,有些容器內應用(比如編碼器)需要用到物理層面的網路資源(比如組播流)。這就要求Kubernetes中的該Pod以HOST模式來啟動。以下實驗了Kubernetes-HOST網路模式,並給出了一些運維建議。
1、Pod的網路
每個Pod都會預設啟動一個pod-infrastructure(或pause)的容器,作為共享網路的基準容器。其他業務容器在啟動之後,會將自己的網路模式指定為“"NetworkMode": "container:pause_containerID”。這樣就能做到Pod中的所有容器網路都是共享的,一個Pod中的所有容器中的網路是一致的,它們能夠通過本地地址(localhost)訪問其他使用者容器的埠。在Kubernetes的網路模型中,每一個Pod都擁有一個扁平化共享網路名稱空間的IP,稱為PodIP。通過PodIP,Pod就能夠跨網路與其他物理機和容器進行通訊。
也可以設定Pod為Host網路模式,即直接使用宿主機的網路,不進行網路虛擬化隔離。這樣一來,Pod中的所有容器就直接暴露在宿主機的網路環境中,這時候,Pod的PodIP就是其所在Node的IP。從原理上來說,當設定Pod的網路為Host時,是設定了Pod中pod-infrastructure(或pause)容器的網路為Host,Pod內部其他容器的網路指向該容器。如下所示(65070affecfc61為業務容器,f60a2ee415e3為pod-infrastructure容器):
[root@k8s-node-3 ~]# docker inspect 65070affecfc6131b2385e5c40d4f21f73c343cc15e7983cdce8594e38ed020f | grep NetworkMode "NetworkMode": "container:f60a2ee415e301491f30ffc12855880273da6eded2526a5319eed72a92caef7f", [root@k8s-node-3 ~]# docker inspect f60a2ee415e301491f30ffc12855880273da6eded2526a5319eed72a92caef7f | grep NetworkMode "NetworkMode": "host", [root@k8s-node-3 ~]#
2、啟動示例
[root@k8s-master yaml]# cat test-host.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: test-host spec: replicas: 4 template: metadata: labels: name: test-host spec: containers: - name: test-host image: registry:5000/back_demon:1.0 command: - /jboss/jboss-eap-6.1/bin/standalone.sh ports: - containerPort: 8080 hostNetwork: true
3、運維經驗
3.1 副本數量
對於同Deployment下的Host模式啟動的Pod,每個node上只能啟動一個。也就是說,Host模式的Pod啟動副本數不可以多於“目標node”的數量,“目標node”指的是在啟動Pod時選定的node,若未選定(沒有指定nodeSelector),“目標node”的數量就是叢集中全部的可用的node的數量。當副本數大於“目標node”的數量時,多出來的Pod會一直處於Pending狀態,因為schedule已經找不到可以排程的node了。
以下示例中,叢集只有4個node,當設定副本數量為5時,最後一個Pod狀態會一直處於Pending狀態。
[root@k8s-master yaml]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE test-host-1108333573-11wbl 1/1 Running 0 17s 10.0.251.153 k8s-node-1 test-host-1108333573-2k35s 1/1 Running 0 17s 10.0.251.146 k8s-node-3 test-host-1108333573-lnlpy 1/1 Running 0 17s 10.0.251.222 k8s-node-4 test-host-1108333573-t6izr 1/1 Running 0 17s 10.0.251.155 k8s-node-2 test-host-1108333573-tf4mc 0/1 Pending 0 17s <none>
3.2 PodIP
Pod的PodIP就是其所在Node的IP,具體如下:
[root@k8s-master yaml]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE test-host-1108333573-11wbl 1/1 Running 0 2h 10.0.251.153 k8s-node-1 test-host-1108333573-2k35s 1/1 Running 0 2h 10.0.251.146 k8s-node-3 test-host-1108333573-lnlpy 1/1 Running 0 2h 10.0.251.222 k8s-node-4 test-host-1108333573-t6izr 1/1 Running 0 2h 10.0.251.155 k8s-node-2
雖然PodIP是NodeIP,但也可以通過service的方式加到Kubernetes的虛擬化網路中被使用。具體如下:
[root@k8s-master yaml]# cat demon1/frontend-service.yaml apiVersion: v1 kind: Service metadata: name: frontend-service labels: name: frontend-service spec: type: NodePort ports: - port: 8080 nodePort: 30002 selector: name: frontend-service [root@k8s-master yaml]# kubectl create -f test-host-svc.yaml service "test-host" created [root@k8s-master yaml]# kubectl describe svc test-host Name: test-host Namespace: default Labels: name=test-host Selector: name=test-host Type: NodePort IP: 10.254.127.198 Port: <unset> 8080/TCP NodePort: <unset> 30003/TCP Endpoints: 10.0.251.146:8080,10.0.251.153:8080,10.0.251.155:8080 + 1 more... Session Affinity: None No events.
建立成功之後,叢集內部的應用可通過虛擬網路中的clusterIP:10.254.127.198:8080來訪問後端服務,叢集外部的應用(如瀏覽器)可以通過nodeIP+NodePort來訪問後端服務。
3.3 埠占用
3.3.1 其他Pod埠占用
若同叢集中,用host模式啟動的deployment(或RC)有多個,若這些 deployment中定義的containerPort有相同的值,那麼,Kubernetes會校驗出埠資源的衝突。示例如下:
[root@k8s-master yaml]# cat test-host.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: test-host spec: replicas: 3 template: metadata: labels: name: test-host spec: containers: - name: test-host image: registry:5000/back_demon:1.0 command: - /jboss/jboss-eap-6.1/bin/standalone.sh ports: - containerPort: 8080 hostNetwork: true [root@k8s-master yaml]# cat test-host1.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: test-host1 spec: replicas: 2 template: metadata: labels: name: test-host1 spec: containers: - name: test-host1 image: registry:5000/back_demon:1.0 command: - /jboss/jboss-eap-6.1/bin/standalone.sh ports: - containerPort: 8080 hostNetwork: true [root@k8s-master yaml]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE test-host-1108333573-9oo55 1/1 Running 0 19m 10.0.251.155 k8s-node-2 test-host-1108333573-uc2v2 1/1 Running 0 19m 10.0.251.146 k8s-node-3 test-host-1108333573-vxezq 1/1 Running 0 19m 10.0.251.153 k8s-node-1 test-host1-6476903-q8e6o 0/1 Pending 0 19m <none> test-host1-6476903-zmk5l 1/1 Running 0 19m 10.0.251.222 k8s-node-4
實驗叢集下,可用的node數量只有4個,而兩個deployment——test-host、test-host1對外暴露額埠是相同的——8080。兩個deployment一共要啟動的副本數量為5,這時,最後啟動的那個Pod就會一直處於Pending狀態。
3.3.2 宿主機埠占用
當Host模式的Deployment(或RC)宣告一個埠時,比如8080,若宿主機上有非Kubernetes控制的程式佔用了8080這個埠,這時Kubernetes是無法校驗到的。也就是說,schedule僅僅會記錄Kubernetes叢集中的埠占用資訊,並在排程時做相關的校驗工作。但schedule不會校驗宿主機上真正的埠占用資訊。這其實是非常合理的,叢集中的node通常成千上萬,被當做一臺臺單純的提供計算能力的資源,計算什麼由中心節點來決定。沒有必要,也沒有場景需要在node上額外的跑其他程式。
在使用Host模式網路時,需注意的是,每個應用(部署成一個deployment)都要有自己固定的、和其他應用不同的埠,比如編碼器永遠固定成9525、源伺服器永遠固定成9537等。且宿主機在做了Kubernetes叢集中的node之後,儘量不對非本叢集應用提供服務。
3.4 映象製作要求
必須用Host模式啟動的Pod,在映象製作時要求埠唯一、且單一。
一般Pod中只會存在一個業務主映象,該業務映象在製作時,應該只放一種應用,這個應用只對外開放一個介面。例如,編碼器主控節點這個應用,主要有兩方面的功能:1)接收組播流,並控制處理節點,佔用埠9525;2)視覺化操控介面,佔用埠8080。其中接收組播流這塊,需要使用Host模式的網路。拆分建議為兩個業務映象,部署時部署兩個deployment。即接收組播流拆成一個映象,固定埠9525,使用Host模式啟動;視覺化介面拆成一個映象,用Kubernetes預設網路模式啟動。