在kubernets中,Pod是應用程式的載體,Pod你可以想象成就是容器,為動態的一組Pod提供一個固定的存取入口,它是以一種叫ClusterIP地址來進行標識,而ClusterIP就位於我們叢集網路(Cluster Network)當中,我們可以通過Pod的IP地址來進行存取,但是會遇到問題:
為了解決這個問題,K8s提供了Service資源,Service為動態的一組Pod提供一個固定的存取入口;這個固定的存取入口可以理解為是一組應用的前端的負載均衡器;就像LVS或Nginx為一組ReadyServer做負載均衡器是一樣的,你是看不見的,可以理解為Service就是負載均衡器,但是這種負載均衡器比傳統的負載均衡器要強大;Service資源通過"標籤選擇器Label Selector"把篩選出來的符合條件的一組Pod物件定義成一個邏輯集合,而後Service對外提供自己的IP和埠。
當用戶端請求Service的IP和埠時,Service將請求排程給標籤匹配的所有的Pod,Service向用戶端隱藏了真實處理請求的Pod資源,使得使用者端的請求看上去是由Service直接處理並進行響應。
Service物件的IP地址(Cluster IP或Service IP)是虛擬IP地址,由kubernetes系統在Service物件建立時在專有網路(Service Network)地址中自動分配或由使用者手動指定,其次Service是基於埠過濾,並根據事先定義好的規則將請求轉發至其後端Pod對應的埠上,因此這種代理機制也稱為"埠代理"或"四層代理"工作在TCP/IP協定棧的傳輸層;
1.7.1UserSpace
apiVersion: v1 # API的版本
kind: Service # 資源型別定義為Service
metadata:
name: ... # Serivce的名稱
namespace: ... # 預設的default
labels:
key1: value1 # 標籤 key:value格式;
key2: value2
spec:
type <string> # Service型別,預設為ClusterIP;
selector <map[string]string> # 標籤選擇器
ports: # ClusterIP:ServicePort
targetPort: <string> #後端目標程序的埠號或名稱。
nodePort: <integer> # 節點埠號,僅適用於NodePort和loadbalancer型別。 "建議動態選擇30000-32767"
clusterIP <string> # Service的叢集IP,建議由系統自動分配
externalTrafficPolicy <string> # 外部流量策略處理方式,local表示由當前節點處理,cluster表示向叢集範圍排程
loadBalancerIP <string> # 外部負載均衡器使用的IP地址,僅適用於loadbalancer,前提是你的公有云得支援你自己指定;
externalName <string> # 外部服務名稱,該名稱作為Service的DNS CNAME值
ClusterIP: 通過叢集內部IP暴露服務,選擇ServiceIP只能夠在叢集內部存取,這也是預設的Service型別;該地址僅在叢集內部可見、可達。無法被叢集外部使用者端存取;而且是預設型別,建立的任何Service預設就是ClusterIP型別,而且只能接受叢集內部使用者端的存取。
root@kubernetes-master01:~# cat services-clusterip-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-clusterip
namespace: default
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
clusterIP:
selector: # 標籤選擇器
app: nginx
ports:
- name: http # 埠名稱
protocol: TCP # 協定型別,目前支援TCP、UDP、SCTP預設為TCP
port: 80 # Service的埠號
targetPort: 80 # 後端目標程序的埠號
root@kubernetes-master01:~# kubectl apply -f services-clusterip-nginx.yaml
pod/nginx-clusterip created
service/nginx-svc created
2.2.1.1檢視Service;
root@kubernetes-master01:~# kubectl get svc
nginx-svc ClusterIP 10.106.70.164 <none> 80/TCP 3m
2.2.1.2 可以看到後端就一個Pod;
root@kubernetes-master01:~# kubectl get pods --show-labels -l app=nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
nginx-clusterip 1/1 Running 0 8m58s 10.244.4.49 kubernetes-node01 <none> <none> app=nginx
2.2.1.3檢視Endpoint資源,Endpoints可以簡寫為ep;
root@kubernetes-master01:~# kubectl get endpoints
nginx-svc 10.244.4.49:80 10m
2.2.1.4測試存取;只能在叢集內部存取,外部無法存取;
root@kubernetes-master01:~# curl -I 10.106.70.164
HTTP/1.1 200 OK
Server: nginx/1.21.5
Content-Type: text/html
Content-Length: 615
Connection: keep-alive
ETag: "61cb5be0-267"
Accept-Ranges: bytes
NodePort:首先是一種ClusterIP型別,也就是說,NodePort是ClusterIP的擴充套件型別。NodePort型別的Service不僅僅能夠被叢集內部的使用者端可見,還能對外部使用者端可見。怎麼可見呢?它會與ClusterIP的功能之外在每個節點上使用一個相同的埠號"注意是在每個節點上使用一個相同的埠號"將外部流量引入到該Service上來。
root@kubernetes-master01:~# cat services-nodeport-nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-nodeport-svc
namespace: default
spec:
type: NodePort
clusterIP:
selector:
app: nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80 # 後端Pod監聽什麼埠就寫什麼埠。要不然到達Service的請求轉發給Pod,Pod沒有那個埠也沒用。一定真正轉發到後端程式監聽的埠。如果沒有特殊情況的話,ServicePort和TargetPort保持一致。NodePort可以不用指定。
nodePort: # 正常情況下應由系統自己分配,預設是3000~32767
root@kubernetes-master01:~# kubectl apply -f services-nodeport-nginx.yaml
service/nginx-nodeport-svc created
2.3.1.1檢視Service,意味著存取宿主機IP+nodeport埠就可以存取服務;
root@kubernetes-master01:~# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 36d
nginx-nodeport-svc NodePort 10.111.124.121 <none> 80:32049/TCP 5s
nginx-svc ClusterIP 10.106.70.164 <none> 80/TCP 34m
2.3.1.2 測試,這是windows的命令列,也是沒有問題;
C:\Users\海棠>curl -I 10.0.0.1xx:30824
HTTP/1.1 200 OK
Server: nginx/1.21.5
Content-Type: text/html
Content-Length: 615
Connection: keep-alive
ETag: "61cb5be0-267"
Accept-Ranges: bytes
loadBalancer: 這類Service依賴雲廠商,需要通過雲廠商呼叫API介面建立軟體負載均衡將服務暴露到叢集外部,當建立LoadBalancer型別的Service物件時,它會在叢集上自動建立一個NodePort型別的Service,叢集外部的請求流量會先路由至該負載均衡,並由該負載均衡排程至各個節點的NodePort;
root@kubernetes-master01:~# cat services-loadbalancer-nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-loadbalancer-svc
namespace: default
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
loadBalancerIP: 1.2.3.4
2.4.1.2測試存取;
# 我們還是隻能是通過NodePort來存取,因為沒有LoadBalancer的IP;
# LoadBalancer其實就是一個增強的NodePort。而LoadBalancer沒有限制流量排程策略的。外部流量策略對loadbalancer依然使用,因為LoadBalancer首先是一個NodePort的Service。
C:\Users\冷雨夜>curl -I 10.0.0.1XX:31943
HTTP/1.1 200 OK
Server: nginx/1.21.5
Content-Type: text/html
Content-Length: 615
Connection: kep-alive
ETag: "61cb5be0-267"
Accept-Ranges: bytes
此型別不是用來定義如何存取叢集內服務的,而是把叢集外部的某些服務以DNS CANME方式對映到叢集內,從而讓叢集內的Pod資源能夠存取外部服務的一種實現方式。