Kubernetes-Host網路模式應用

振宇要低調發表於2017-04-20

  在實際生產環境中,有些容器內應用(比如編碼器)需要用到物理層面的網路資源(比如組播流)。這就要求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預設網路模式啟動。

 

相關文章