我們通過Deployment可以爲一個應用創建多個Pod,而且可以動態的進行增加、或者刪除多餘的Pod,Kubernetes Pod 是有生命週期的,它們可以被創建,也可以被銷燬,但是每次Pod的IP地址就會發生變化,外面如何訪問到該Pod呢?總不能每次Pod重啓就修改訪問的IP地址吧。 每個 Pod 都會獲取它自己的 IP 地址,但是每次即使這些 IP 地址不總是穩定可依賴的。 這會導致一個問題:在 Kubernetes 集羣中,如果一組 Pod(稱爲 backend)爲其它 Pod (稱爲 frontend)提供服務,那麼那些 frontend 該如何發現,並連接到這組 Pod 中的哪些 backend 呢?
這個時候就要用到Service了。
一、Service概念
Service定義了一個服務的訪問入口地址,前端的應用(Pod)通過這個入口地址訪問其背後的一組由Pod副本組成的集羣實例。 Service與其後端Pod副本集羣之間則是通過Label Selector
來實現"無縫對接"
既然每個Pod都會被分配一個單獨的IP地址,而且每個Pod都提供了一個獨立的Endpoint
**(Pod IP+ContainerPort)**以被客戶端訪問,現在多個Pod副本組成了一個集羣來提供訪問。
Kubernetes 需要在每個Node上安裝kube-proxy
,kube-proxy
進程其實就是一個智能的軟件負載均衡器,它負責把對Service的請求轉發到後端的某個Pod實例上,並在內部實現服務的負載均衡與會話保持機制。
Kubernetes發明了一個很巧明的設計,Service不是共用一個負載均衡器的IP地址,而是每個Service分配了一個全局唯一的虛擬IP地址,這個虛擬IP被稱爲Cluster IP。這樣每個服務就變成了具備唯一IP地址的"通信節點",服務調用就變成了最基礎的TCP網絡通信問題。而且在Service的整個聲明週期內,它的Cluster IP不會發生改變。
二、Service的幾種類型
在Serive定義時,我們需要指定spec.type
字段,這個字段擁有四個選項:
ClusterIP。默認值。給這個Service分配一個Cluster IP,它是Kubernetes系統自動分配的虛擬IP,因此只能在集羣內部訪問。
NodePort。將Service通過指定的Node上的端口暴露給外部。通過此方法,訪問任意一個NodeIP:nodePort
都將路由到ClusterIP,從而成功獲得該服務。
LoadBalancer。在 NodePort 的基礎上,利用其他第三方的LB暴露服務的,谷歌或者亞馬遜的LB等等。
ExternalName。將服務通過 DNS CNAME 記錄方式轉發到指定的域名(通過 spec.externlName 設定)。需要 kube-dns 版本在 1.7 以上。
三、Service示例
1、ClusterIP
繼續我們Nginx的案例,之前用DaemonSet創建了nginx應用,現在爲這些應用創建一個Service
[root@k8s-01 ~]# cat nginx-service.yaml
kind: Service
apiVersion: v1
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
- 第1行:定義資源類型爲Service
- 第2行:定義當前Service API的版本
- 第3行:metadata設置
- 第4行:設置Service的名稱爲nginx-service
- 第5行:spec: 開始設置Service的內容
- 第6行:selector: 爲該Service指定一個匹配的標籤
- 第7行:app: nginx 所有帶有標籤app:nginx的Pod將使用該Service
- 第8行:ports: 指定Service需要對外的端口
- 第9行:設置端口協議:支持TCP和UDP
- 第10行:設置Service的端口
- 第11行:設置Pod的端口,Kubernetes會將發送給Service端口的連接,轉發到Pod的端口上。
創建Nginx Service
[root@k8s-01 ~]# kubectl create -f nginx-service.yaml
service/nginx-service created
查看Nginx Service
[root@k8s-01 ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.254.0.1 <none> 443/TCP 18d
nginx-service ClusterIP 10.254.247.47 <none> 80/TCP 10s
訪問Servce IP
[root@k8s-01 ~]# curl --head 10.254.247.47
HTTP/1.1 200 OK
Server: nginx/1.13.12
Date: Tue, 12 May 2020 07:26:00 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Mon, 09 Apr 2018 16:01:09 GMT
Connection: keep-alive
ETag: "5acb8e45-264"
Accept-Ranges: bytes
2、NodePort
在開始之前,將之前創建的pod和service清理下。
1)通過指令創建NodePort
nginx的yaml文件:
[root@k8s-01 ~]# cat nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
創建並查看Pod
[root@k8s-01 ~]# kubectl create -f nginx-pod.yaml
pod/nginx-pod created
[root@k8s-01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-pod 1/1 Running 0 26s
[root@k8s-01 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-pod 1/1 Running 0 32s 172.30.64.4 k8s-01 <none> <none>
現在用命令將其配置爲NodePort的形式:
[root@k8s-01 ~]# kubectl expose pod nginx-pod --type=NodePort
service/nginx-pod exposed
[root@k8s-01 ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.254.0.1 <none> 443/TCP 18d
nginx-pod NodePort 10.254.199.142 <none> 80:30248/TCP 29s
這個時候可以看到nginx-pod的類型變成了NodePort
,而且後面也寫明瞭端口的映射關係:將pod中的80端口映射到node的30248端口。
現在就直接訪問node的30248端口:
master:
node:
2)通過yaml形式創建NodePort
在開始之前,先刪除剛剛的service
[root@k8s-01 ~]# kubectl delete svc nginx-pod
service "nginx-pod" deleted
然後編寫yaml文件
[root@k8s-01 ~]# cat service-nginx.yml
kind: Service
apiVersion: v1
metadata:
name: nginx-service
spec:
selector:
app: nginx
type: NodePort
ports:
- protocol: TCP
port: 32001
targetPort: 80
nodePort: 32111
- port:service暴露在cluster ip(Seriver ip )上的端口,:port 是提供給集羣內部客戶訪問service的入口。
- nodePort:kubernetes提供給集羣外部客戶訪問service入口的一種方式(另一種方式是[LoadBalancer]),是提供給集羣外部客戶訪問service的入口。
- targetPort:targetPort很好理解,targetPort是pod上的端口,從port和nodePort上到來的數據最終經過kube-proxy流入到後端pod的targetPort上進入容器。
創建:
[root@k8s-01 ~]# kubectl create -f service-nginx.yml
service/nginx-service created
訪問:
四、外部系統訪問Service問題
我們需要掌握kubernetes中的三種IP
- Node IP:Node節點IP地址
- Pod IP:Pod的IP地址
- Cluster IP:Service的IP地址
NodePort的實現方式是在Kubernetes集羣裏的每個Node上爲需要外部訪問的Service開啓一個對應的TCP請求,外部系統只要用任意Node的IP地址+具體的NodePort端口即可訪問服務,在任意node上運行netstat服務,我們可以看到NodePort端口被監聽。
但NodePort還沒有完全解決外部訪問Service的所有問題,比如負載均衡的問題,假如說我們集羣中有10個Node,則此時最好有一個負載均衡,外部的請求只需要訪問此負載均衡器的IP地址,由負載均衡負責轉發流量到後面的node上。
上圖中Load balancer組件獨立於Kubernetes集羣之外,通常是一個硬件的負載均衡器,或者是以軟件方式實現的,例如Haproxy或者Nginx。對於每個Service,我們通常配置一個對應的Load balancer實例來轉發流量到後端的Node。
參考文章:
https://k.i4t.com/kubernetes_service.html
http://k8s.unixhot.com/kubernetes/service-admin.html
http://www.eryajf.net/2127.html