Kubernetes 服務選擇(selector)


本文轉載自https://freeaihub.com/kubernetes/service-selector.html,可在線進行體驗

K8S中的Service是一個抽象概念,它定義了一個服務的多個pod邏輯合集和訪問pod的策略,一般把service稱為微服務

舉個例子:一個a服務運行3個pod,b服務怎么訪問a服務的pod,pod的ip都不是持久化的重啟之后就會有變化。
這時候b服務可以訪問跟a服務綁定的service,service信息是固定的提前告訴b就行了,service通過Label Selector跟a服務的pod綁定,無論a的pod如何變化對b來說都是透明的。

創建服務對應的后端

先創建一個可以充當 backend pods 的 deployment

文件名:service-deployment-hello.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello
  labels:
    app: hello
spec:
  selector:
    matchLabels:
      app: hello
  replicas: 5
  template:
    metadata:
      labels:
        app: hello
    spec:
      containers:
      - name: hello
        image: nginx
        imagePullPolicy: IfNotPresent
        resources:
          requests:
            cpu: 100m
            memory: 100Mi
        ports:
        - containerPort: 80

這個普通的 Deployment。唯一需要注意的是 ports 信息,它顯示了這個 Pod 暴露了哪些端口,類似於 docker 中 expose 的意義。但是一般來講,這個信息是沒必要的。因為 Pod 具有唯一的集群內可訪問的 ip, 不會跟其他 Pod 產生沖突,任何監聽了 0.0.0.0 這樣地址的服務都可以通過 :的方式訪問。這里寫上的作用主要是提供一些更明確的信息,也方便一些工具比如 kubectl 的使用而已。

在終端執行如下命令創建 deployment:

ctr -n k8s.io i import /share/images/nginx.tar
kubectl create -f /share/lesson/kubernetes/service-deployment-hello.yaml

看下最終我們創建出來的 pods 結果

kubectl get po

然后我們來創建對應的 Service

文件名:service-svc-hello.yaml

apiVersion: v1
kind: Service
metadata:
  name: hello
  labels:
    app: hello
spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: hello

Service 的 spec 部分就是它的主要信息,主要包含以下內容:

  • ports: 是一個端口信息列表,也就是說一個 Service 可以管理多個端口的訪問。本身 Pod 可以對外暴露多個端口
    • port: service 綁定的端口,也就是這個 Service 所對應的 ip 監聽的端口
    • targetPort: backend 的端口,也就是 Pod 所暴露的端口
  • selector: 標簽選擇,符合這個標簽的 Pod 會作為這個 Service 的 backend。

在終端執行如下命令創建並查看:

kubectl create -f /share/lesson/kubernetes/service-svc-hello.yaml
kubectl get svc 

這條命令用來查看 default namespace 下的 Service 信息列表。因為 default namespace 是默認值,可不寫。 -o wide 會增加一些額外的信息展示,看下結果:

除了 yaml 中我們填寫的信息之外,kubernetes 幫我們補充了其他的默認信息:

  • Type: 類型,決定着 Service 如何對外提供服務。因為我們在 yaml 里未設置,所以這里用的默認值: ClusterIP, 具體有哪些可選的會在下面講解。
  • Cluster IP: 系統幫我們自動生成的 ip 地址。這個 ip 地址的范圍是可配置的,並且只能在集群內部訪問。

看下完整的 yaml:

kubectl get svc hello -o yaml

這里又比剛才的列表頁顯示了更多的信息,需要注意的如下:

  • sessionAffinity: 這是負載均衡里面比較常見的一個概念,就是讓來自於同一個 client 的請求落到同一個 backend 上。默認為 None。
  • ports[0].protocol: 端口協議,默認為 TCP ,目前只支持 TCP/UDP。

容器的輕量級特性,讓作為 backend 的 Pod 可以比傳統方式更加隨意地起停。Service 只記錄了 labelSelector,但具體的映射關系仍然需要有個地方記錄下來。當然這個工作是由 kubernetes 來完成,而不是用戶。記錄這個映射關系的資源就是 Endpoints,同一個 namespace 下與 Service 同名的 Endpoints Resource 即是這個映射關系的管理者。剛才我們創建好了 Service 之后,Kubernetes 已經幫我們創建好了相應的 Endpoints 資源:

kubectl get ep hello -o yaml

注:ep 是 endpoints 的簡稱。

主要信息在 subsets 里面,addresses 列表記錄了每個 backend 的信息,這里面的兩個 Pod 信息就是我們剛才創建的兩個 Pod 。addresses 里面記錄了 Pod 的 ip、所在的主機名稱、以及具體的 Resource Object 的引用。

下面我們可以通過訪問這個 service 的 ip(即CLUSTERIP) 來訪問這個服務了。

helloclusterip=$(kubectl get svc hello -o go-template --template='{{.spec.clusterIP}}')
echo $helloclusterip
curl $helloclusterip

其中$helloclusterip即上面的 service 生成之后所分配的 ip ,每次創建的 ip 都是不一樣的。

注意:

  • 我們的hello程序運行了一個頁面,其中顯示了運行其的 host 的 hostname, 在這個場景中就是 pod 的 hostname, 而 pod 的 hostname 一般就是其名字。
  • 這里我們可以觀察出來, Service 做了負載均衡,將流量轉發到了不同的pod實例上。

DNS

上面的使用 ip 的使用有一個很致命的問題,就是它不好記,而且不方便使用。如果你讓系統自動分配,那很難知道生成的結果是什么,無法提前配置。如果是自己選好固定的 ip ,服務多了又不好管理。而服務發現就解決了這個問題。我們仍然拿剛才的實驗繼續驗證下。

首先要注意的是,service 的 ip 是可以在 kubernetes 的 node 上和 pod 里面直接訪問的。但 dns 只能在 pod 里面訪問,因為它需要配置 kubernetes 的 dns 服務為解析服務器,而且還要配置其他參數。 kubernetes 在啟動每個 pod 時都會將這些配置好。

准備busybox pod

ctr -n k8s.io i import /share/images/busybox.latest.tar
kubectl create -f /share/lesson/kubernetes/busybox.yaml

進入busybox pod

kubectl exec -it busybox sh

使用域名訪問服務,而不是IP

wget -O- hello

可以看到,運行結果與上面通過 curl 是一樣的。那么它是怎么實現的呢?

我們用 nslookup 命令來探究下:

nslookup hello

nslookup 命令用於解析某一個域名,會得到如下類似的結果

Server:         10.96.0.10
Address:        10.96.0.10:53

Name:   hello.default.svc.cluster.local
Address: 10.96.177.43

這里我們需要注意的是:

(1)server 的地址,這里顯示的 server 就是 dns server, 它就是 kubernetes 中 dns 服務的地址。

kubectl get svc -n kube-system

在部署完集群后,這個 svc 就自動創建了。

(2)解析到的名字

dns server 幫我們解析到了正確的 ip ,但是后面顯示的域名比較長。這里涉及到了一個 dns search-path 的概念。我們看下 dns resolve 的配置文件。

cat /etc/resolv.conf

簡單來講,當我們查詢 hello 這個域名時,dns server 會幫我們查詢下面的幾個名字:

  • hello
  • hello.default.svc.cluster.local
  • hello.svc.cluster.local
  • hello.cluster.local

其中 hello.default.svc.cluster.local 是正確的域名,它的格式為..svc.。其中 suffix 是集群配置,而 namespace 則視具體的情況而定。有了 search path, kubernetes 的服務不僅實現了通過域名訪問,而且實現了最簡單的僅通過名字即可訪問的模式。在實際的業務場景中,這是非常便利的一個條件。想象一個常見的場景, 有一個 namespace 叫 http,里面有服務 a 、 b, 有一個 namespace 叫 storage, 里面有 redis、db 兩個服務,那么 a、b 之間的互相訪問只需要知道對方的名字即可,不需要知道它們所處的 namespace(可以方便地一起遷移)。而 a b 想要訪問 redis 或者 db, 那么也僅僅需要用 redis.storage 或者 db.storage 這兩個名字即可。

kubernetes 在線安裝過程錄屏

asciicast


免責聲明!

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



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