iT邦幫忙

2021 iThome 鐵人賽

DAY 14
1
DevOps

k8s 入門學習 30天系列 第 14

IT 鐵人賽 k8s 入門30天 -- day14 K8s Services explained

  • 分享至 

  • twitterImage
  •  

前言

這篇文章主要來介紹 Service 元件

內容會談到 Service 的功能與不同種 Services 類型與適合使用時機

Service

在 k8s 叢集裡, 每個 Pod 都有自己的內部 IP

內部 IP 是在 Pod 啟動時動態給予的

因此, 當 Pod 重起之後內部 IP 的就會跟原本的不同

所以使用內部 IP 來存取 Pod 不是個好方法

Service 元件提供了一個固定 IP 給 Pod

所以一旦讓 Pod 綁定 Service

就可以透過這個固定 IP 來存取 Pod

除了提供固定 IP 外, 當多個 Pod 掛載在同一個 Service 上時

Service 會對傳入的 request 做負載平衡

由於 Pod 綁定 Service 所以對於其他相關的服務只依賴於 Service 這個抽象層

所以對 Pod 間做到了鬆耦合

而對於 Pod 來說對內與對外的接口都是透過 Service 來做處理

在 k8s 叢集中, Service 類別分為好幾種, 以下就分別來介紹幾種比較常見的

ClusterIP Service

k8s 叢集, 預設的 Service 就是 ClusterIP Service

設定檔範例如下:

apiVersion: v1
kind: Service
metadata:
  name: microservice-one-service
spec:
  selector:
    app: microservice-one
  ports:
    - protocol: TCP
      port: 3200
      targetPort: 3000

上面設定檔, 如果 kind 部份直接設定成 Service

則預設就是給 ClusterIP Service

而實際上關於 ClusterIP Service 給的固定 IP 值是看 Pode 所處的結點 IP 範圍

如下圖所示:

如果想要查詢 Pod 所對應的 IP 可以使用以下指令

kubectl get pod -o wide

假設給定 Ingress, Service 與 Deployment 設定
ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress-no-third-host
spec:
  rules:
  - host: analytics.myapp.com
    http:
      paths:
      - path: "/"
        path: Prefix
        backend:
          service:
            name: microservice-one-service
            port:
              number: 3200

service-clusterIP.yaml 如下

apiVersion: v1
kind: Service:
metadata:
  name: microservice-one-service
spec:
  selector:
    app: microservice-one
  ports:
    - portocol: TCP
      port: 3200
      targetPort: 3000

deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: v
spec:
  replicas: 2
  ...
  template:
    metadata:
      labels:
        app: microservice-one

則 ingress 透過 Service 的 name 找到到相對應的路由

而 Service 透過 selector 比對 Deployment 中的 Pod 對應的 labels 找到對應的 Pod

舉例來說: 上面的 Service selector 為 app: microservice

而 Deployment 中 template 內的 metadata labels 也是相同的值

而 Service 要路由到 Pod 的 Port 則定義在 Service 的 TargetPort

封包路由如下圖:

EndPoint

當 k8s 叢集建立 Service, 同時也會建立 Endpoint 物件

EndPoint 物件會跟 Service 具有相同名稱, 除了 IP 資訊外多了一個 Port 資訊

下面是 k8s 官網 EndPoint 物件的設定檔範例

apiVersion: v1
kind: Endpoints
metadata:
  name: my-service
subsets:
  - addresses:
      - ip: 192.0.2.42
    ports:
      - port: 9376

EndPoint 物件用來紀錄哪個 Pod 屬於哪一個 Service

Service 定義的對外的 Port 可以由使用者定義

targetPort 則必須要開放到 Pod 內 Container 實際服務的 Port

Muti-Port Services

這類的 Service 代表同時會開放對應到兩個 Port

舉例來說: 假設 mongodb 除了本身外還有一個 mongodb-exporter 需要開發給 Prometheus app 存取, 設定檔如下

apiVersion: v1
kind: Service
metadata:
  name: mongodb-service
spec:
  selector:
    app: mongodb
  ports:
    - name: mongodb
      protocol: 27017
      targetPort: 27017
    - name: mongodb-exporter
      protocol: 9216
      targetPort: 9216 

注意的是, 如果同時服務兩個以上的 Port 就必須要設定名稱

Headless Service

Headless 只會連接一個 Pod

設定檔範例如下:

apiVersion: v1
kind: Service
metadata:
  name: mongodb-service
  selector:
    app: mongodb
  ports:
    - protocol: TCP
      port: 27017
      targetPort: 27017

當不需要做平衡負載時, 就可以使用 Headless Service

使用時機當想要只跟某個一特定的 Pod 做通訊

這種 Service 會使用在有狀態的應用, 比如 資料庫(mysql, mongodb), elastic search

因為有狀態的應用每個 Pod 並非相同, 像是資料庫只有 master Pod 才能做寫入

這類 Service 的 IP 會直接回應 Pod IP address

Sevice type 設定值

當要建立 Service 時, type 有三種值可以設定 ClusterIP, NodePort, LoadBalancer

ClusterIP

是 type 的預設值, 不需要特別設定

屬於內部 Service, 外面讀取不到

範例如下:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: ClusterIP

NodePort

就是對於每個結點 IP 開一個固定的 Port 來做端點

這類 Service 可以從外部經過以下形式的路徑來存取:

NodeIP: 開啟的 Port

設定檔範例如下:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort

假設一個 NodePort Service 定義如下:

apiVersion: v1
kind: Service
metadata:
  name: ms-service-nodeport
spec:
  type: NodePort
  selector: 
    app: microservice-one
  ports:
    - protocol: TCP
      port: 3200
      targetPort: 3000
      nodePort: 30008

則代表這個 microservice-one 服務的 Port 在定義的 nodePort 30008

而這個 NodePort 有一個範圍限定 30000-32767

然而, NodePort Service 因為直接開放結點的 Port 給外部來連接

因此不是一個安全的作法

LoadBalancer

LoadBalancer 類別讓 Service 可以透過 cloud provider 的負載平衡器來對外開放服務

其結構概念如下:

由結構圖可以發現當 type 為 LoadBalancer Service 建立時, 相對應的 NodePort Service 與 ClusterIP Service 也會自動建立

設定檔範例如下

apiVersion: v1
kind: Service
metadata:
  name: my-service-loadbalancer
spec:
  type: LoadBalancer
  selector:
    app: microservice-one
  ports:
    - protocol: TCP
      port: 3200
      targetPort: 3000
      nodePort: 30010

注意的是, 這邊的 nodePort 只開放給 loadBalancer 存取

loadBalancer 透過 nodePort 傳遞封包到結點然後透過對應的 ClusterIP Service 傳遞到對應的 Pod

後記

一般而言, 實務上不太會使用 NodePort Service 在正式環境上, NodePort Service 只會在測試階段拿來驗證服務
在 k8s 叢集, 用來把應用對外開放的元件一般來說是使用 loadBalancer 類型的 Service 外面對接 cloud provider 提供的 loadbalancer 或是直接使用 Ingress 對接 ClusterIP Service 來使用


上一篇
IT 鐵人賽 k8s 入門30天 -- day13 Deploying Stateful Apps with StatefulSet
下一篇
IT 鐵人賽 k8s 入門30天 -- day15 k8s Workload 簡介
系列文
k8s 入門學習 30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言