在上一篇《單節點環境搭建》中,通過Docker for Windows在Windows開發機中搭建了一個單節點的K8S環境,接下來就是動人心弦的部署ASP.NET Core API到K8S了。但是,在部署之前,我還是把基本的一些概念快速地簡單地不求甚解地過一下,過完這些基本概念就可以體驗一下部署一個ASP.NET Core WebAPI到K8S了。
一、K8S叢集基本概念
(1)叢集
首先,K8S叢集也是需要多台伺服器組成,作為容器的編排管理平台,隻有一個節點在生産環境是不夠的。
(2)Node
其次,Node作為K8S叢集中的工作節點,一個Node可以是VM或實體機,它運作真正的應用程式。
K8S中的Node又分為Master和Worker,和Hadoop叢集中的NameNode和DataNode類似,簡而言之就是一個是負責排程(維護叢集狀态)的,一個是負責幹活(運作容器)的。
(3)資源
在K8S每個元件(比如Pod,Service等)開放對外暴露的都是一組RESTful API,是以我們所有對于元件的操作都可以通過RESTful API來完成,是以我們可以将其看作是資源。
(4)Kubectl
Kubectl是一個用戶端指令行工具,使用它可以連接配接K8S叢集和進行互動。
如下圖所示,我們通過kubectl輸入指令與遠端的K8S叢集連接配接,而這些指令本質是通過調用API通路Master節點提供的API,通過這些API去操作所謂的叢集中的“資源”,對這些資源進行建立(POST),修改(PUT),删除(DELETE)等操作。
二、三大核心元件
(1)Pod
Pod是K8S最基本的操作單元,包含一個或多個緊密相關的容器,一個Pod可以被一個容器化的環境看作是應用層的“邏輯主控端”;
換句話說,在K8S中建立,排程和管理的最小機關就是Pod,而非容器(Container),多個容器之間的挂載是可以共享的,Pod通過提供更高層次的抽象,提供了更加靈活的部署和管理模式;
(2)Service
Service是一個抽象概念,它定義了邏輯集合下通路Pod組的政策。通過使用Service,我們就可以不用關心這個服務下面的Pod的增加和減少、故障重新開機等,隻需通過Service就能夠通路到對應服務的容器,即通過Service來暴露Pod的資源。
這樣說可能還是有點難懂,舉個例子,假設我們的一個服務Service A下面有3個Pod,我們都知道Pod的IP都不是持久化的,重新開機之後就會有變化。那麼Service B想要通路Service A的Pod,它隻需跟綁定了這3個Pod的Service A打交道就可以了,無須關心下面的3個Pod的IP和端口等資訊的變化。換句話說,就像一個Service Discovery服務發現的元件,你無須關心具體服務的URL,隻需知道它們在服務發現中注冊的Key就可以通過類似Consul、Eureka之類的服務發現元件中擷取它們的URL一樣,還是實作了負載均衡效果的URL。
(3)Deployment
Deployment主要負責Pod的編排,例如我們可以使用下面的yaml檔案來建立一個Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.12.2
ports:
- containerPort: 80
熟悉Docker-Compose的朋友應該對這個yaml不陌生,可以看到Deployment定義了Pod内容,包括Pod數量、更新方式、使用的鏡像,資源限制,容器中的映射端口等等。
三、Service的幾種類型
(1)ClusterIP
ClusterIP 服務是 Kubernetes 的預設服務。它給你一個叢集内的服務,叢集内的其它應用都可以通路該服務,但是叢集外部無法通路它。
是以,這種服務常被用于内部程式互相的通路,且不需要外部通路,那麼這個時候用ClusterIP就比較合适,如下面的yaml檔案所示:
apiVersion: v1
kind: Service
metadata:
name: my-internal-service
selector:
app: my-app
spec:
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
那麼,如果需要從外部通路呢(比如我們在開發模式下總得調試吧)?可以啟用K8S的代理模式:
$ kubectl proxy --port=8080
如此一來,便可以通過K8S的API來通路了,例如下面這個URL就可以通路在yaml中定義的這個my-internal-service了:
http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/
(2)NodePort
除了隻在内部通路的服務,我們總有很多是需要暴露出來公開通路的服務吧。在ClusterIP基礎上為Service在每台機器上綁定一個端口,這樣就可以通過:NodePort來通路這些服務。例如,下面這個yaml中定義了服務為NodePort類型:
apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
selector:
app: my-app
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30036
protocol: TCP
PS:這種方式顧名思義需要一個額外的端口來進行暴露,且端口範圍隻能是 30000-32767,如果節點/VM 的 IP 位址發生變化,你需要能處理這種情況。
(3)LoadBalancer
LoadBalancer 服務是暴露服務到 internet 的标準方式,它借助Cloud Provider建立一個外部的負載均衡器,并将請求轉發到:NodePort(向節點導流)。
例如下面這個yaml中:
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
loadBalancerIP: 78.11.24.19
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 146.148.47.155
PS:每一個用 LoadBalancer 暴露的服務都會有它自己的 IP 位址,每個用到的 LoadBalancer 都需要付費,這将是比較昂貴的花費。
四、準備一個ASP.NET Core WebAPI
這裡準備一個空的ASP.NET Core WebAPI項目,使用預設自帶的ValuesController控制器,具體代碼見[這裡](https://github.com/EdisonChou/AspNetCore.On.K8S/tree/master/src/01_hello-k8s/EDC.K8S.Demo.WebApi)。
Dockerfile如下:
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
FROM microsoft/dotnet:2.1-sdk AS build
WORKDIR /src
COPY . .
RUN dotnet restore
RUN dotnet build -c Release -o /app
FROM build AS publish
RUN dotnet publish -c Release -o /app
FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "EDC.K8S.Demo.WebApi.dll"]
我們可以事先在自己的Docker環境建構這樣的一個鏡像,看看能否正常使用。
由于後面會使用到這個鏡像,是以可以将此鏡像push到
Docker Hub上。
docker push your-image-name:tagname
當然你也可以直接使用我上傳的這個鏡像(edisonsaonian/k8s-demo)。
五、部署ASP.NET Core WebAPI到K8S
5.1 準備Deployment YAML
在上一篇中我們知道Deployment主要負責Pod的編排,那麼我們這裡就通過一個YAML來建立一個Deployment。
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8s-demo
namespace: aspnetcore
labels:
name: k8s-demo
spec:
replicas: 2
selector:
matchLabels:
name: k8s-demo
template:
metadata:
labels:
name: k8s-demo
spec:
containers:
- name: k8s-demo
image: edisonsaonian/k8s-demo
ports:
- containerPort: 80
imagePullPolicy: Always
---
kind: Service
apiVersion: v1
metadata:
name: k8s-demo
namespace: aspnetcore
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
selector:
name: k8s-demo
這裡這個deploy.yaml就會告訴K8S關于你的API的所有資訊,以及通過什麼樣的方式暴露出來讓外部通路。
需要注意的是,這裡我們提前為要部署的ASP.NET Core WebAPI項目建立了一個namespace,叫做aspnetcore,是以這裡寫的namespace : aspnetcore。
K8S中通過标簽來區分不同的服務,是以這裡統一name寫成了k8s-demo。
在多執行個體的配置上,通過replicas : 2這個設定告訴K8S給我啟動2個執行個體起來,當然你可以寫更大的一個數量值。
最後,在spec中告訴K8S我要通過NodePort的方式暴露出來公開通路,是以端口範圍從上一篇可以知道,應該是 30000-32767這個範圍之内。
5.2 通過kubectl部署到K8S
首先,確定你的Docker for Windows以及Kubernetes都啟動起來了。
然後,在Powershell中通過kubectl完成API的部署,隻需要下面這一句指令行即可:
kubectl create -f deploy.yaml
看到上面的提示"service created",就可以知道已經建立好了,這裡我們再通過下面這個指令來驗證一下:
kubectl get svc -n aspnetcore
可以看到,在命名空間aspnetcore下,就有了一個k8s-demo的服務運作起來了,并通過端口号31435向外部提供通路。
5.3 在K8S中驗證WebAPI
首先,我們可以通過浏覽器來通路一下這個API接口,看看是否能正常通路到。
- /api/values
- /api/values/1000
其次,還記得在第一篇中部署的Dashboard嗎?我們通過Dashboard來看看我們的k8s-demo的狀态:
從Dashboard中可以看到更為詳細的資訊,包括運作的Deployment、容器組(由于我們設定的replicas=2,是以會有2個容器運作起來)、副本集等等,也可以通過Dashboard實時初步地監控我們的API的運作情況。
六、在K8S中對WebAPI的伸縮
6.1 通過Dashboard伸縮WebAPI
在Dashboard中,我們可以可視化地對我們的Deployment進行容器執行個體的伸縮,如下圖所示:
在彈出的伸縮選項對話框中輸入個數,例如我們這裡從2個縮減為1個,然後确定。
再次觀看Dashboard,可以看到已經從原來的2個容器執行個體變為1個了。
3.2 通過Kubectl伸縮WebAPI
除了在Dashboard中可視化地操作進行伸縮,也可以通過kubectl來進行,例如下面這句指令,将容器執行個體擴充到3個。需要注意的是,由于我們的k8s-demo所在的命名空間是在aspnetcore下,是以也需要指明--namespace=aspnetcore。
kubectl scale deployment k8s-demo --replicas=3 --namespace=aspnetcore
再到Dashboard中來驗證一下,是否擴充到了3個容器執行個體:
6.2 自動伸縮WebAPI執行個體
在K8S中,提供了一個autoscale接口來實作服務的自動伸縮,它會采用預設的自動伸縮政策(例如根據CPU的負載情況)來幫助我們實作彈性伸縮的功能。例如下面這句指令可以實作我們的k8s-demo可以伸縮的範圍是1~3個,根據負載情況自己伸縮,在沒有多少請求量壓力很小時收縮為一個,在壓力較大時啟動另一個執行個體來降低負載。
kubectl autoscale deployment k8s-demo --min=1 --max=3 --namespace=aspnetcore
七、補充知識點
7.1 常用Kubectl指令
kubectl get svc -n kube-system //擷取指定命名空間的服務
kubectl cluster-info // 擷取叢集資訊
kubectl get nodes // 擷取叢集節點資訊
kubectl delete node 192.168.2.152 //删除節點 192.168.2.152
kubectl get namespaces // 擷取所有命名空間
kubectl create namespace aspnetcore // 建立一個命名空間“aspnetcore”
更多kubectl指令參考:
(1)
https://jimmysong.io/kubernetes-handbook/guide/kubectl-cheatsheet.html(2)
https://www.jianshu.com/p/fb5c0d1154217.2 YAML檔案解析
關于YAML檔案各個節點的解釋,可以通過下面這個指令去了解:
kubectl explain deployment.metadata
更多YAML檔案的節點參考:
https://www.kubernetes.org.cn/1414.html7.3 更多K8S基礎知識?
推薦閱讀《
18張插畫了解Kubernetes背景與概念》
八、小結
本文簡單的介紹了一下在Docker for Windows環境下,通過kubectl部署一個ASP.NET Core WebAPI到K8S中,并初步使用了K8S的伸縮特性對Deployment進行執行個體的伸縮,體驗了一下所謂的容器的編排。當然,筆者也是初玩,有很多還沒學習,這也隻是K8S的冰山一角,後續我會學習在Linux下部署K8S的生産級叢集環境,深入學習K8S的各種概念并實踐,最後會學習阿裡雲ACK服務(容器服務Kubernetes版)或騰訊雲TKE服務(基于Kubernetes的容器服務)去部署和實踐公司的生産環境,相信到時也會有很多的分享的!
參考資料
- Jesse, http://video.jessetalk.cn/my/course/6
- 阿裡雲, https://github.com/AliyunContainerService/k8s-for-docker-desktop/tree/18.09
- https://yq.aliyun.com/articles/508460?spm=a2c4e.11153940.blogcont221687.18.7dd57733hFolMo
- 小黑老, https://www.jianshu.com/p/1555c9b7fccd
- 騰訊雲, http://www.sohu.com/a/227967825 _212034
- 池劍鋒(譯者), http://dockone.io/article/4884