還記得上一篇文章我們使用 port-forward 實現將本地的接口轉發到 Kubernetes 中指定的 Pod 操作嗎?而 Service 元件就是 Kubernetes 特地為了用來定義『一群 Pod 要如何被連線及存取』 的元件,此舉不只將暴露端口的任務解耦抽象出來,更利用 Labels 和 Seletor 來識別需要套用該設定這些屬於非永久資源的 Pod,如此一來,當 Pod 被動態的創建或銷毀時,相較於直接使用 port-forward 的 Pod 將會失去他的暴露端口,而新創建出來的 Pod 會因為具有原來的 Labels 而繼續套用我們先前暴露端口的相關設定。
Service 是 Kubernetes 內定義的抽象化物件(object),官方網站的介紹傳神地描述它的基本(原始)用途。
A Kubernetes Service is an abstraction which defines a logical set of Pods and a policy by which to access them. Kubernetes Service 是個抽象化的概念,主要定義了邏輯上的一群 Pod 以及如何存取他們的規則。
簡單一句話描述就是帶著相同標籤、做類似事情的一群 Pod。
每個 Pod 本身會帶著一或多個不等的標籤在身上,當 Service 指定存取某些特定的標籤時,Label Selector 會根據 Pod 身上自帶的標籤進行分組,並回傳 Service 所要求的 Pod 資訊。

Service 作為中介層,避免使用者和 Pod 進行直接連線,除了讓我們服務維持一定彈性能夠選擇不同的 Pod 來處理請求外,某種程度上亦避免裸露無謂的 Port 而導致資安問題。
另外,也體現出雲服務架構設計中一個非常重要的觀念:
對於使用者而言,僅須知道有人會處理他們的請求,而毋須知道實際上處理的人是誰。
就讓我們來由把昨天 foo 再新增一個夥伴 bar ,並且使用 Service 來實作看看如何管理這兩個 Pod 吧:
// pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: foo
labels:
app: foo
type: demo
spec:
containers:
- name: foo
image: mikehsu0618/foo
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Pod
metadata:
name: bar
labels:
app: bar
type: demo
spec:
containers:
- name: bar
image: mikehsu0618/bar
ports:
- containerPort: 8080
撰寫 Service 設定 :
// service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
type: demo
type: LoadBalancer
ports:
- protocol: TCP
port: 8000
targetPort: 8080
apiVersion : Service 使用的Kubernetes API v1 版本metadata.name : 該 Service 的名稱。spec.type : 可以指定 Service 的型別,可以是NodePort或是LoadBalancer
spec.ports.port : 可以指定,創建的 Service 的 Cluster IP,是哪個 port number 去對應到targetPort 。spec.ports.nodePort : 可以指定Node物件是哪一個 port number,去對應到targetPort,若是在 Service 的設定檔中沒有指定的話,Kubernetes 會隨機幫我們選一個 port number。spec.ports.targetPort : targetPort 是我們指定的 Pod 的 port number,由於我們會在Pod中運行一個port number 8080 的 container (foo & bar),所以我們指定hello-service的特定port number 都可以導到該 container。spec.ports.protocol : 目前 Service 支援TCP 、 SCTP 與UDP 三種 protocol,預設為TCP 。spec.selector : selector 則會幫我們過濾,在範例中,我們創建的 Service 會將特定的 port number 收到的流量導向 Lable 為 type=demo 的 Pods。運行一下設定檔:
kubectl apply -f pod.yaml,service.yaml
查看服務狀態:
kubectl get services // 查看服務
or
kubectl get all // 查看全部元件狀態

由上圖可以看出我們順利的 run 起一個 LoadBalancer ,如果我們的Kubernetes Cluster是架在第三方雲端服務(cloud provider),例如 Amazon 或 Google Cloud Platform,我們可以透過這些 cloud provider 提供的 LoadBalancer ,幫我們分配流量到每個 Node ,而我們使用 docker-desktop 直接會預設幫我們把 External IP 指向到我們的 [localhost](http://localhost) 。
由此一來,當我們使用 curl 去 call 我的設定好的 8000端口 ,Kubernetes Service 就會將我們的流量隨機分配到 foo bar 這兩個 container 中。
curl localhost:8000

Kubernetes的Service 讓我們非常簡單的實現管理 Pod 流量以及 LoadBalance 的功能,在以前可是需要到雲端平台一個一個設定才可以辦到,Kubernetes 幫我們省下許多細節使我們可以專注在實現維運部署的邏輯上面,但背後的觀念非常值得我們回來細細咀嚼,在這裡只是先做一個簡單的小 demo,日後將會對 Service 的運作機制做更深入的了解。
千呼萬喚始出來!鐵人賽系列「從異世界歸來發現只剩自己不會 Kubernetes」同名改編作品出版了!
感謝所有交流指教的各路英雄,也感謝願意點閱文章的各位,如果能幫助到任何人都將會是我的榮幸。
本書內容改編自第 14 屆 iThome 鐵人賽 DevOps 組的優選系列文章《從異世界歸來發現只剩自己不會 Kubernetes》。此書是一本綜合性的指南,針對想要探索認識 Kubernetes 的技術人員而生。無論是初涉此領域的新手,還是已有深厚經驗的資深工程師,本書都能提供你所需的知識和技能。
「這本書不僅提供了豐富的範例程式碼和操作指南,讓身為工程師的我們能實際操作來加深認知;更重要的是,它教會我如何從後端工程師的角度去思考和應用 Kubernetes。從容器的生命週期、資源管理到部署管理,每一章都與我們的日常開發工作息息相關。」
──── 雷N │ 後端工程師 / iThome 鐵人賽戰友
天瓏連結: 從異世界歸來發現只剩自己不會 Kubernetes:初心者進入雲端世界的實戰攻略!
相關文章:
Reference
Kubernetes Service 深度剖析 - 標籤對於 Service 的影響
如果簡單加入解釋spec.type 的loadBalancer 會比較好。(加入幾個字,因為未必人人都熟識networking)
非常認同!但 Networking 很難幾個字解釋出來,我會再努力~
最後部份"curl localhost:8080" 後面的圖是顯示curl http://localhost:8000/ 結果.
已更正為 curl localhost:8000 呼叫 kubernetes service 的端口無誤
感謝~