Contents

Kubernetes 服務探索(Service Discovery)

Kubernetes Service 筆記

抽象圖小記

graph TD subgraph Kubernetes Cluster A[Service] --> N1[Nginx] A --> |Endpoints|N2[Nginx] A --> N3[Nginx] A --> N4[Nginx] APP -->|Access Service 訪問Virutal Server| A subgraph Node1 N1 N2 end subgraph Node2 N3 end subgraph Node3 N4 APP end end

簡單記錄一下,在沒有 Service,有很多服務,要怎麼分享出去使用是一個重要的課題。
不可能在程式設定多個IP,Service 透過 Virtual IP做分享內部服務。

Virtual IP 主要是做備援(HA)機制。不是在做LB。但是K8S是會做SLB。可以看相關 keepalived,利用LVS+keepalived的主從模式實現http的高可用性_實用技巧_程式人生,不過我沒有實做過。

使用上會使用DNS,${service}.${namespade}.cluster.local

實現 VIP和 Endpoint 轉化,有:

  1. Iptable(預設)
  2. Userspace
  3. IPVS

切換方法,是透過 kube-proxy --proxy-mode做切換。

Kubernates Service Type

  • ClusterIP
  • NodePort
  • Loadbalancer
  • ExternalName
  • Headless

Kubernetes — Service Types Overview | by Ashish Patel | DevOps Mojo | Medium

ClusterIP

來源端必須屬於 Cluster 內部,內部是指「各節點與運行中的Pod」。

沒有指定type,預設是 clusterIP

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

範例參考: Service | Kubernetes

  1. Port 對外存取的port。
  2. targetPort pod上面的對外的 port
    詳細可看:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#serviceport-v1-core

ServicePort v1 core裡面有寫詳細。

Kubernetes 元件處理 Service 流程

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
kubectl run alpaca-prod \
--image=gcr.io/kuar-demo/kuard-amd64:blue \
--port=8000 \
--labels="ver=1,app=alpaca,env=prod"

# 用 expose 創建一個 service
kubectl expose pod alpaca-prod

# 這邊很有趣,看 kubectl describe svc alpaca-prod
# 裡面
# spec:
#   clusterIP: 10.96.29.232
#   ports:
#   - port: 8000
#     protocol: TCP
#     targetPort: 8000
#   selector:
#     app: alpaca
#     env: prod
#     ver: "1"
#是用 selector 對應

kubectl get services -o wide
1
2
3
4
5
6
7
8
9
# 現在 kubectl run 產生 pod ,所以應該可以不用這段
# 這段是書寫的,之後改成 deployment 再嘗試
ALPACA_POD=$(kubectl get pods -l app=alpaca \
-o jsonpath='{.items[0].metadata.name}')

# $ALPACA_POD => alapaca-pod
kubectl port-forward $ALPACA_POD 48858:8080

# 執行完成可以用 localhost:48858 看到頁面

Cluster IP

Cluster IP 是虛擬 IP,通常會指定一個 DNS,通常 IP 不會更動,這樣就不會有 DNS 快取問題。
在 namespace ,我們只需要用 service 名稱連結 pod

Service DNS

用剛剛kubectl port-forward $ALPACA_POD 48858:8080
進去http://localhost:48858/裡面的DNS QUERY
name 輸入 alpaca-prod就可以找到

Debugging DNS Resolution | Kubernetes

alpaca-prod.default.svc.cluster.local

這邊可以看到 alpaca-prod後面 default 是 namespace
可以在 dns 搜尋 alpaca-prod.default 查詢到東西
完整的alpaca-prod.default.svc.cluster.local
也可以查詢到

1
2
3
4
5
6
7
8
;; opcode: QUERY, status: NOERROR, id: 22467
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;alpaca-prod.default.svc.cluster.local.	IN	 A

;; ANSWER SECTION:
alpaca-prod.default.svc.cluster.local.	30	IN	A	10.99.141.81

Readiness Prob

1
kubectl  edit deployment/alpaca-prod

由於這邊使用 pod 會有Forbidden: pod updates may not change fields other than

Kubernetes 對 Pod 的更新做了限制,除了更改 Pod 中容器(包括工作容器與初始化容器)的鏡像,以及 activeDeadlineSeconds (對 Job 類型的 Pod 定義失敗重試的最大時間), tolerations (Pod 對污點的容忍),修改其它部分將不會產生作用,如我們可以嘗試在前面 Pod 定義文檔 pod-test.yaml 中將宿主機端口 8081 改為 8082,重新執行 kubectl apply, 將提示如下錯誤,

參考:Kubernetes筆記(五):瞭解Pod(容器組) - 知乎

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
...
    livenessProbe:
      httpGet:
        path: /
        port: 80
        httpHeaders: # 此處header無意義,僅作示例
        - name: purpose
          value: for-test
      initialDelaySeconds: 2
      periodSeconds: 5

這邊就先不仔細研究

用 endpoints 觀察

使用 endpint 是尋找 service 將流量發送到何處地方,這邊會抓所有pod IP收集。

1
kubectl get endpoints alpaca-prod --watch

NodePort

ClusterIP功能都有,除了內部訪問,主機外面的
對每個節點(node)IP都可以被訪問Pod。

port: port Mapping(VIP使用)
targetPort: Service 8080 to Pod :80
nodePort: Node Port 30123 to Pod :80

nodePort 範圍 default(30000~32767),可以用 --service-node-port-range調整。

1
kubectl edit service alpaca-prod

TYPE 改成 NodeType
這個就跟 docker 設定 port 對外很像

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
Name:                     alpaca-prod
Namespace:                default
Labels:                   app=alpaca
                          env=prod
                          ver=1
Annotations:              <none>
Selector:                 app=alpaca,env=prod,ver=1
Type:                     NodePort
IP Families:              <none>
IP:                       10.99.141.81
IPs:                      <none>
Port:                     <unset>  8000/TCP
TargetPort:               8000/TCP
NodePort:                 <unset>  30306/TCP
Endpoints:                10.244.0.6:8000
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

這邊注意,由於我們使用 Kind 做測試
使用 nodePort 發現怎麼連不到
後來我注意到 node ,不應該是指操作 kubectl 主機上 面

1
kubectl get node -o wide

但是對 node 主機上 port 還是連不到

1
ssh <ndoe_ip> -L 8080:localhost:30306

不過看來 kind 不支源使用 nodeport

在考慮之後用 vagrant 環境跑跑看

LoadBalancer

一般雲端內件有提供這個功能
但好像也能自己架
這邊就不嘗試
如何建構 Kubernetes loadbalancer – BROBRIDGE
[Day12] 實作 Kubernetes 裸機 Load Balancer Part2 - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天

Endpoint

創建 Service 會一同建立 Endpoint

詳細:[Kubernetes] Service Overview | 小信豬的原始部落
感覺是 Service 底層操作元件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
kubectl describle endpints alpaca-prod
# Name:         alpaca-prod
# Namespace:    default
# Labels:       app=alpaca
#               env=prod
#               ver=1
# Annotations:  <none>
# Subsets:
#   Addresses:          10.244.0.6
#   NotReadyAddresses:  <none>
#   Ports:
#     Name     Port  Protocol
#     ----     ----  --------
#     <unset>  8000  TCP

# Events:  <none>
1
2
3
4
5
kubectl get endpints alpaca-prod --watch
# NAME          ENDPOINTS         AGE
# alpaca-prod   10.244.0.6:8000   6d2h
# alpaca-prod   <none>            6d2h  <--  kubectl delete pods alpaca-prod  
# alpaca-prod   10.244.0.7:8000   6d2h  <--  kubectl run alpaca-prod --image=gcr.io/kuar-demo/kuard-amd64:blue --port=8080 --labels="ver=1,app=alpaca,env=prod"  

建立 Service yaml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

簡單來說 Service 對印 selector 去抓含有 Label 的 Pod

kube-proxy

kube-proxy 每一台 node 主機上面都會有這個東西。
kube-proxy 會監測 service 和 endpoint 是否發生變化,會重寫該模組 iptables 規則。

詳細:

Cluster IP 環境變數

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
kubectl exec alpaca-prod -- env
# PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# HOSTNAME=alpaca-prod
# KUBERNETES_PORT_443_TCP_PROTO=tcp
# ALPACA_PROD_PORT_8000_TCP_PROTO=tcp
# KUBERNETES_SERVICE_HOST=10.96.0.1
# KUBERNETES_PORT=tcp://10.96.0.1:443
# KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
# ALPACA_PROD_PORT=tcp://10.99.141.81:8000
# ALPACA_PROD_PORT_8000_TCP_PORT=8000
# KUBERNETES_SERVICE_PORT_HTTPS=443
# KUBERNETES_PORT_443_TCP_PORT=443
# ALPACA_PROD_PORT_8000_TCP=tcp://10.99.141.81:8000
# ALPACA_PROD_PORT_8000_TCP_ADDR=10.99.141.81
# KUBERNETES_SERVICE_PORT=443
# KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
# ALPACA_PROD_SERVICE_HOST=10.99.141.81
# ALPACA_PROD_SERVICE_PORT=8000

清除所有建立物件

1
2
3
4
# 查看之前建立有app label 的 pods , services 狀態
kubectl get pods,services  -l app
# 刪除 app label 物件
kubectl delete services,deployments,pods -l app