天天看點

Kubernetes 入門之網絡詳解

Service 是 k8s 網絡部分的核心概念,在 k8s 中,Service 主要擔任了四層負載均衡的職責。本文從負載均衡、外網通路、DNS 服務的搭建及 Ingress 七層路由機制等方面,講解 k8s 的網絡相關原理。

1.Service 詳解

Service 是主要用來實作應用程式對外提供 服務的機制。

如上圖所示,Service 是對 Pod 的一層抽象,主要通過 TCP/IP 機制及監聽 IP 和端口号來對外提供服務。與 Pod 不同的是,Service 一旦建立,系統會為其分發一個 ClusterIP (也可以自己指定),且在其生命周期内不會發生變化。

Service 的建立

指令行快速建立

在建立好 RC 後,可以通過指令行

kubectl expose

來快速建立一個對應的 Service 。比如現已有一個名為 hdls 的 rc:

kubectl expose rc hdls

這種方式建立出來的 Service,其 ClusterIP 是系統自動為其配置設定的,而 Service 的端口号是從 Pod 中的 containerPort 複制而來。

通過 YAML 建立

apiVersion: v1

kind: Service

metadata:

name: hdls

spec:

ports:

- port: 8080 # Service 的虛拟端口

targetPort: 8000 # 指定後端 Pod 的端口号

selector: # Label 選擇器

app: hdls

定義好 YAML 檔案後,通過指令

kubectl create-f<service.yml>

即可建立。Service 的定義需要指定以下幾個關鍵字段:

ports

  • port:Service 的虛拟端口
  • targetPort:後端 Pod 的端口号,若不填則預設與 Service 的端口一緻

selector:Label 選擇器,指定後端 Pod 所擁有的 Label

負載分發政策

k8s 提供了兩種負載分發政策:

  • RoundRobin:輪詢方式。即輪詢将請求轉發到後端的各個 Pod 上。
  • SessionAffinity:基于用戶端 IP 位址進行會話保持模式。即相同 IP 的用戶端發起的請求被轉發到相同的 Pod 上。

在預設情況下,k8s 采用輪詢模式進行路由選擇,但我們也可以通過将 service.spec.SessionAffinity 設定為 “ClusterIP” 來啟用 SessionAffinity 模式。

Notes:一些特殊情況

1.開發人員需要自己控制負載均衡政策的情況

在這種情況下,k8s 通過 Headless Service 的概念來實作,即不給 Service 設定 ClusterIP (無入口 IP),僅通過 Label Selector 将後端的 Pod 清單傳回給調用的用戶端。

apiVersion: v1

kind: Service

metadata:

name: hdls

spec:

ports:

- port: 8080

targetPort: 8000

clusterIP: None

selector:

app: hdls

該 Service 沒有虛拟的 ClusterIP ,對其通路可以獲得所有具有

app=hdls

的 Pod 清單,用戶端需要實作自己的負責均衡政策,再确定具體通路哪一個 Pod。

2.需要将某些服務作為後端服務

一般來說,應用系統需要将外部資料庫作為後端服務進行連接配接,或另一個叢集或 namespace 中的服務作為後端服務。這些情況,可以通過建立一個無 Label Selector 的 Service 來實作:

apiVersion: v1

kind: Service

metadata:

name: hdls

spec:

ports:

- port: 8080

targetPort: 8000

該 Service 沒有标簽選擇器,即無法選擇後端 Pod。這時系統不會自動建立 Endpoint,需要手動建立一個與該 Service 同名的 Endpoint,用于指向實際的後端通路位址。

apiVersion: v1

kind: Endpoints

metadata:

name: hdls # 與 Service 同名

subsets:

- addresss:

- IP: 1.2.3.4 # 使用者指定的 IP

ports:

- port: 8000

此時,如上面的 YAML 建立出來 Endpoint,通路無 Label Selector 的 Service ,即可将請求路由到使用者指定的 Endpoint 上。

3.多端口的 Service

在 service.spec.ports 中定義多個 port 即可,包括指定 port 的名字和協定。

apiVersion: v1

kind: Service

metadata:

name: hdls

spec:

ports:

- name: dns

port: 8080

protocol: TCP

- name: dns-tcp

port: 8080

protocol: UDP

selector:

app: hdls

2.外網通路

Pod 和 Service 都是 k8s 叢集内部的虛拟概念,是以叢集外的客戶無法通路。但在某些特殊條件下,我們需要外網可以通路 Pod 或 Service,這時我們需要将 Pod 或 Service 的端口号映射到主控端,這樣客戶就可以通過實體機通路容器應用。

外網通路 Pod

将容器應用的端口号映射到實體機上。有兩種方式,如下。

設定容器級别的 hostPort

這種是将容器應用的端口号映射到實體機。設定如下:

apiVersion: v1

kind: Pod

metadata:

name: hdls-pod

spec:

containers:

- name: hdls-container

image: ***

ports:

- containerPort: 8000

hostPort: 8000

設定 Pod 級别的 hostNetwork=true

這種是将該 Pod 中所有容器端口号都直接映射到實體機上。此時需要注意的是,在容器的 ports 定義部分,若不指定 hostPort,預設 hostPort=containerPort,若設定了 hostPort,則 hostPort 必須等于 containerPort。設定如下:

apiVersion: v1

kind: Pod

metadata:

name: hdls-pod

spec:

hostNetwork: true

containers:

- name: hdls-container

image: ***

ports:

- containerPort: 8000

外網通路 Service

對于外網通路 Service 也有兩種方式。

1.設定 nodePort 映射到實體機

首先需要設定 nodePort 映射到實體機,同時需要設定 Service 的類型為 NodePort:

apiVersion: v1

kind: Service

metadata:

name: hdls

spec:

type: NodePort # 指定類型為 NodePort

ports:

- port: 8080

targetPort: 8000

nodePort: 8000 # 指定 nodePort

selector:

app: hdls

2.設定 LoadBalancer 映射到雲服務商提供的 LoadBalancer 位址

這種用法僅用于在公有雲服務提供商的雲平台上設定 Service 的場景。需要将 service.status.loadBalancer.ingress.ip 設定為雲服務商提供的負載均衡器的 IP。則對該 Service 的通路請求将會通過 LoadBalancer 轉發到後端 Pod,且負載均衡的實作方式依賴于雲服務商提供的 LoadBalancer 的實作機制。

3.DNS 搭建

為了能夠實作通過服務名在叢集内部進行服務的互相通路,需要建立一個虛拟的 DNS 服務來完成服務名到 ClusterIP 的解析。

k8s 提供的 DNS

k8s 提供的 DNS 服務名為 skydns,由下面四個元件組成:

  • etcd:DNS 存儲;
  • kube2sky:将 k8s Master 中的 Service 注冊到 etcd ;
  • skyDNS:DNS 域名解析服務;
  • healthz:對 skyDNS 的健康檢查。

skyDNS 服務由一個 RC 和一個 Service 組成。在 RC 的配置檔案中,需要定義 etcd / kube2sky / skydns / healthz 四個容器,以保證 DNS 服務正常工作。需要注意的是:

1. kube2sky 容器需要通路 k8s Master,是以需要在配置檔案中為其配置 Master 所在實體主機的 IP 位址和端口;

2. 需要将 kube2sky 和 skydns 容器的啟動參數

--domain

設定為 k8s 叢集中 Service 所屬域名。容器啟動後 kube2sky 會通過 API Server 監控叢集中所有 service 的定義,生成相應的記錄并儲存到 etcd ;

3. skydns 的啟動參數

-addr=<IP:Port>

表示本機 TCP 和 UDP 的 Port 端口提供服務。

在 DNS Service 的配置檔案中,skyDNS 的 ClusterIP 需要我們指定,每個 Node 的 kubelet 都會使用這個 IP 位址,不會通過系統自動配置設定;另外,這個 IP 需要在 kube-apiserver 啟動參數

--service-cluster-ip-range

内。

在 skydns 容器建立之前,需要先修改每個 Node 上 kubelet 的啟動參數:

  • --clusterdns= ,dnscluster_ip 為 DNS 服務的 ClusterIP ;
  • --clusterdomain= , dnsdomain 為 DNS 服務中設定的域名。

DNS 工作原理

1. 首先 kube2sky 容器應用通過調用 k8s Master 的 API 獲得叢集中所有 Service 資訊,并持續監控新 Service 的生成,寫入 etcd;

2. 根據 kubelet 的啟動參數的設定,kubelet 會在每個新建立的 Pod 中設定 DNS 域名解析配置檔案

/etc/resolv.conf

中增加一條 nameserver 配置和 search 配置,通過 nameserver 通路的實際上就是 skydns 在對應端口上提供的 DNS 解析服務;

3. 最後,應用程式就可以像通路網站域名一樣,僅通過服務的名字就能通路服務了。

4.Ingress

Service 工作在 TCP/IP 層,而 Ingress 将不同的 URL 通路請求轉發到後端不同的 Service ,實作 HTTP 層的業務路由機制。而在 k8s 中,需要結合 Ingress 和 Ingress Controller ,才能形成完整的 HTTP 負載均衡。

Ingress Controller

Ingress Controller 用來實作為所有後端 Service 提供一個統一的入口,需要實作基于不同 HTTP URL 向後轉發的負載分發規則。Ingress Controller 以 Pod 的形式運作,需要實作的邏輯:

  • 監聽 APIServer,擷取所有 Ingress 定義;
  • 基于 Ingress 的定義,生成 Nginx 所需的配置檔案

    /etc/nginx/nginx.conf

  • 執行

    nginx-s reload

    ,重新加載 nginx.conf 配置檔案的内容。

定義 Ingress

k8s 中有一種單獨的名為 Ingress 的資源,在其配置檔案中可以設定到後端 Service 的轉發規則。比如,為 hdls.me 定義一個 ingress.yml:

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

name: hdls-ingress

spec:

rules:

- host: hdls.me

http:

paths:

- path: /web

backend:

serviceName: hdls

servicePort: 8000

最後采用

kubectl create-f ingress.yml

建立 Ingress。可以登入 nginx-ingress Pod 檢視其自動生成的 nginx.conf 配置檔案内容。

本文轉自掘金-

Kubernetes 入門之網絡詳解

繼續閱讀