程式狂想筆記

一個攻城師奮鬥史

0%

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