03-K8S之service工作方式及使用


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM