前言:服務網格演變史
還記得17年的夏天,我第一次接觸docker,立刻就被容器化的新穎理念以及它帶來的種種優勢所震撼了
容器化帶給業界的衝擊是巨大的,不到短短一年的時間裡,容器化的部署和運維就已經徹底替代傳統機器部署成為了主流,同時docker也為服務端的發展形態帶來了非常多的可能性,使得“微服務”這一架構如雨後春筍般生長起來,迅速成熟
當服務的載體由虛擬機器器變為容器後,部署和運維的粒度更小了,但從巨集觀的角度來看,一個完整的服務系統變得更加零碎和複雜了 —— 數量眾多的微服務以及承載他們的容器交織成一張脈絡複雜的巨網,如何對這樣龐大的系統進行管理便成為一個難題
那一年,k8s還沒有“爆紅”,談到容器管理,人們的第一反應仍然是docker官方團隊著名的“三劍客”:
docker-machine提供底層的跨平臺虛擬
docker-compose解決複雜服務的自動部署
docker-swarm實現大型叢集的管理
一切看起來都很美妙,直到半路殺出google孕育的k8s,以其強大的功能和扁平易用的管理方式一統江湖,2018年我們幾乎再也看不到三劍客的身影,k8s和lstio以及它們所帶來的“服務網格”正在成為雲原生時代新的基礎設施,越來越多的大型系統開始在雲上構建和部署
作為一個工程師,應當有意識的去了解自己服務究竟生長在什麼樣的一片土壤上,這也正是本次開坑學習k8s的原因
整體概覽
什麼是k8s?
Kubernetes是一個用於容器叢集的自動化部署、擴容以及運維的開源平臺。
k8s誕生的目的
k8s孕育的初衷是培育出一個元件及工具的生態,幫助大家減輕在公有云及私有云上執行應用的負擔,換言之,使得大型分散式應用的構建和運維變得更加簡單(當然,越簡單的表面意味著越複雜的內部細節)。
整體架構圖
下面逐步展開介紹各個元件
元件一覽
Node: 硬體節點
Node是k8s中最小的計算硬體單元,它類似於傳統叢集中單臺機器的概念,是對硬體物理資源的一層抽象,它可以是真實機房的物理機器,又或者是雲平臺上的ECS,甚至可以是邊緣計算的一個終端。
無論如何,藉助Node的抽象,我們可以把任何一臺機器簡單的看做是一組CPU和RAM資源的組合,從而達到解耦的效果
Cluster: 叢集
對於大型系統,我們往往不會把關注點放在單個機器上,而是聚焦更大粒度的叢集。
在k8s中,一般將叢集看做一個整體,而不關心內部節點的狀態,叢集內部狀態的調整將由k8s自動完成。
Persistent Volumes: 持久卷
考慮到叢集內部的節點始終在發生排程和變動,所以所有節點內部的檔案系統都是易失的,無法保證持久,為了解決這一問題,k8s引入了持久卷的概念,用於對映實際的物理儲存節點(雲盤或者是物理磁碟),它可以隨時被掛載到任何的叢集上去。
Container: 容器
容器是打包好的執行環境,這點無需再多贅述。值得一提的是k8s中的容器支援不僅僅包含了docker,還支援一些其他的容器標準
Pod
這是k8s區別於其他容器編排平臺的一個顯著特點:它不直接執行容器,而是執行一種稱為Pod的高階結構,裡面封裝了一系列相關的容器,並共享相同的namespace和網路。
Pod也是k8s進行服務編排和縮擴容的基本單位,這意味著Pod裡所有的容器都會被一併縮放(不管是否有必要),因此定製Pod時應該使它的體積儘可能小一些。
另外還有一個和Pod相關的概念,就是副本集(Replica Sets),它是指在擴容時產生的Pod的複製
我們可以把上面幾個邏輯概念的關係用下圖表示:
Deployment: 部署
deployment是用於管理pod的抽象層,它的定位類似於docker-compose。
k8s一個很巧妙的地方在於它把deployment層設計成“過程無關”的,你只需要宣告你所期望的最終狀態,k8s將會自動為你排程pod並保證它們滿足你的預期。
Ingress: 入口
當我們將整個系統以及其精巧的內部結構搭建起來後,我們仍然需要一個通道,使得它能夠真正地與外界溝通,這就是Ingress
HelloWorld
瞭解一門技術最快的方法就是用它寫一個Hello World,由於真實的k8s需要部署在較大規模的叢集上,普通的開發PC顯然不能達到這個需求,所以使用官方提供的本地實驗環境工具minikube來做嘗試
(以下實踐均執行在OSX 10.11環境下)
準備
首先需要安裝minikube
+ kubectl
,因為minikube需要docker作為底層支援,所以你還需要先提前安裝好docker
,docker的安裝就不多贅述了,這裡說下如何在國內環境安裝另外兩個重要的元件:
-
kubectl
的安裝:wget https://storage.googleapis.com/kubernetes- release/release/v1.5.1/bin/darwin/amd64/kubectl chmod +x kubectl mv kubectl /usr/local/bin/kubectl 複製程式碼
-
minikube
的安裝:首先需要安裝
VirtualBox
作為底層的driver,然後從命令列安裝。這裡用的是阿里雲在國內的源,所以會比brew快很多curl -Lo minikube http://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/releases/v0.30.0/minikube-darwin-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/ 複製程式碼
安裝完畢後可以啟動k8s環境了,命令列執行minikube start
,可以看到它會自動更新和下載一些元件(這個過程可能會持續幾分鐘)
啟動完畢後執行minikube ssh
進入minikube的虛擬機器內部,執行docker ps
檢視所有的元件容器是否啟動成功
如果沒有問題退出登入,在外部執行minikube dashboard
即可在瀏覽器啟動控制檯,到這裡k8s的實驗環境就已經搭建完畢了
部署應用
k8s環境啟動後,就可以開始部署應用和服務了。首先我們需要一個可用的應用映象,這裡用我自己打包好的一個簡單的Http Hello World服務映象來做示範(映象地址:registry.cn-qingdao.aliyuncs.com/gold-faas/gold-rest-demo:1.0
)
接下來第一步就是建立Deployment,它將負責建立和更新我們的應用例項,並且持續監控應用的狀態。
使用kubectl
來建立一個deployment:
kubectl run helloworld --image=registry.cn-qingdao.aliyuncs.com/gold-faas/gold-rest-demo:1.0 --port=8080
複製程式碼
執行後master節點將會選擇一個合適的node來部署該應用(minikube環境下只有一個node),建立完成後可以使用kubectl get deployment
來檢視該應用:
此時控制檯中也可以看到相應的部署:
訪問應用
應用部署好後,暫時還只能在內部訪問,我們可以進入pod內部來做一個測試:
可以看到服務已經在正常執行了,如果想要在外部的終端訪問,可以簡單的使用kubectl proxy
來建立一個當前終端到k8s cluster的代理,然後來訪問我們的pod(可以先用kubectl get pod
來檢視pod名)
代理啟動後在新終端通過restful api的方式就可以通過代理訪問到內部pod所提供的服務,restful的url模式如下:
/api/v1/namespace/{namespace}/pods/{name}/proxy/{path:*}
複製程式碼
效果:
(這是k8s對外暴露的resftul api的一部分,是通過程式碼和網路手段控制k8s的重要手段,後面會再詳細展開講)
建立Service
上面使用proxy來訪問內部容器的方法更多適合在debug等場景下使用,當我們需要對外提供可用的真實服務時,需要更加可靠的手段,那就是Service
,可以暫時把它理解為一個集合了負載均衡、服務發現等功能的外部服務入口(後面再詳細展開)。
如圖,一個Service可以對映多個Pod,為了把多個Pod在邏輯上組合起來,k8s又引入了Label
的概念,簡單的說就是每個Pod上都可以打一個Label(標籤),具有相同Label的Pod就成為一個邏輯分組。Service就是通過Label Selector的方式來關聯多個Pod的,如下圖:
現在我們來建立一個Service並將它暴露到外部,通常可以有LoadBalancer
和NodePort
兩種手段,不過minikube只支援後者,使用kubectl expose
命令即可建立Service:
使用kubectl get service
我們可以看到已經建立的服務,其中kubernetes
是k8s預設已經建立好的。可以看到,新建立的service把對應pod的8080埠暴露到了外部的32344埠,接下來通過這個埠就可以訪問到hello world服務了:
這裡的ip是minikube的docker-daemon的ip,可以通過minikube docker-env
來檢視:
我們可以檢視一下service和pod的詳情,來看看Label是否按照我們預期的被建立:
label是key=value
的形式被建立的,如果想要自定義一些label,使用kubectl label
命令即可:
在pod和service非常多的時候,可以用作一種過濾的手段,使用-l引數即可進行篩選,就像sql的where語句一樣:
最後,如果想要刪除一個service,只需要執行kubectl delete service [服務名]
即可,當然服務刪除後pod仍然存在並且會持續執行,只是對外的入口消失了而已。
小結
到這裡,k8s的基礎概念已經介紹的差不多了,也瞭解瞭如何在k8s上部署應用和服務,get了大概的運作流程。不過目前能看到的只是k8s基礎能力的一部分,更多的實踐以及背後的工作原理,將會在後面的文章中陸續介紹。
原文地址: http://marklux.cn/blog/104, 轉載請註明出處