天天看點

ASP.NET Core on K8S學習初探(2)部署WebAPI到K8S一、K8S叢集基本概念二、三大核心元件三、Service的幾種類型四、準備一個ASP.NET Core WebAPI五、部署ASP.NET Core WebAPI到K8S六、在K8S中對WebAPI的伸縮七、補充知識點八、小結參考資料

在上一篇《單節點環境搭建》中,通過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/fb5c0d115421

7.2 YAML檔案解析

   關于YAML檔案各個節點的解釋,可以通過下面這個指令去了解:

kubectl explain deployment.metadata           

  更多YAML檔案的節點參考:

https://www.kubernetes.org.cn/1414.html

7.3 更多K8S基礎知識?

  推薦閱讀《

18張插畫了解Kubernetes背景與概念

八、小結

  本文簡單的介紹了一下在Docker for Windows環境下,通過kubectl部署一個ASP.NET Core WebAPI到K8S中,并初步使用了K8S的伸縮特性對Deployment進行執行個體的伸縮,體驗了一下所謂的容器的編排。當然,筆者也是初玩,有很多還沒學習,這也隻是K8S的冰山一角,後續我會學習在Linux下部署K8S的生産級叢集環境,深入學習K8S的各種概念并實踐,最後會學習阿裡雲ACK服務(容器服務Kubernetes版)或騰訊雲TKE服務(基于Kubernetes的容器服務)去部署和實踐公司的生産環境,相信到時也會有很多的分享的!

參考資料

繼續閱讀