kubernetes系列08—service資源詳解

本文收錄在容器技術學習系列文章總目錄html

一、認識service

1.1 爲何要使用service

  Kubernetes Pod 是有生命週期的,它們能夠被建立,也能夠被銷燬,然而一旦被銷燬生命就永遠結束。 經過 ReplicationController 可以動態地建立和銷燬 Pod(例如,須要進行擴縮容,或者執行 滾動升級)。 每一個 Pod 都會獲取它本身的 IP 地址,即便這些 IP 地址不老是穩定可依賴的。 這會致使一個問題:在 Kubernetes 集羣中,若是一組 Pod(稱爲 backend)爲其它 Pod (稱爲 frontend)提供服務,那麼那些 frontend 該如何發現,並鏈接到這組 Pod 中的哪些 backend 呢?答案是:Servicenode

 

1.2 service介紹

  Kubernetes Service 定義了這樣一種抽象:一個 Pod 的邏輯分組,一種能夠訪問它們的策略 —— 一般稱爲微服務。 這一組 Pod 可以被 Service 訪問到,一般是經過 Label Selector(下面咱們會講到咱們爲何須要一個沒有label selector的服務)實現的。redis

  舉個例子,考慮一個圖片處理 backend,它運行了3個副本。這些副本是可互換的 —— frontend 不須要關心它們調用了哪一個 backend 副本。 然而組成這一組 backend 程序的 Pod 實際上可能會發生變化,frontend 客戶端不該該也不必知道,並且也不須要跟蹤這一組 backend 的狀態。 Service 定義的抽象可以解耦這種關聯。算法

  對 Kubernetes 集羣中的應用,Kubernetes 提供了簡單的 Endpoints API,只要 Service 中的一組 Pod 發生變動,應用程序就會被更新。 對非 Kubernetes 集羣中的應用,Kubernetes 提供了基於 VIP 的網橋的方式訪問 Service,再由 Service 重定向到 backend Podvim

 

1.3 三種代理模式

  •  userspace 代理模式(K8S 1.1以前版本)
  •  iptables 代理模式(K8S 1.10以前版本)
  •  ipvs 代理模式(K8S 1.11 以後版本,激活ipvs須要修改配置)

1.3.1 userspace 代理模式

  這種模式,kube-proxy 會監視 Kubernetes master  Service 對象和 Endpoints 對象的添加和移除。 對每一個 Service,它會在本地 Node 上打開一個端口(隨機選擇)。 任何鏈接到代理端口的請求,都會被代理到 Service backend Pods 中的某個上面(如 Endpoints 所報告的同樣)。 使用哪一個 backend Pod,是基於 Service  SessionAffinity 來肯定的。 最後,它安裝 iptables 規則,捕獲到達該 Service  clusterIP(是虛擬 IP)和 Port 的請求,並重定向到代理端口,代理端口再代理請求到 backend Pod後端

  網絡返回的結果是,任何到達 Service IP:Port 的請求,都會被代理到一個合適的 backend,不須要客戶端知道關於 KubernetesService、或 Pod 的任何信息。api

  默認的策略是,經過 round-robin 算法來選擇 backend Pod。 實現基於客戶端 IP 的會話親和性,能夠經過設置 service.spec.sessionAffinity 的值爲 "ClientIP" (默認值爲 "None")。bash

 

 1.3.2 iptables 代理模式

  這種模式,kube-proxy 會監視 Kubernetes master  Service 對象和 Endpoints 對象的添加和移除。 對每一個 Service,它會安裝 iptables 規則,從而捕獲到達該 Service  clusterIP(虛擬 IP)和端口的請求,進而將請求重定向到 Service 的一組 backend 中的某個上面。 對於每一個 Endpoints 對象,它也會安裝 iptables 規則,這個規則會選擇一個 backend Pod服務器

  默認的策略是,隨機選擇一個 backend實現基於客戶端 IP 的會話親和性,能夠將 service.spec.sessionAffinity 的值設置爲 "ClientIP" (默認值爲 "None")。網絡

  和 userspace 代理相似,網絡返回的結果是,任何到達 Service IP:Port 的請求,都會被代理到一個合適的 backend,不須要客戶端知道關於 KubernetesService、或 Pod 的任何信息。 這應該比 userspace 代理更快、更可靠。然而,不像 userspace 代理,若是初始選擇的 Pod 沒有響應,iptables 代理可以自動地重試另外一個 Pod,因此它須要依賴 readiness probes

 

1.3.3 ipvs代理模式

  ipvs (IP Virtual Server) 實現了傳輸層負載均衡,也就是咱們常說的4LAN交換,做爲 Linux 內核的一部分。ipvs運行在主機上,在真實服務器集羣前充當負載均衡器。ipvs能夠將基於TCPUDP的服務請求轉發到真實服務器上,並使真實服務器的服務在單個 IP 地址上顯示爲虛擬服務。

  在kubernetes v1.8 中引入了 ipvs 模式,在 v1.9 中處於 beta 階段,在 v1.11 中已經正式可用了。 iptables 模式在 v1.1 中就添加支持了,從 v1.2 版本開始 iptables 就是 kube-proxy 默認的操做模式,ipvs iptables 都是基於netfilter的, ipvs 模式和 iptables 模式之間的差別:

  •  ipvs 爲大型集羣提供了更好的可擴展性和性能
  •  ipvs 支持比 iptables 更復雜的複製均衡算法(最小負載、最少鏈接、加權等等)
  •  ipvs 支持服務器健康檢查和鏈接重試等功能

  同時ipvs 也依賴 iptablesipvs 會使用 iptables 進行包過濾、SNATmasquared(假裝)。具體來講,ipvs 將使用ipset來存儲須要DROPmasquared的流量的源或目標地址,以確保 iptables 規則的數量是恆定的,這樣咱們就不須要關心咱們有多少服務了

ipvs雖然在v1.1版本中已經支持,可是想要使用,還需激活ipvs

修改配置文件

[root@master ~]# vim /etc/sysconfig/kubelet
KUBE_PROXY=MODE=ipvs

編寫腳本,讓kubelet所在的主機,啓動時裝入如下幾個模塊:

ip_vsip_vs_rrip_vs_wrrip_vs_shnf_conntrack_ipv4

 

1.4 service定義資源清單幾個字段

  •  apiVersionv1  版本
  •  kindService  類型
  •  metadata  元數據
  •  spec  指望狀態
    •  ports:服務公開的端口列表;把哪一個端口和後端創建聯繫
      •  port:此服務將公開的端口
      •  targetPort:要在服務所針對的pod上訪問的端口的編號或名稱
      •  nodePortK8S 集羣節點上的端口
    •  selector:標籤選擇器;關聯到哪些pod資源上
    •  clusterIP:服務的IP地址,一般由主服務器隨機分配
    •  type:肯定服務的公開方式。 默認爲ClusterIP
      •  ClusterIP(默認)
      •  NodePort
      •  LoadBalancer
      •  ExternelName
    •  sessionAffinityservice負載均衡,默認值是None,根據iptables規則隨機調度;可以使用sessionAffinity保持會話連線;
  •  status  當前狀態

 

1.5 service4中類型

  •  ClusterIP(默認):僅用於集羣內通訊,集羣內部可達,能夠被各pod訪問,節點自己可訪問;
  •  NodePort:構建在ClusterIP上,並在路由到clusterIP的每一個節點上分配一個端口;
    •  client ---> NodeIP:NodePort ---> ClusterIP:ServicePort ---> PodIP:containePort
  •  LoadBalancer:構建在NodePort上,並建立一個外部負載均衡器(若是在當前雲中受支持),它將路由到clusterIP
  •  ExternelName:經過CNAMEserviceexternalName的值(好比:foo.bar.example.com)映射起來. 要求kube-dns的版本爲1.7或以上.

 

二、建立clusterIP類型的service

1)編寫yaml文件並建立名爲redisservice

先建立一個deployment,啓動一個redis pod;在使用service綁定這個pod

[root@master manifests]# vim redis-svc.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:4.0-alpine
        ports:
        - name: redis
          containerPort: 6379
---
apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: default
spec:
  selector:
    app: redis
    role: logstor
  clusterIP: 10.99.99.99
  type: ClusterIP
  ports:
  - port: 6380
    targetPort: 6379
[root@master manifests]# kubectl apply -f redis-svc.yaml
deployment.apps/redis created
service/redis created

  

2)查詢驗證

[root@master ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP    142d
redis        ClusterIP   10.99.99.99   <none>        6380/TCP   12s
---查詢service詳細信息,pod綁定成功
[root@master ~]# kubectl describe svc redis
Name:              redis
Namespace:         default
Labels:            <none>
Annotations:       kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"redis","namespace":"default"},"spec":{"clusterIP":"10.99.99.99","ports":[{"por...
Selector:          app=redis,role=logstor
Type:              ClusterIP
IP:                10.99.99.99
Port:              <unset>  6380/TCP
TargetPort:        6379/TCP
Endpoints:         10.244.2.94:6379
Session Affinity:  None
Events:            <none>

  

三、建立NodePort類型的service

3.1 建立service

1)編寫yaml文件並建立名爲myappservice

先建立一個deployment,啓動3myapp pod;在使用service綁定這3pod

[root@master manifests]# vim myapp-svc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      release: canary
  template:
    metadata:
      labels:
        app: myapp
        release: canary
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        ports:
        - name: http
          containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  selector:
    app: myapp
    release: canary
  clusterIP: 10.97.97.97
  type: NodePort
  ports:
  - port: 80
    targetPort: 80
    nodePort: 31180
[root@master manifests]# kubectl apply -f myapp-svc.yaml
deployment.apps/myapp-deploy unchanged
service/myapp created

  

2)查詢驗證

[root@master ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP        145d
myapp        NodePort    10.97.97.97   <none>        80:31180/TCP   39s
redis        ClusterIP   10.99.99.99   <none>        6380/TCP       2d
[root@master ~]# kubectl describe svc myapp
Name:                     myapp
Namespace:                default
Labels:                   <none>
Annotations:              kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"clusterIP":"10.97.97.97","ports":[{"nod...
Selector:                 app=myapp,release=canary
Type:                     NodePort
IP:                       10.97.97.97
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  31180/TCP
Endpoints:                10.244.1.96:80,10.244.2.101:80,10.244.2.102:80
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

  

3)在集羣外訪問服務

 

3.2 使用sessionAffinity保持會話鏈接

1sessionAffinity默認是None,沒有修改前,訪問業務是隨機調度

[root@master ~]# while true; do curl 192.168.10.103:31180/hostname.html; sleep 1; done
myapp-deploy-69b47bc96d-mmb5v
myapp-deploy-69b47bc96d-wtbx7
myapp-deploy-69b47bc96d-wtbx7
myapp-deploy-69b47bc96d-cj48v
... ...

  

2)打補丁修改sessionAffinityclientip;實現會話鏈接

也可使用exec修改;或者直接修改yaml文件也能夠;

[root@master ~]# kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"ClientIP"}}'
service/myapp patched

  

3)查詢驗證

[root@master ~]# kubectl describe svc myapp
Name:                     myapp
Namespace:                default
Labels:                   <none>
Annotations:              kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"myapp","namespace":"default"},"spec":{"clusterIP":"10.97.97.97","ports":[{"nod...
Selector:                 app=myapp,release=canary
Type:                     NodePort
IP:                       10.97.97.97
Port:                     <unset>  80/TCP
TargetPort:               80/TCP
NodePort:                 <unset>  31180/TCP
Endpoints:                10.244.1.96:80,10.244.2.101:80,10.244.2.102:80
Session Affinity:         ClientIP
External Traffic Policy:  Cluster
Events:                   <none>

  

4)訪問業務查詢驗證;發現同一客戶端的請求始終發往同一pod

[root@master ~]# while true; do curl 192.168.10.103:31180/hostname.html; sleep 1; done
myapp-deploy-69b47bc96d-cj48v
myapp-deploy-69b47bc96d-cj48v
myapp-deploy-69b47bc96d-cj48v
myapp-deploy-69b47bc96d-cj48v
... ...

  

5)從新打補丁修改成None,當即恢復爲隨機調度

[root@master ~]# kubectl patch svc myapp -p '{"spec":{"sessionAffinity":"None"}}'
service/myapp patched
[root@master ~]# while true; do curl 192.168.10.103:31180/hostname.html; sleep 1; done
myapp-deploy-69b47bc96d-cj48v
myapp-deploy-69b47bc96d-mmb5v
myapp-deploy-69b47bc96d-cj48v
myapp-deploy-69b47bc96d-mmb5v

  

四、建立無頭service

1)編寫yaml文件並建立名爲myapp-svcservice

綁定上面建立myapp3pod

[root@master manifests]# vim myapp-svc-headless.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
  namespace: default
spec:
  selector:
    app: myapp
    release: canary
  clusterIP: None
  ports:
  - port: 80
    targetPort: 80
[root@master manifests]# kubectl apply -f myapp-svc-headless.yaml
service/myapp-svc created

  

2)查詢驗證

[root@master ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1     <none>        443/TCP        145d
myapp        NodePort    10.97.97.97   <none>        80:31180/TCP   2h
myapp-svc    ClusterIP   None          <none>        80/TCP         6s
redis        ClusterIP   10.99.99.99   <none>        6380/TCP       2d

  

3)和有頭正常myappservice對比

無頭service的解析:

[root@master manifests]# dig -t A myapp-svc.default.svc.cluster.local. @10.96.0.10
... ...
;; ANSWER SECTION:
myapp-svc.default.svc.cluster.local. 5 IN A	10.244.1.96
myapp-svc.default.svc.cluster.local. 5 IN A	10.244.2.101
myapp-svc.default.svc.cluster.local. 5 IN A	10.244.2.102
... ...

有頭正常myappservice的解析:

[root@master manifests]# dig -t A myapp.default.svc.cluster.local. @10.96.0.10
... ...
;; ANSWER SECTION:
myapp.default.svc.cluster.local. 5 IN	A	10.97.97.97
... ...
相關文章
相關標籤/搜索