Skip to content

從 Red Hat OpenShift 外部訪問 Services 或 Pods

Red Hat OpenShift v3.11 架構裡網路主要分為三大塊:

  1. Hosts subnet
  2. Service subnet
  3. Pod subnet

Host subnet 毫無懸念指的就是主機所使用的 IP,也就是對外可以接觸到主機的網路; 而 Service 和 Pods subnet 在 OpenShift 裡面是一個虛擬概念,正常狀況下外部網路無法透過 Pod IP/Port 和 Service IP/Port 接觸到服務

那如果我想要讓 Pod 或 Service IP 可以被外面接觸到呢? 以下分為兩個層級來討論: 1. Pod mapping to host 2. Service mapping to host

Pod port Mapping to Host port

使用 hostNetwork=true

若沒有特別指定的話,預設 hostPort 等於 containerPort,意思是說 Pod 裡面的容器開了什麼 Port 就會直接對應到 host 上面的 Port,而 Pod IP 則會理所當然地等於 Host IP

外面訪問服務的 IP/Port,請求會直接轉到和 Pod 相同的 IP/Port ,途中不經過 iptables 及 service 處理

優點: 直接可以從外面直接接觸到 Pod 層級服務,網路轉發效率會比 nodePort 好 缺點: 不能在同一台主機 (Host) 開啟第二個相同的 Pod,因為會有 Port 衝突的問題,也不能跨主機建立服務

---
apiVersion: v1
kind: Pod
metadata:
  name: influxdb
spec:
  hostNetwork: true <----
  containers:
    - name: nginx
      image: nginx

使用 hostPort

概念跟前者很像,差異會在可以指定特定的 hostPort 對應到 containerPort,但並不需要全部的 Pod Port 都跟 Host 做對應,可以有限度的開放出去

優點: 直接可以從外面直接接觸到 Pod 層級服務 缺點: 不能在同一台主機 (Host) 開啟第二個相同的 Pod,因為會有 Port 衝突的問題,也不能跨主機建立服務

---
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
    - name: nginx
      image: nginx
      ports:
      - containerPort: 80
        hostPort: 8080 <----

Service port Mapping to Host port

使用 nodePort

廣泛應用的服務揭露方式,在預設情況下,每啟動一個 Service 都會搭配一個 ClusterIP,而這個 ClusterIP 僅能在同一個集群內部被訪問,外面不能接觸到,倘若想要讓他被接觸的話,就要指定 nodePort 對外揭露

hostPort 跟 nodePort 的差異在,前者是針對單一主機裡的單一容器進行設定,後者則是以一個集群來看待,服務可以跨主機

優點: 可跨主機,直接可以從外面直接接觸到 Service 層級服務,且能透過所產生的 ClusterIP 對後端的 Pod 做負載均衡 缺點: 所有集群的 Port 都會同時被開起來,讓外部做接觸

---
kind: Service
apiVersion: v1
metadata:
  name: influxdb
spec:
  type: NodePort
  ports:
    - port: 8086
      nodePort: 30000 <---
  selector:
    name: influxdb

建議可以搭一個外部 Reverse Proxy 來做使用,譬如像是 F5 / A10 / HAProxy

使用 Ingress Controller: OpenShift Router

綜合 Pod 跟 Service 的優點的改良作法,也是普遍建立對外服務時的最佳實踐。你不需要自己對所有的 Service 去新增 nodePort,而可以直接在 OpenShift 上建立一個 Reverse Proxy 的服務,直接進行對外服務揭露及對內服務負載平衡,依據不同的 Ingress Controller 實作,通常功能都會包含 HTTP 路徑揭露、Session Sticky、SSL Transparent/Re-encrypt/Terminated 等等負載平衡的功能

OpenShift Router 是採用 hostnetwork 的方式建立,所以每一台主機至多只能安裝一個,同時 80 / 443 /1936 這三個 Port 會被預設佔走

想了解於 OpenShift 對於 Ingress Controller 的實作 Router 可以參考 Router Overview - OpenShift v3.11 Docs

使用 Service Type: LoadBalancer

正常使用下,這功能僅限於公有雲,但在 OpenShift 裡面有支援一個功能叫做 ingress IP,效果就是給 OpenShift 僅一個特定的網段 (Subnet) 之後,可以從中選取任一 IP,並使用 type: LoadBalancer 對外揭露服務,詳細可以參考 Using Ingress to Expose Services

使用 External IngressIP

倘若一定要走 non-HTTP/HTTPS 的服務,又想要有類似於使用 Service Type: LoadBalancer,那可以考慮使用 IngressIP 來做使用,Using Ingress to Expose Services

可以做成下面的效果

$ oc get svc -n openshift-ingress
NAME                      TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                      AGE
router-default            LoadBalancer   172.30.16.119   52.230.228.163   80:30745/TCP,443:32561/TCP   2d6h

Summary

在 OpenShift 的環境之下

  1. 對於 http/https 的服務,對外透過 Ingress Controller: OpenShift Router 揭露 FQDN 讓外面使用
  2. 對於非 http/https 的服務,如 mysql,有下列兩種做法:
  3. 若不需要提供對外服務,僅使用 ClusterIP 在內部進行使用
  4. 若需要提供對外服務,有下列三種做法:
    1. Single Instance,不需要在多個 node 上面運行,使用 hostnetworkhostPort
    2. Multiple Instance,需要在多個 node 上面運行,做到 scale-out 的效果,則使用 ingress IP 為佳

References