帶你理解Kubernetes,部署一個Node應用

zxhaaa發表於2019-02-16

Kubernetes是什麼?

Kubernetes是容器叢集管理系統,是一個開源的平臺,可以實現容器叢集的自動化部署、自動擴縮容、維護等功能。可以在物理或虛擬機器的Kubernetes叢集上執行容器化應用,Kubernetes能提供一個以“容器為中心的基礎架構”。如果你曾經用過Docker容器技術部署容器,那麼可以將Docker看成Kubernetes內部使用的低階別元件。Kubernetes不僅僅支援Docker,還支援Rocket,這是另一種容器技術。

通過Kubernetes你可以:

  • 自動化容器的部署和複製
  • 快速擴充套件應用
  • 將容器組織成組,並且提供容器間的負載均衡
  • 無縫對接新的應用功能

想理解Kubernetes叢集,需要先搞明白其中的幾個重要概念。

Deployment

Deployment負責建立和更新應用,當建立Deployment後,Kubernetes master 會將Deployment建立好的應用例項排程到叢集中的各個節點。
應用例項建立完成後,Kubernetes Deployment Controller會持續監視這些例項。如果管理例項的節點被關閉或刪除,那麼 Deployment Controller將會替換它們,實現自我修復能力。

Pod

建立Deployment時,Kubernetes會建立了一個Pod來託管應用。Pod是Kubernetes中一個抽象化概念,由一個或多個容器組合在一起得共享資源。Pod是獨立執行的基本單位,包含一組容器和卷。同一個Pod裡的容器共享同一個網路名稱空間,可以使用localhost互相通訊。Pod是短暫的,不是持續性實體。
當在Kubernetes上建立Deployment時,該Deployment將會建立具有容器的Pods(而不會直接建立容器),每個Pod將被繫結排程到Node節點上,並一直保持在那裡直到被終止(根據配置策略)或刪除。在節點出現故障的情況下,群集中的其他可用節點上將會排程之前相同的Pod。

Node

一個Pod總是在一個(Node)節點上執行,Node是Kubernetes中的工作節點,可以是虛擬機器或物理機。每個Node由 Master管理,Node上可以有多個pod,Kubernetes Master會自動處理群集中Node的pod排程,同時Master的自動排程會考慮每個Node上的可用資源。

Replication Controller

Replication Controller確保任意時間都有指定數量的Pod“副本”在執行。如果為某個Pod建立了Replication Controller並且指定3個副本,它會建立3個Pod,並且持續監控它們。如果某個Pod不響應,那麼Replication Controller會替換它。如果在執行中將副本總數改為5,Replication Controller會立刻啟動2個新Pod,保證總數為5。

Service

事實上,Pod是有生命週期的。當一個工作節點(Node)銷燬時,節點上執行的Pod也會銷燬,然後通過ReplicationController動態建立新的Pods來保持應用的執行。
舉個例子,考慮一個圖片處理 backend,它執行了3個副本,這些副本是可互換的 —— 前端不需要關心它們呼叫了哪個 backend 副本。也就是說,Kubernetes叢集中的每個Pod都有一個獨立的IP地址,因此需要有一種方式來自動協調各個Pod之間的變化,以便應用能夠持續執行。
Kubernetes中的Service 是一個抽象的概念,它定義了Pod的邏輯分組和一種可以訪問它們的策略,讓你的這組Pods能被Service訪問。藉助Service,可以方便的實現服務發現與負載均衡。
Service可以被指定四種型別:

  • ClusterIP – 在叢集中內部IP上暴露服務。此型別使Service只能從群集中訪問。
  • NodePort – 通過每個 Node 上的 IP 和靜態埠(NodePort)暴露服務。NodePort 服務會路由到 ClusterIP 服務,這個 ClusterIP 服務會自動建立。通過請求 <NodeIP>:<NodePort>,可以從叢集的外部訪問一個 NodePort 服務。
  • LoadBalancer – 使用雲提供商的負載均衡器(如果支援),可以向外部暴露服務。外部的負載均衡器可以路由到 NodePort 服務和 ClusterIP 服務。(一般常用此型別向外暴露埠,並做負載均衡)
  • ExternalName – 通過返回 CNAME 和它的值,可以將服務對映到 externalName 欄位的內容,沒有任何型別代理被建立。

Label

你可以賦予標籤(鍵值對)來標識你的Pod、Deployment、Service。之後就可以通過選擇標籤來做具體的指令。

使用Minikube在kubernetes中部署第一個應用

本文以 MAC OS X 為例進行。目標是將簡單的Hello World Node.js應用部署在Kubernetes上執行。因此你可能需要Node.js環境。
Minikube 是一個使我們很容易在本地執行 kubernetes 的工具,由Kubernetes社群開發。

準備工作

  1. Node.js
  2. Docker
  3. VM – VirtualBox
  4. Minikube
  5. Kubectl

對於Node.js、Docker、VirtualBox的安裝,在這裡不做詳細介紹。可以直接到官網下載安裝最新穩定版本。

建立Minikube叢集

使用curl下載並安裝最新版本Minikube:

$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-amd64 && 
  chmod +x minikube && 
  sudo mv minikube /usr/local/bin/

使用Homebrew下載kubectl命令管理工具:

$ brew install kubectl

預設的VM驅動程式VirtualBox,因此可直接啟動Minikube:

$ minikube start

接下來會列印出類似資訊…

Starting local Kubernetes v1.9.4 cluster...
Starting VM...
Getting VM IP address...
Moving files into cluster...
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
Loading cached images from config file.

驗證kubectl是否安裝成功:

$ kubectl cluster-info

會列印出類似的資訊:

Kubernetes master is running at https://192.168.99.100:8443

建立Node.js應用

編寫應用程式。將這段程式碼儲存在一個名為hellonode的資料夾中,檔名server.js:

var http = require(`http`);

var handleRequest = function(request, response) {
  console.log(`Received request for URL: ` + request.url);
  response.writeHead(200);
  response.end(`Hello World!`);
};
var www = http.createServer(handleRequest);
www.listen(3000);

啟動應用:

$ node server.js

現在可以在 http://localhost:3000 中檢視到“Hello World!”訊息。
Ctrl-C停止正在執行的Node.js伺服器。

建立Docker容器映象

在hellonode資料夾中建立一個Dockerfile命名的檔案。

FROM node:8.10.0
EXPOSE 3000
COPY server.js .
CMD node server.js

我們使用Minikube,而不是將Docker映象push到registry,可以使用與Minikube VM相同的Docker主機構建映象,以使映象自動存在。為此,請確保使用Minikube Docker守護程式:

$ eval $(minikube docker-env)

注意:如果不在使用Minikube主機時,可以通過執行eval $(minikube docker-env -u)來撤消此更改。

使用Minikube Docker守護程式build Docker映象:

$ docker build -t hello-node:v1 .

建立Deployment

Kubernetes Deployment 是檢查Pod的健康狀況,如果它終止,則重新啟動一個Pod的容器,Deployment管理Pod的建立和擴充套件。

使用kubectl run命令建立Deployment來管理Pod。

$ kubectl run hello-node --image=hello-node:v1 --port=3000

檢視Deployment:

$ kubectl get deployments

輸出:

NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-node   1         1         1            1           5s

檢視Pod:

$ kubectl get pods

輸出:

NAME                          READY     STATUS    RESTARTS   AGE
hello-node-6ddb5576c9-644xn   1/1       Running   0          1m

檢視deployment的詳細資訊:

$ kubectl describe deployment

建立Service

Pod只能通過Kubernetes群集內部IP訪問。要使hello-node容器能從Kubernetes虛擬網路外部訪問,須要使用Kubernetes Service暴露Pod。

我們可以使用kubectl expose命令將Pod暴露到外部環境:

$ kubectl expose deployment hello-node --type=LoadBalancer

檢視Service:

$ kubectl get services

輸出:

NAME         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
hello-node   LoadBalancer   10.110.94.17   <pending>     8080:32081/TCP   2m
kubernetes   ClusterIP      10.96.0.1      <none>        443/TCP          6d

檢視詳細資訊:

$ kubectl describe service hello-node

輸出:

Name:                     hello-node
Namespace:                default
Labels:                   run=hello-node
Annotations:              <none>
Selector:                 run=hello-node
Type:                     LoadBalancer
IP:                       10.110.94.17
Port:                     <unset>  8080/TCP
TargetPort:               8080/TCP
NodePort:                 <unset>  32081/TCP
Endpoints:                172.17.0.5:8080
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

通過–type=LoadBalancer 來在群集外暴露Service,在支援負載均衡的雲提供商上,將配置外部IP(EXTERNAL-IP,在Minikube顯示為:<pending>)地址來訪問Service。在Minikube上,該LoadBalancer type使服務可以通過minikube Service 命令訪問。

$ minikube service hello-node

將開啟瀏覽器,在本地IP地址為應用提供服務,顯示“Hello World”的訊息。

可以檢視到日誌:

$ kubectl logs <pod-name>  //exp: kubectl logs hello-node-6ddb5576c9-644xn
// 可通過 kubectl get pods 檢視pod-name

擴充套件例項

根據線上需求,擴容和縮容是常會遇到的問題。Scaling 是通過更改 Deployment 中的副本數量實現的。一旦有多個例項,就可以滾動更新,而不會停止服務。通過kubectl scale指令來擴容和縮容。

$ kubectl scale deployments/hello-node --replicas=4

在檢視pods:

$ kubectl get pods

輸出:

NAME                         READY     STATUS    RESTARTS   AGE
hello-node-9f5f775d6-6qdmn   1/1       Running   0          3s
hello-node-9f5f775d6-9mrm6   1/1       Running   0          3s
hello-node-9f5f775d6-jxb8z   1/1       Running   0          3s
hello-node-9f5f775d6-tx8kg   1/1       Running   0          11m

總共有4個例項,那麼就可通過Service 的 --type=LoadBalancer 進行負載均衡。

更新應用程式

編輯server.js檔案以返回新訊息:

response.end(`Hello World Again!`);

docker build新版本映象:

$ docker build -t hello-node:v2 .

Deployment更新映象:

$ kubectl set image deployment/hello-node hello-node=hello-node:v2

再次在瀏覽器檢視訊息:

$ minikube service hello-node

清理刪除

刪除在群集中建立的資源:

$ kubectl delete service hello-node
$ kubectl delete deployment hello-node

檢視pods:

$ kubectl get pods

輸出:

NAME                         READY     STATUS        RESTARTS   AGE
hello-node-9f5f775d6-6qdmn   1/1       Terminating   0          6m
hello-node-9f5f775d6-9mrm6   1/1       Terminating   0          6m
hello-node-9f5f775d6-jxb8z   1/1       Terminating   0          6m
hello-node-9f5f775d6-tx8kg   1/1       Terminating   0          18m

全部在停止中… 稍等一分鐘,再檢視,輸出 No resources found.

停止

$ minikube stop

輸出:

Stopping local Kubernetes cluster...
Machine stopped.

完畢

相關文章