深入了解Kubernetes Service
Service是Kubernetes最核心的概念,通過創建Service,可以為一組具有相同功能的容器應用提供一個統一的入口地址,並且將請求進行負載分發到后端的各個容器應用上。
Service的四種類型
- Clusterip: 默認類型,自動分配一個僅cluster內部可以訪問的虛擬ip
- NodePort: 在clusterip基礎上為service在每台機器上綁定一個端口,這樣就可以通過Nodeip:port方式來訪問該服務
- Loadbalance: 在NodePort基礎上,接觸cloud provider創建一個外部負載均衡器,並將請求轉發到nodeip:port
- externalName: 把集群外部的服務引入到集群內部,在集群內中直接使用,沒有任何類型的代理被創建
yaml格式的pod配置文件內容及屬性說明
apiVersion: v1 // 必選,版本: v1 kind: Service // 必選,Service metadata: // 必選,元數據 name: string // 必選,Service名稱 namespace: string // 命令空間,不指定時系統系統默認的空間"default" labels: // 自定義屬性標簽列表 - name: string // 自定義注釋屬性列表 spec: // 詳細描述 selector: [] // label Selector配置,選擇具有指定label標簽的Pod作為管理范圍 type: string // Service的類型,默認為ClusterIP,可選NodePort和Loadbalancer。 clusterIP: string // 虛擬服務IP地址,類型為ClusterIP時,如不指定,則系統自動分配 sessionaffinity: string // 是否支持session,默認為空,可選ClusterIP,表示同一個客戶端的訪問請求轉發到同一個口段Pod ports: // Service需要暴露的端口列表 - name: string // 端口名稱 protocol: string // 端口協議,支持tcp和udp,默認tcp port: int // 服務監聽的端口號 targetPort: int // 需要轉發到后端Pod的頓口號 nodePort: int // 當type為NodePort時,指定映射到物理機的端口號介於[30000-32767]間 status: // 當type為loadbalancer時,設置尾部負載均衡的地址,用於公有雲環境 loadBalancer: // 外部負載均衡器 ingress: // 外部負載均衡器 ip: string // 外部負載均衡器的Ip hostname: string // 外部負載均衡器的主機名
Service的基本用法
一般來說,對外提供服務的應用程序需要通過某種機制來實現,對於容器應用最方便的方式就是通過TCP/IP及監聽IP和端口號的方式來實現。直接通過Pod的IP地址和端口號訪問應用,但是Pod的IP地址是不可靠的,當Pod所在的Node發生故障,Kubernetes會了重新調度到另一台Node上,這樣Pod的IP將發生變化。重要的是,容器本身是分布式的部署方式,通過多個實例共同提供服務,需要在這些實例的前端設置一個負載均衡器來實現請求的分發,Kubernetes中的Service就師用來解決該問題的核心組件。
Kubernetes提供一種快速的方法,即通過kubectl expose命令來創建Service
如:
#kubectl expose rc webapp
查看新創建的Service,可以看到系統為它分配了一個虛擬的IP地址(Cluster IP),而Service所需的端口號則從Pod中的containerPort復制而來.
#kubectl get svc NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE webapp 169.169.235.79 <none> 8080/TCP 3s
我們可以通過該Service的IP地址和端口號來訪問
#curl 169.169.235.79:8080
對Service地址169.169.235.79:8080的訪問會自動負載到后端的兩個Pod中的一個。 除了使用命令創建Service,也可以通過配置文件定義Service,在通過kubectl create -f命令來進行創建。
apiVersion: v1 kind: service metadata: name: webapp spec: ports: - port: 8081 // Service所需的虛擬端口號 targetPort: 8080 // 后端Pod的端口號 selector: app: webapp // 后端擁有label: app=webapp的Pod
目前,Kubernetes提供兩種負載分發策略:RoundRobin和SessionAffinity。默認情況下采用RoundRobin模式進行路由選擇。
- RoundRobin:輪詢模式,即輪詢將請求轉發到后端各個Pod
- SessionAffinity:基於客戶端Ip地址進行會話保持,即第一次將某個客戶端發情的請求轉發到后端某個Pod上,之后相同的客戶端發起的請求都將被轉發到后端相同的Pod上。
默認情況下,Kubernetes采用RoundRbin模式進行路由選擇,某些應用場景下開發人員系統自己控制負載均衡策略,Kubernetes通過Headless Service的概念來實現這種功能,即不給Service設置ClusterIP,僅通過Label Selector將后端的Pod列表返回給調用的客戶端.
如:
apiVsersion: v1 kind: Service metadata: name: nginx label: name: nginx spec: ports: - ports: 80 clusterIP: None selector: app: nginx
該Service沒有虛擬的clusterip地址,對其進行訪問將獲得具有label "app=nginx"的全部Pod別表,然后客戶端程序需要實現自己的負載均衡分發策略。
集群外部訪問Pod或Service
由於Pod和Service都是Kubernetes集群范圍內的虛擬概念,所以集群外的客戶端無法通過Pod的IP或者service的虛擬ip和端口號訪問。為了讓外部用戶可以訪問這些服務,可以將Pod和Service的端口映射到宿主機,使客戶端通過物理機訪問容器應用.
方式將容器應用的端口號映射到物理機
- 通過設置容器級別的hostport,將容器應用的端口號映射到物理機
apiVersion: v1 kind: Pod metadata: name: webapp labels: name: webapp spec: containers: - name: tomcat image: tomcat ports: - containerPort: 8080 hostPort:8081
通過kubectl create創建該pod后即可通過物理機的IP和8081端口訪問Pod內的容器服務
#curl 10.0.0.23:8081
- 通過設置Pod級別的hostNetwork=true,該Pod中所有容器的端口號都將被直接映射到物理機,需要注意的是,在容器的ports定義部分如不指定hostport,則默認hostport等於containerport。
使用nodePort類型將Service的端口號映射到物理機
- 過設置nodePort映射到物理機,同時這是Service的類型為nodePort
apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30033
selector:
name: webapp
通過物理機的IP地址和nodePort30033端口訪問服務
#curl 10.0.0.22:30033
同樣對該Service的訪問也將被負載分發到后端的多個Pod上
- 通過設置LoadBalancer映射到雲服務商提供的LoadBalancer地址。該用法僅用於在公有雲服務商的平台上設置Service的場景
