目錄
service
1.service工作模式
1.userspace k8s1.1-
2.iptables k8s1.8-
3.ipvs k8s1.8+
kubernetes中的3類IP地址
node network(節點網絡):配置在節點的接口之上
pod network(pod 網絡):配置在pod資源之上
service network(cluster network):virtual IP,沒有配置在某個接口當中,只是出現在service的規則當中。
每個節點之上都有一個kube-proxy組件,它會始終監視(通過watch請求方法實現)着apiserver當中有關service資源的變動信息,當有service資源內容發生變動(創建),kube-proxy組件都將把它轉化為當前節點之上的能夠實現service資源調度(包括將用戶請求調度到后端pod之上的規則,規則是iptables或者ipvs,取決於service的實現方式,)
2.kubernetes的3種service實現模型
1.userspace
1. userspace: Client Pod(客戶端)請求到達service以后,先把service轉化為監聽在某個套接字上的用戶空間的kube-proxy,由它負責處理,之后再轉給Service IP,service IP再轉給其代理的Pod。
對於客戶端的請求,經過Service IP,還要回到監聽在某個端口上的kube-proxy,由kube-proxy再進行分發,而kube-proxy是工作在用戶空間的進程,這種方式就叫做userspace。但是工作效率低,其需要經過內核轉給用戶空間的kube-proxy進行報文封裝,再次回到內核由iptables規則進行分發。
2.iptables
iptables:Client Pod(客戶端)請求直接由內核iptables規則所截取,直接調度到相關聯的pod。
3.ipvs
ipvs:Client Pod(客戶端)請求直接由內核ipvs規則所截取,直接調度到相關聯的pod。
3.service使用iptables和ipvs規則實現的區別
參考文章:https://blog.csdn.net/qq_36807862/article/details/106068871
4.sevcie常用字段
kubectl explain svc.spec
selector <map[string]string> # 選擇關聯的pod的標簽
ports <[]Object> # 定義service監聽端口(port),暴露外部可以訪問的端口(nodePort,前提type:NodePort),以及目標端口(targetPort,)
loadBalancerIP <string>
clusterIP <string> # 手動指定集群內部訪問IP,不指定此字段,默認自動隨機分配IP
type <string> # 指定集群訪問類型
sessionAffinity # 可以設置成ClientIP,把來至同一客戶端的請求調度到同一個pod中。默認是none不使用;
kubectl explain svc.spec.type
# svc類型
ExternalName:把集群外部的服務引入到集群內部使用
ClusterIP: 創建service時,指定集群內部通信ClusterIP。
NodePort:接入集群外部的流量,使用NodePort
LoadBalancer:把kubernetes部署在虛擬機上,虛擬機部署在雲環境中,而雲環境支持LBAS(負載均衡及服務,)的一鍵調用,自動在外部創建一個軟負載均衡器,創建軟負載均衡器時使用。
kubectl explain svc.spec.ports
ports <[]Object>
name <string> # 端口名稱
port <integer> -required- # service對外提供服務的端口
nodePort <integer> # type=NodePort,LoadBalancer,才能定義nodePort;service將在每個節點上暴露此端口,可以在集群外部,通過集群任意節點IP:nodePort訪問此service關聯的一組后端pod服務。
protocol <string> # 不指定的話,默認是TCP
targetPort <string> # 容器端口
1.定義為ClusterIP時使用的ports下使用字段:
port: # service上的端口,k8s集群內部服務之間訪問service的入口,要與鏡像暴露的端口一致。
targetPort: #可以不寫, podIP上的端口 可以是端口名稱,也可以是端口;如果是端口名稱,要和pod中容器定義的port端口名稱一致。
2.定義為NodePort時使用的字段:
type: NodePort
ports:
- port: # 要與鏡像暴露的端口一致
nodePort: # service對外暴露的端口
3.loadbalancerIP:公有雲主機底層支持創建LoadbalacerIP # 下圖1
type: LoadBalancer
loadBalancerIP: 52.130.86.47
ports:
- port: 80
selector:
app:nginx
4. ExternalName:集群內pod訪問一個服務,此服務在集群之外,又想讓pod訪問到這個服務,如何做?pod網絡都是內網地址,即使請求能路由出去,外部的響應報文也無法回來。
spec:
type: ExternalName # 下圖2
externalName: my.database.example.com # cname必須能被DNS服務解析
圖1:
圖2:
5.nodePort、port、targetPort、hostPort解釋
1.nodePort
外部流量訪問k8s集群中service入口的一種方式(另一種方式是LoadBalancer),即nodeIP:nodePort是提供給外部流量訪問k8s集群中service的入口。比如外部用戶要訪問k8s集群中的一個Web應用,那么我們可以配置對應service的type=NodePort,nodePort=30001。其他用戶就可以通過瀏覽器http://node:30001訪問到該web服務。而數據庫等服務可能不需要被外界訪問,只需被內部服務訪問即可,那么我們就不必設置service的NodePort。
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: default
spec:
selector:
app: myapp
release: canary
type: NodePort
ports:
- port: 80 # myapp svc 監聽端口
targetPort: http # pod端口,這個名稱必須是在containers.ports中有定義(containers.ports.name)
#targetPort: 80
nodePort: 30080
2.Port
k8s集群內部服務之間訪問service的入口。即clusterIP:port是service暴露在clusterIP上的端口。mysql容器暴露了3306端口,集群內其他容器通過33306端口訪問mysql服務,但是外部流量不能訪問mysql服務,因為mysql服務沒有配置NodePort。對應的service.yaml如下:
apiVersion: v1
kind: Service
metadata:
name: mysql-service
namespace: default
spec:
selector:
name: mysql-pod
ports:
- port: 33306
targetPort: 3306
3.targetPort
容器的端口(最終的流量端口)。targetPort是pod上的端口,從port和nodePort上來的流量,經過kube-proxy流入到后端pod的targetPort上,最后進入容器。
制作容器時暴露的端口一致(使用DockerFile中的EXPOSE),例如官方的nginx(參考DockerFile)暴露80端口。 對應的service.yaml如下:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: default
spec:
selector:
name: nginx-pod
type: NodePort # 有配置NodePort,外部流量可訪問k8s中的服務
ports:
- port: 30080 # 服務訪問端口(service監聽端口)
targetPort: 80 # 容器端口
nodePort: 30001 # NodePort 如果不給值,docker會隨機給默認值
4.hostport
hostPort這是一種直接定義Pod網絡的方式。hostPort是直接將容器的端口與所調度的節點上的端口路由,這樣用戶就可以通過宿主機的IP加上來訪問Pod了,如:
apiVersion: v1
kind: Pod
metadata:
name: influxdb
spec:
containers:
- name: influxdb
image: influxdb
ports:
- containerPort: 8086
hostPort: 8086
5.總結
總的來說,port和nodePort都是service的端口,前者暴露給k8s集群內部服務訪問,后者暴露給k8s集群外部流量訪問。從上兩個端口過來的數據都需要經過反向代理kube-proxy,流入后端pod的targetPort上,最后到達pod內的容器。
6.創建redis service示例
1.創建ClusterIP類型的service:
vim redis-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: default
spec:
selector:
app: redis
role: logstor
# 不指定service類型,默認創建在集群內部使用的service,不手動指定ClusterIP,會隨機分配一個10.96.0.0/12網絡的IP,如果手動指定,一定要確認這個IP沒被分配,不和原有的service沖突。
clusterIP: 10.97.97.97 # 一旦被創建成功,無法再次apply修改。除非刪除svc重建。
type: ClusterIP
ports:
- port: 6379
# targetPort: redis #
targetPort: 6379
redis deployment:
[root@master01 service]# cat ../controll/pod-daemonset-controll.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: redis
role: logstor
template:
metadata:
labels:
app: redis
role: logstor
spec:
containers:
- name: redis
image: redis:6.0.3
ports:
- name: redis
containerPort: 6379
當一個service創建完成以后,會自動在集群的DNS中動態添加一個A記錄,我們可以通過這個服務名進行解析,格式為:
SVC_NAME>NS_NAME_DOMAIN.LTD.
集群默認的域名后綴:
svc.cluster.local.
redis.default.svc.cluster.local. # 對於redis service的域名
2.創建NodePort類型的service:
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: default
spec:
selector:
app: myapp
release: canary
# 不指定service類型,默認創建在集群內部使用的service,不手動指定ClusterIP,會隨機分配一個10.96.0.0/12網絡的IP,如果手動指定,一定要確認這個IP沒被分配,不和原有的service沖突。
clusterIP: 10.99.99.99 # 自定義集群內部service IP
type: NodePort
ports:
- port: 80 # myapp svc 監聽端口
targetPort: http # pod端口,這個名稱必須是在containers.ports中有定義(containers.ports.name)
#targetPort: 80
nodePort: 30080
myapp deployment:
[root@master01 service]# cat ../controll/pod-deploy-controll.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy-controll
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
name: myapp-deploy-controll
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: nginx:1.20.2
ports:
- name: http
containerPort: 80
7.使用ipvs模型的配置補充
編輯kubelet配置文件/etc/sysconfig/kubelet,設置其忽略Swap啟用的狀態錯誤,內容如下:
KUBE_EXTRA_ARGS="--fail-swap-on=false"
KUBE_PROXY_MODE=ipvs
# 安裝ipvs調度算法相關模塊
yum intall ip_vs,ip_vs_rr,ip_vs_wrr,ip_vs_sh,nf_conntrack_ipv45
HeadLess Service
有時不需要或不想要負載均衡,以及單獨的 Service IP。 遇到這種情況,可以通過指定 Cluster IP(spec.clusterIP)的值為 "None" 來創建 Headless Service。您可以使用headless Service 與其他服務發現機制進行接口,而不必與 Kubernetes 的實現捆綁在一起。典型應用就是Ingress。
vim headless-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: headless-svc
namespace: default
spec:
selector:
app: myapp
release: canary
clusterIP: None
ports:
- port: 80
targetPort: 80
kubectl apply -f headless-svc.yaml
kubectl get svc -o wide
dig -t A headless-svc.default.svc.cluster.local. @10.96.0.10
dig -t A myapp.default.svc.cluster.local. @10.96.0.10