ASP.NET Core on K8S学习初探(2)部署WebAPI到K8S

  1. 云栖社区>
  2. 博客>
  3. 正文

ASP.NET Core on K8S学习初探(2)部署WebAPI到K8S

Edison Zhou 2019-07-01 20:47:09 浏览305
展开阅读全文

在上一篇《单节点环境搭建》中,通过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的容器服务)去部署和实践公司的生产环境,相信到时也会有很多的分享的!

参考资料

网友评论

登录后评论
0/500
评论
Edison Zhou
+ 关注