【K8s學習筆記】K8s是如何部署應用的?
阿新 • • 發佈:2020-06-21
## 本文內容
![](https://img2020.cnblogs.com/blog/1149398/202006/1149398-20200620120651443-1149123992.png)
本文致力於介紹K8s一些基礎概念與串聯部署應用的主體流程,使用Minikube實操
## 基礎架構概念回顧
溫故而知新,上一節[【K8S學習筆記】初識K8S 及架構元件](https://www.cnblogs.com/hellxz/p/first-impression-of-k8s.html) 我們學習了K8s的發展歷史、基礎架構概念及用途,本節講的內容建立在其上,有必要把之前的架構小節提出來回顧下:
> K8s架構分為控制平臺(位於的Master節點)與執行節點Node
>
> 控制平臺包含:
>
> - kube-apiserver(訪問入口,接收命令)
>
> - etcd(KV資料庫,儲存叢集狀態與資料)
>
> - kube-scheduler(監控節點狀態,排程容器部署)
>
> - kube-controller-manager(監控叢集狀態,控制節點、副本、端點、賬戶與令牌)
>
> - cloud-controller-manager(控制與雲互動的節點、路由、服務、資料卷)
>
> 執行節點包含:
>
> - kubelet(監控與實際操作容器)
>
> - kube-proxy(每個節點上執行的網路代理,維護網路轉發規則,實現了Service)
>
> - 容器執行時環境CRI(支援多種實現K8s CRI的容器技術)
接下來需要引入 Pod 與 Service 的概念,這也是在上一篇文章中未給出的
## Pod、Service與Label概念
### Pod概念與結構
Pod 是 K8s最重要的基本概念,官網給出概念:Pod是Kubernates可排程的最小的、可部署的單元。怎麼理解呢?最簡單的理解是,Pod是一組容器。
再詳細些,Pod是一組容器組成的概念,這些容器都有共同的特點:
- 都有一個特殊的被稱為“根容器”的Pause容器。Pause容器映象屬於K8s平臺的一部分
- 包含一個或多個緊密相關的使用者業務容器。假設個場景:業務容器需要獨立的redis提供服務,這裡就可以將它們兩個部署在同一Pod中。
下邊是Pod的組成示意圖:
![](https://img2020.cnblogs.com/blog/1149398/202006/1149398-20200620111300659-1056373233.jpg)
為什麼Kubernetes會設計出一個全新的概念與Pod會有這樣特殊的結構呢?
- 原因之一:K8s需要將一組容器視為一個單元處理。當其中某些容器死亡了,此時無法判定這組容器的狀態。而當成一個單元,只要其中有一個容器掛了,這個單元就判定掛了。
- 原因之二:通過Pause共享容器IP,共享Pause掛接的Volume,簡化密切關聯的業務容器之間的通訊問題和檔案共享問題
K8s為每個Pod都分配了唯一的IP地址,稱為Pod IP,一個Pod裡的多個容器共享Pod IP地址。需要牢記的一點是:在 kubernetes 裡,一個 Pod 裡的容器與另外主機上的 Pod 容器能夠直接通訊。
### Pod的建立流程
當一個普通的Pod被建立,就會被放入etcd中儲存,隨後被 K8s Master節點排程到某個具體的Node上並進行繫結(Binding),隨後該Pod被對應的Node上的kubelet程序例項化成一組相關的Docker容器並啟動。
當Pod中有容器停止時,K8s 會自動檢測到這個問題並重啟這個 Pod(Pod裡所有容器);如果Pod所在的Node宕機,就會將這個Node上的所有Pod重新排程到其他節點上。
![](https://img2020.cnblogs.com/blog/1149398/202006/1149398-20200620114650288-388778616.jpg)
> 細心的讀者是否發現:
>
> 當Pod越來越多,Pod IP 也越來越多,那是如何從茫茫IP地址中找到需要的服務呢?換句話來說,是否有一種提供唯一入口的機制,來完成對Pod的訪問,而無需關心訪問到具體是哪個Pod(who care :happy:)?
>
> Kubernetes 提供了這種機制,稱之為 Service。
### Service概念
Service服務是Kubernetes裡的核心資源物件之一,從名稱上來看,理解其為一個”服務“也不為過,Service的作用是為相同標識的一系列Pod提供唯一的訪問地址。
> Service使用的唯一地址稱為ClusterIP,僅當在叢集內的容器才能通過此IP訪問到Service
它具體實現對一系列Pod繫結,需要再引入Label的概念,才能做出解答。
### Label概念
Kubernetes 提供了Label(標籤)來對Pod、Service、RC、Node等進行標記。相當於打標籤,Label可以是一組KV鍵值對,也可以是一個set
一個資源物件可以定義任意數量的Label,同一個Label可以新增到任意數量的資源物件上。通常由定義資源物件時新增,建立後亦可動態新增或刪除。
![](https://img2020.cnblogs.com/blog/1149398/202006/1149398-20200620123903294-109764052.jpg)
![](https://img2020.cnblogs.com/blog/1149398/202006/1149398-20200620123932902-1782116128.jpg)
### Service如何動態繫結Pods?
原來,在定義 Pod 時,設定一系列 Label 標籤,Service 建立時定義了 Label Selector(Label Selector 可以類比為對 Label 進行 SQL 的 where 查詢),kube-proxy 程序通過 Service的Label Selector 來選擇對應的 Pod,自動建立每個 Service 到對應 Pod 的請求轉發路由表,從而實現 Service 的智慧負載均衡機制。
![](https://img2020.cnblogs.com/blog/1149398/202006/1149398-20200620162518779-1756951607.jpg)
小結:Pod是K8s最小的執行單元,包含一個Pause容器與多個業務容器,每個Pod中容器共享Pod IP,容器之間可直接作用Pod IP通訊;Label是一種標籤,它將標籤打在Pod上時,Service可以通過定義Label Selector(Label查詢規則)來選擇Pod,具體實現路由表建立的是kube-proxy
## 部署應用實踐(Minikube)
安裝kubectl需要安裝成本地服務,這裡是debian10,更多參考https://developer.aliyun.com/mirror/kubernetes
```bash
sudo su -
apt-get update && apt-get install -y apt-transport-https
curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
cat </etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubectl
exit
```
下載安裝Minikube(阿里雲修改版):
```bash
curl -Lo minikube-linux-amd64-1.11.0-aliyuncs http://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/releases/v1.11.0/minikube-linux-amd64
sudo install minikube-linux-amd64-1.11.0-aliyuncs /usr/local/bin/minikube
```
> 使用魔改版是因為官方程式碼裡有些地方寫死了地址,而國內無法訪問
部署k8s叢集:
```bash
minikube start --driver docker --image-repository registry.cn-hangzhou.aliyuncs.com/google_containers --kubernetes-version v1.18.3
```
![](https://img2020.cnblogs.com/blog/1149398/202006/1149398-20200620153717911-524847325.png)
> 本地有docker時使用此driver,其他可選的虛擬化技術參考https://minikube.sigs.k8s.io/docs/drivers/ 選擇
```bash
#部署一個Pod,Pod的deployment是一種預設的無狀態多備份的部署型別
kubectl create deployment hello-minikube --image=registry.cn-hangzhou.aliyuncs.com/google_containers/echoserver:1.4
#檢視叢集中當前的Pod列表
kubectl get pods
#建立的NodePort型別Service,將所有Node開放一個埠號,通過這個埠將流量轉發到Service以及下游Pods
kubectl expose deployment hello-minikube --type=NodePort --port=8080
#minikube提供的特色功能,直接通過瀏覽器開啟剛才建立的Service
minikube service hello-minikube
```
![](https://img2020.cnblogs.com/blog/1149398/202006/1149398-20200620155937048-412359598.png)
自動開啟瀏覽器訪問服務(Minikube特色功能)
![](https://img2020.cnblogs.com/blog/1149398/202006/1149398-20200620235606000-1972383929.png)
檢視Pod的描述資訊
```bash
kubectl describe pod hello-minikube
```
![](https://img2020.cnblogs.com/blog/1149398/202006/1149398-20200620161659326-1466659705.png)
> 最下方可以清楚得看到K8s叢集default-scheduler成功指派我們要求的Pod在節點minikube上建立,kubelet收到資訊後,拉取映象並啟動了容器
## 部署流程原理簡述
1. `kubectl` 傳送建立 deployment 型別、名為`hello-minikube`的Pod 請求到 `kube-apiserver`
2. `kube-apiserver` 將這條描述資訊存到 etcd
3. `kube-scheduler` 監控 etcd 得到描述資訊,監測Node負載情況,建立Pod部署描述資訊到etcd
4. 待部署Node的`kubelet`監聽到 etcd 中有自己的部署Pod資訊,取出資訊並按圖拉取業務映象,建立pause容器與業務容器(此時叢集外部無法訪問)
5. `kubectl` 執行`expose`命令,同時將建立Service與NodePort資訊存到etcd中
6. 各節點`kube-proxy`監聽到etcd變化,建立邏輯上的Service與路由資訊,開闢NodePort
7. 當請求到達`<任意Node節點IP>:` 時,根據路由錶轉發到指定的Service上,負載均衡到Pod,提供服務
叢集外部訪問:
![](https://img2020.cnblogs.com/blog/1149398/202006/1149398-20200621004737866-1074205814.png)
**參考**
- https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/
- https://kubernetes.io/docs/concepts/services-networking/
- https://minikube.sigs.k8s.io/docs/start/
- https://minikube.sigs.k8s.io/docs/handbook/controls/
- 《Kubernetes權威指南》第 4 版
> 行文過程中難免出現錯誤,還請讀者評論幫忙改正,大家共同進步,在此感謝
轉載請註明出處,文章中概念引入《Kubernetes權威指南》很多,侵權改。