轉載請注明出處:葡萄城官網,葡萄城為開發者提供專業的開發工具、解決方案和服務,賦能開發者。
第一章:Docker與k8s的恩怨情仇(一)—成為PaaS前浪的Cloud Foundry
第二章:Docker與k8s的恩怨情仇(二)—用最簡單的技術實現“容器”
第三章:Docker與k8s的恩怨情仇(三)—后浪Docker來勢洶洶
第四章:Docker與k8s的恩怨情仇(四)-雲原生時代的閉源落幕
第五章:Docker與k8s的恩怨情仇(五)——Kubernetes的創新
第六章:Docker與k8s的恩怨情仇(六)—— “容器編排”上演“終結者”大片
在上節中我們介紹了活字格想在k8s上部署,如何實現容器之間的編排與管理控制。為了進一步實現內外交互調用,則需要實現服務發現的功能。也就是我們前面提到“人與狗”之間的關系。
做過微服務的同學可能了解過什么叫服務發現,spring cloud項目中的Eureka框架就是完成這個功能的,其主要工作就是注冊內部的服務,以供其他集群的服務可以調用、訪問這個服務。
我們合理猜測Kubernetes的存在很有可能激發了各種微服務框架產生服務發現機制。
在Kubernetes中服務發現對應的模塊是Service與Ingress,接下來,我們分別來說說這兩個功能。
Service與Ingress
Service類似於服務的注冊功能。
其邏輯很簡單,在kubernetes聲明一個服務,從而生成一個VIP(虛擬網絡),所有Kubernetes集群中的其他組件,都可以通過這個VIP來訪問這個服務,並且這個服務是不會隨Service的改變而改變的,只要創建就是終生存在。
Service
而服務的內容是什么呢?這部分和上述的Deployment一樣,是通過selector選擇器確定的。我們可以通過下述yaml來創建一個服務:
apiVersion: v1
kind: Service
metadata:
name: hostnames
spec:
selector:
app: hostnames
ports:
- name: default
protocol: TCP
port: 80
targetPort: 9376
通過上一篇的介紹,我們可以了解這個服務所需要代理的內容是app==hostnames的Pod。同時這里也有一個新的字段ports,這個字段是說明該代理的服務的請求方式(protocol)、對外暴露的端口(port)、內部的端口(targetPort)分別是什么。
我們可以通過這個sample-service.yaml的文件創建一個Service並且查看一個Service:
# 創建
kubectl apply -f sample-service.yaml
# 查看
kubectl get services hostnames
在這個service中存在一個ClusterIP,這個IP就是這個Service生成的VIP,在集群內部的其他成員,都可以通過這個VIP來訪問這個Service。但是由於我們現在沒有任何的具體服務讓這個Service代理,因此現在請求這個IP是不會成功的。
那么,我們需要為這個Service創建一個具體實現:以下的sample-deployment.yaml文件是創建一個多副本的Pod,其Pod的功能是返回自己的podname:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hostnames
spec:
selector:
matchLabels:
app: hostnames
replicas: 3
template:
metadata:
labels:
app: hostnames
spec:
containers:
- name: hostnames
image: k8s.gcr.io/serve_hostname
ports:
- containerPort: 9376
protocol: TCP
~
在這段代碼中,我們把容器的9376端口暴露的出來,因為這個Pod是通過這個端口與外部通行的。同樣我們執行以下命令創建和查看這個pod副本:
# 創建
kubectl apply -f sample-deployment.yaml
# 查看
kubectl get pods -l app=hostnames
在這部分內容中可以看到這個pod副本已經創建成功了。此時,根據我上一節所說的控制器模式,Service也有對應的處理Service的控制器,其內部發現了有滿足app==hostnames的服務,即將這個服務和Service進行了綁定 。此時,我們就可以通過任意一台集群內的主機來請求剛才上文中的ClusterIP:
在這一部分可以看到,我們進行了很多次請求,但是每次返回的結果都不同,這是因為Service在其內部通過網絡插件(CNI)做了負載均衡處理,所以我們可以通過Service來實現的負載均衡功能。
學習過程中的“誤入歧路”
在學習了解這部分內容的時候,我一直有一個誤解:認為Service是必須對應Deployment這種Pod的編排控制器對象才能工作的,所以把Service --> Deployment --> Pods這條邏輯關系熟記於心,但這種理解其實是錯誤的。
在Kubernetes中,每個功能組件各司其職,他們只會處理自己該做的事,比如這里,Service綁定Pod所依賴的是選擇器中的app==hostnames,而這個定義是出現在Deployment中定義在Pod中的,因此Service和Deployment完全沒有關系,它們倆誰也不認識誰,關系可以用下圖來描述:
並且,在之前的學習中還錯誤地認為負載均衡服務是由Deployment提供的,其實這個功能是Service中的網絡插件來處理的,並且用戶同樣也可以自定義使用的網絡查件或者負載均衡算法是什么,Kubernetes給了用戶足夠大的自由度。
Ingress
有了Service之后,我們的服務就可以在集群中隨意訪問達到服務之間的交流關系了, 但是要想讓我們的服務讓最終的用戶訪問到,我們還需要最后一個組件Ingress。
Ingress是Kubernetes中的反向代理服務,它可以解析配置的域名指向到我們內部的Service中,其定義可以通過下述的yaml來實現:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: sample-ingress
spec:
rules:
- host: hostname.sample.com
http:
paths:
- path: /
backend:
serviceName: hostnames
servicePort: 80
上述代碼中,我們將hostname.sample.com這個域名指向了剛才定義的hostnames這個Service。通過這樣的操作,我們的服務便就可以通過定義域名配置供外部的服務進行訪問了。而Ingress的創建命令,也和前面所說的一樣:
kubectl apply -f sample-ingress.yaml
有了這部分配置,我們的功能原則上就能夠讓外部訪問了。但在實際應用中我們本地沒有可供測試的環境,本地的Kubernetes環境是通過kindD生成的,其核心是多個Docker Container而不是多台機器。上述內容在Container內部運行,是使用Docker模擬Kubernetes的功能,因此這也是本文中唯一無法驗證成功的一個功能模塊。
完整部署一個活字格應用
通過上節我們一起學習了Pod間的編排控制器的使用,本節中實現了內外交互調用,進一步實現服務發現的功能,我們現在就可以再次回到之前提出的問題: 究竟如何成功部署一個活字格應用。
通過介紹整個Kubernetes的基礎使用的流程,我們可以看到一個服務在Kubernetes變成Pod,通過Deployment部署,通過Service服務發現,通過Ingress反向代理的全過程,經過這些模塊的協力配合之后,我們的活字格應用終於可以部署在這個Kubernetes集群中了。
希望這張圖片展示,能夠為大家帶來更加直觀的感覺。
總結
截止到本章,我們已經完整介紹了活字格做k8s部署的全過程。下一節將會為大家帶來本系列文章的最后一篇——Kubernetes總覽,讓大家對Kubernetes集群內容部分有一個整體性印象,對一些深層次功能做一個總結。
感興趣的小伙伴不要錯過~我們下篇接着聊。