關注“Java藝術”一起來充電吧!
Docker
與Kubernetes
是什麼關係?這可能是我們剛接觸Kubernetes
時都有的一個疑問。那麼Kubernetes
是什麼?
Kubernetes
是一個容器集羣編排管理系統,用於實現容器集羣的自動化部署、自動擴縮容等功能。Docker
提供用於運行應用程序的容器技術,而Kubernetes
本身並不提供用於運行應用程序的容器,而是負責管理容器。
瞭解Docker
與Kubernetes
的關係之後,就能理解爲什麼我們要先學習Docker
再學習Kubernetes
,這與先學習Spring
框架才能更好地學習Spring Boot
、Spring Cloud
是一樣的。如果還不瞭解Docker
可以先看下上一篇《開發也需瞭解的運維知識之Docker》。
作爲開發,我們爲什麼要了解容器技術,這不是運維該學習的嗎?作爲開發者,只有足夠了解容器技術,才能做好技術選型,以及開發部署在Kubernetes
容器服務之上的應用應該要注意哪些問題。如果運維不瞭解代碼,開發也不瞭解Kubernetes
,誰能解決將服務遷移到Kubernetes
上遇到的各種問題呢?
關於Kubernetes
筆者學習Kubernetes
的路線,分享給大家:
官方學習文檔:http://docs.kubernetes.org.cn/
閱讀書籍:《
Kubernetes in Action
中文版》極客時間視頻教程:《
Spring Cloud
與Kubernetes
雲原生微服務實戰》
學習Kubernetes
首先要了解Kubernetes
的架構,瞭解一些“概念”,再瞭解配置文件。配置文件這塊對初學者來說是最難理解的,因此推薦大家閱讀《Kubernetes in Action
中文版》這本書,跟着例子一步步掌握一些配置文件中每種kind
的作用,每個配置項的作用是什麼。
Kubernetes
管理所有可用的物理機,以阿里雲容器服務Kubernetes
爲例,Kubernetes
負責管理一堆ECS
實例,這需要我們在創建Kubernetes
集羣時,購買足夠的ECS
實例,至少兩臺。後續也可將新購買的ECS
實例加到Kubernetes
集羣,由Kubernetes
管理。
開發者和運維都不需要知道一個應用程序部署在哪個ECS
實例上,只需要指定運行應用程序所需要的cpu
、內存等資源,Kubernetes
會根據要求計算出滿足條件的節點(ECS
),並在節點(ECS
)上從鏡像倉庫拉取應用程序的鏡像創建容器並運行容器,並且監控容器的整個生命週期。我們可以把Kubernetes
管理的所有節點(ECS
)看成一個大的物理機,這臺大的物理機的cpu
、內存是所有節點(ECS
)的總和。
(圖片來之《Kubernetes in Action
》)
如上圖所示,開發者只需要將應用構造成鏡像,並將鏡像push
到遠程鏡像倉庫,然後編寫一個配置文件,在配置文件中描述應用程序鏡像運行所需要的資源、鏡像從哪拉取等,使用kubectl
調用Kubernetes
提供的API
就能將應用程序部署到Kubernetes
。
Kubernetes
由兩種類型的節點組成。
(圖片來自《Kubernetes in Action
》)
一種是主節點Master
,負責控制和管理整個集羣,爲實現高可用,主節點也要求部署集羣。主節點上會部署一些組件,這些組件可以運行在單個主節點上,或者通過副本分別部署在多個主節點上,實現高可用。如基於Reft
協議實現的數據強一致性存儲服務etcd
、提供給我們使用的Kubernetes API
服務、調度應用部署的Scheculer
組件、執行集羣功能的Controller Manager
組件。這些組件我們可以先這麼簡單瞭解,暫時不用過於深究。
另一種是工作節點,運行用戶實際部署的應用。
假設我們在阿里雲購買了託管的Kubernetes
服務,那麼主節點就由阿里雲託管,而工作節點就是我們購買的ECS
實例,一個集羣中有多少個ECS
實例就是有多少個工作節點。
工作節點就是運行容器的機器,除了運行用於運行我們部署的應用程序的容器外,每個工作節點上還會運行一些組件,這些組件負責運行、監控和管理應用服務。如Docker
、Kubelet
、Kube-proxy
。Docker
我們已經很熟悉了;Kubelet
負責與主節點的Kubernetes API
服務通信,並管理它所在的工作節點的容器;Kube-proxy
負責組件之間的負載均衡網絡流量。
上圖是根據到目前爲止我們對Kubernetes
的瞭解所畫出的一個應用部署流程圖。
1、開發者在本地機器構建應用程序鏡像;
2、開發者將本地應用程序鏡像
psuh
到鏡像倉庫;3、開發者爲運行應用程序編寫描述文件(
yaml
配置文件);4、開發者使用
kubectl
調用Kubernetes API
將應用程序描述文件提交給Kubernetes
;5、
Scheduler
組件根據描述文件調度工作節點部署應用程序;6、在工作節點上由
Container runtime
負責從鏡像倉庫拉取鏡像、創建容器並運行容器;
在實際項目部署時,我們可能最關係也最難理解就是網絡和容器這部分內容。比如,在不使用Kubernetes
時,我們部署一個需要SSD
資源的應用程序時,先購買SSD
掛載在該服務器上,而使用Kubernetes
時,我們要告訴Kubernetes
只在具有SSD
的節點中選擇節點部署應用。網絡和容器卷的內容還是很多很複雜的,本篇就不過多介紹,後續文章中再介紹,當然也只是簡單的理解和怎麼去用,因爲筆者目前理解的也不多。
需要了解的一些概念
namespaces
:用於區分不同的資源,如測試環境資源、生產環境資源;當然也可以使用labels
區分。不指定namespaces
則默認使用default
,如果使用非defalut
名稱空間,則在使用kubectl
創建secret
、創建ServiceAccount
等都需要明確指定namespaces
。
節點(Node
):節點就是實際的機器或者虛擬機,例如阿里雲ECS
。
Pod
:Pod
是Kubernetes
創建或部署的最小基本單位,一個Pod
封裝一個或多個應用容器,存儲資源、一個獨立的網絡IP
以及管理控制容器運行方式的策略選項。
(圖片來自《Kubernetes in Action
》)
如上圖所示,當一個Pod
包含多個容器時,這些容器總是運行於同一個工作節點上,不會跨越多個工作節點。例如我們部署一個java
程序,可以在一個Pod
中運行多個該java
程序的容器。Pod
可以封裝緊密耦合的應用,它們需要由多個容器組成,它們之間能夠共享資源,例如前後端部署在一起(這個例子不恰當)。而對於我們開發java
微服務應用來說,一般一個Pod
只會運行一個容器,因此初學時可以不用過多去糾結這些概念。
Service
:Service
抽象的概念,是Pod
的邏輯分組,這一組Pod
能夠被Service
訪問到,通常是通過Label
、Selector
實現。例如:
apiVersion: v1
kind: Service
metadata:
name: demo-srv-service
namespace: sit
spec:
selector:
app: demo-srv
env: sit
ports:
- protocol: TCP
port: 80
targetPort: 8080
通過selector
匹配app
爲demo-srv
、env
爲sit
的一組Pod
,這組Pod
對應demo-srv-service
這個Service
。更簡單一點理解,假設我們部署一個java
程序,一個Pod
只啓動一個該java
程序的容器,那麼啓動多個該java
程序就對應多個Pod
,而這組Pod
對應同一個Service
。
ReplicationController
:ReplicationController
(簡稱RC
)是確保用戶定義的Pod
副本數保持不變。在用戶定義範圍內,如指定一個java
程序部署的集羣數量爲3
,如果Pod
超過3
(例如手動啓動),則RC
會終止額外的Pod
,如果少於3
(例如內存溢出導致),RC
會創建新的Pod
,始終保持在定義範圍。
ReplicaSet
:ReplicaSet
簡稱RS
,是RC
的升級版本。RS
和RC
之間的唯一區別是對選擇器(Selector
)的支持,這裏不做過多介紹。
Deployments
:Deployment
爲Pod
和ReplicaSet
提供聲明式更新。你只需要在Deployment
中描述你想要的目標狀態是什麼,Deployment Controller
就會幫你將Pod
和ReplicaSet
的實際狀態改變到你的目標狀態。
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-srv-deployment
namespace: sit
spec:
# 副本數,運行多少個`Pod`
replicas: 3
# 選擇器,使用標籤匹配
selector:
matchLabels:
app: demo-srv
template:
metadata:
# 標籤
labels:
app: demo-srv
env: sit
spec:
# 容器,指定多個容器就會在一個`Pod`內運行多個容器
containers:
- name: demo-srv
image: registry.cn-shenzhen.aliyuncs.com/wujiuye/demo-srv
DaemonSet
:確保每個節點(物理機器或者虛擬機)上只運行一個該應用的Pod
。如阿里雲的實現的日記收集,就是在每個節點上運行一個用於收集日記的應用程序容器,對應一個Pod
。
網絡通信
Pod
之間的網絡通信:
Kubernetes
集羣中的所有Pod
都在同一個共享網絡地址空間中,這意味着每個Pod
都可以通過其他Pod
的IP
地址來實現相互訪問。這也表示它們之間沒有NAT
網關。當兩個Pod
彼此之間發送網絡數據包時,它們都會將對方的實際IP
地址看作數據包中的源IP
。
無論是將兩個Pod
安排在單一的還是不同的工作節點上,同時不管實際節點間的網絡拓撲結構如何,這些Pod
內的容器都能夠像在局域網上的計算機一樣通信。
Service
之間的網絡通信:
Kubernetes Service
爲一組功能相同的Pod
提供單一不變的接入點。當服務存在時,它的IP
地址和端口不會改變。客戶端通過IP
地址和端口號建立連接,這些連接會被路由到提供該服務的任意一個Pod
上,會實現負載均衡。通過這種方式,客戶端不需要知道每個單獨的提供服務的Pod
的地址,這樣這些Pod
就可以在集羣中隨時被創建或移除。
假設現有一個項目,該項目有兩個微服務,分別是demo-srv
、demo-cap
。現在將這兩個服務部署到阿里雲容器服務Kubernetes
上,在控制檯的服務列表頁可以看到,這兩個服務都有一個集羣IP
,不管這個兩個服務部署多少個Pod
,也不管Pod
怎麼變,其它服務都可以通過這個集羣IP
訪問背後的Pod
,當然訪問背後Pod
也是實現負載均衡的。
也是因爲如此,我們開發微服務實現的服務發現都是基於Service
的,那麼在應用程序中實現負載均衡就顯得多餘了。
類型:
ClusterIP
:通過集羣的內部IP
暴露服務,選擇該值,服務只能夠在Kubernetes
集羣內部可以訪問。NodePort
:通過每個Node
上的IP
和靜態端口(NodePort)暴露服務。NodePort
服務會路由到ClusterIP
服務,這個ClusterIP
服務會自動創建。通過請求<NodeIP>:<NodePort>
,可以從集羣的外部訪問一個NodePort
服務。LoadBalancer
:如使用阿里雲提供的負載均衡器,可以向外部暴露服務。外部的負載均衡器可以路由到NodePort
服務和ClusterIP
服務。
本篇就介紹到這,Kubernetes
要學的知識點很多,但作爲開發,我們可能不會去過多的關注一些細節,本篇介紹的知識點是筆者認爲作爲開發應掌握的知識的。網絡、容器卷這部署建議多瞭解一些,網絡有關服務間的調用,而容器卷有關日記的打印、文件存儲,如果使用阿里雲容器服務,那麼日記這塊我們可以不輸出到文件,使用阿里提供的日記服務收集日記。但如果需要持久化存儲的服務,就必須要瞭解容器卷Volume
。
不懂的概念可以查閱官方文檔:http://docs.kubernetes.org.cn
想要深入學習還是推薦閱讀《Kubernetes in Action
》中文版
公衆號:Java藝術
掃碼關注最新動態