《快速掌握 Kubernetes 網絡基礎》最先發布在 blog.hdls.me/15376903337…html
由於 Pod 的易變性(重建以後 IP 可能會改變),Service 承擔了服務入口的職能,是 k8s 網絡部分的核心概念,在 k8s 中,Service 主要擔任了四層負載均衡的職責。本文從負載均衡、外網訪問、DNS 服務的搭建及 Ingress 七層路由機制等方面,講解 k8s 的網絡相關原理。node
Service 是主要用來實現應用程序對外提供服務的機制。nginx
如上圖所示,Service 是對 Pod 的一層抽象,主要經過 TCP/IP 機制及監聽 IP 和端口號來對外提供服務。與 Pod 不一樣的是,Service 一旦建立,系統會爲其分發一個 ClusterIP (也能夠本身指定),且在其生命週期內不會發生變化。web
在建立好 RC 後,能夠經過命令行 kubectl expose
來快速建立一個對應的 Service 。好比現已有一個名爲 hdls 的 rc:數據庫
kubectl expose rc hdls
複製代碼
這種方式建立出來的 Service,其 ClusterIP 是系統自動爲其分配的,而 Service 的端口號是從 Pod 中的 containerPort 複製而來。後端
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 的定義須要指定如下幾個關鍵字段:api
k8s 提供了兩種負載分發策略:bash
在默認狀況下,k8s 採用輪詢模式進行路由選擇,但咱們也能夠經過將 service.spec.SessionAffinity 設置爲 「ClusterIP」 來啓用 SessionAffinity 模式。網絡
Headless Serviceapp
在這種狀況下,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。
無 LabelSelector Service
通常來講,應用系統須要將外部數據庫做爲後端服務進行鏈接,或另外一個集羣或 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 上。
多端口的 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
複製代碼
Pod 和 Service 都是 k8s 集羣內部的虛擬概念,因此集羣外的客戶沒法訪問。但在某些特殊條件下,咱們須要外網能夠訪問 Pod 或 Service,這時咱們須要將 Pod 或 Service 的端口號映射到宿主機,這樣客戶就能夠經過物理機訪問容器應用。
將容器應用的端口號映射到物理機上。有兩種方式,以下。
這種是將容器應用的端口號映射到物理機。設置以下:
apiVersion: v1
kind: Pod
metadata:
name: hdls-pod
spec:
containers:
- name: hdls-container
image: ***
ports:
- containerPort: 8000
hostPort: 8000
複製代碼
這種是將該 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
複製代碼
也有兩種方式。
首先須要設置 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
複製代碼
這種用法僅用於在公有云服務提供商的雲平臺上設置 Service 的場景。須要將 service.status.loadBalancer.ingress.ip 設置爲雲服務商提供的負載均衡器的 IP。則對該 Service 的訪問請求將會經過 LoadBalancer 轉發到後端 Pod,且負載均衡的實現方式依賴於雲服務商提供的 LoadBalancer 的實現機制。
爲了可以實現經過服務名在集羣內部進行服務的相互訪問,須要建立一個虛擬的 DNS 服務來完成服務名到 ClusterIP 的解析。
k8s 提供的 DNS 服務名爲 skydns,由下面四個組件組成:
skyDNS 服務由一個 RC 和一個 Service 組成。在 RC 的配置文件中,須要定義 etcd / kube2sky / skydns / healthz 四個容器,以保證 DNS 服務正常工做。須要注意的是:
--domain
設置爲 k8s 集羣中 Service 所屬域名。容器啓動後 kube2sky 會經過 API Server 監控集羣中全部 service 的定義,生成相應的記錄並保存到 etcd ;-addr=<IP:Port>
表示本機 TCP 和 UDP 的 Port 端口提供服務。在 DNS Service 的配置文件中,skyDNS 的 ClusterIP 須要咱們指定,每一個 Node 的 kubelet 都會使用這個 IP 地址,不會經過系統自動分配;另外,這個 IP 須要在 kube-apiserver 啓動參數 --service-cluster-ip-range
內。
在 skydns 容器建立以前,須要先修改每一個 Node 上 kubelet 的啓動參數:
/etc/resolv.conf
中增長一條 nameserver 配置和 search 配置,經過 nameserver 訪問的實際上就是 skydns 在對應端口上提供的 DNS 解析服務;Service 工做在 TCP/IP 層,而 Ingress 將不一樣的 URL 訪問請求轉發到後端不一樣的 Service ,實現 HTTP 層的業務路由機制。而在 k8s 中,須要結合 Ingress 和 Ingress Controller ,才能造成完整的 HTTP 負載均衡。
Ingress Controller 用來實現爲全部後端 Service 提供一個統一的入口,須要實現基於不一樣 HTTP URL 向後轉發的負載分發規則。Ingress Controller 以 Pod 的形式運行,須要實現的邏輯:
/etc/nginx/nginx.conf
;nginx -s reload
,從新加載 nginx.conf 配置文件的內容。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 配置文件內容。