在之前的文章中,咱们理解了Kubernetes中的基本概念,其硬件构造,不同的软件组件(例如Pod、Deployment、StatefulSet、Services、Ingress和Persistent Volumes),并理解了如何在服务之间与内部进行通信。

在本文中,咱们将理解到:

  1. 应用MongoDB数据库创立NodeJS后端
  2. 编写Dockerfile来容器化咱们的应用程序
  1. 创立Kubernetes Deployment脚本以启动Pod
  1. 创立Kubernetes Service脚本以定义容器与外界之间的通信接
  1. 部署Ingress Controller以申请路由
  1. 编写Kubernetes Ingress脚本来定义与外界的通信。

因为咱们的代码能够从一个节点重定向到另一个节点(例如,一个节点没有足够的内存,所以工作将从新调度到另一个具备足够内存的节点上),因而保留在节点上的数据容易失落 ,意味着MongoDB 数据不稳固。在下一篇文章中,咱们将探讨数据持久性问题以及如何应用Kubernetes长久卷平安地存储咱们的持久数据。

在本文中,咱们将应用NGINX作为Ingress Controller和Azure容器镜像仓库来存储咱们的自定义Docker镜像。文中编写所有脚本都能够在Stupid Simple Kubernetes git repo中找到,如有须要可拜访链接获取:

http://GitHub - CzakoZoltan08/StupidSimpleKubernetes-AKS

请留神:这些脚本不限定于某个平台,因而您能够应用其余类型的云提供程序或带有K3s的本地集群来实际本教程。我之所以倡议应用K3s,因为它十分轻量,所有依赖项都被打包在一个小于100MB的单个二进制文件中。更重要的是,它是一种高可用的、通过CNCF认证的Kubernetes发行版,专门用于资源受限的环境中的生产工作负载。无关更多信息,您能够拜访官网文档:

https://docs.rancher.cn/k3s/

后期筹备

在开始本教程之前,请确保您已装置Docker。同时也要装置kubectl。

Kubectl装置链接:

https://kubernetes.io/docs/tasks/tools/#install-kubectl-on-windows

在本教程中应用的Kubectl命令能够在Kubectl cheat sheet(https://kubernetes.io/docs/reference/kubectl/cheatsheet/)中找到。

在本教程中,咱们将应用Visual Studio Code,但这不是必要的,你也能够应用其余的编辑器。

创立可用于生产的微服务架构

将应用程序容器化

第一步,创立NodeJS后端的Docker镜像。创立镜像后,咱们会将其推送到容器镜像仓库中,在该镜像仓库中能够拜访它,并且能够通过Kubernetes服务(在本例中为Azure Kubernetes Service)拉取。

The Docker file for NodeJS:  FROM node:13.10.1  WORKDIR /usr/src/app  COPY package*.json ./  RUN npm install  # Bundle app source  COPY . .  EXPOSE 3000  CMD [ "node", "index.js" ]

在第一行中,咱们须要依据要创立后端服务的镜像进行定义。在这种状况下,咱们将应用Docker Hub中13.10.1版的官网节点镜像。

在第3行中,咱们创立一个目录来将利用程序代码保留在镜像中。这将是您的应用程序的工作目录。

该镜像曾经装置了Node.js和NPM,因而下一步咱们须要应用npm命令装置您的应用程序依赖项。

请留神,要装置必须的依赖项,咱们不必复制整个目录,而只需复制package.json,这使咱们能够利用缓存的Docker层。

无关高效Dockerfile的更多信息,请拜访以下链接:

http://bitjudo.com/blog/2014/03/13/building-efficient-dockerfiles-node-dot-js/

在第9行中,咱们将源代码复制到工作目录中,在第11行中,将其裸露在端口3000上(如果须要,您能够抉择另一个端口,但请确保同步更改Kubernetes Service脚本。)

最初,在第13行,咱们定义了运行应用程序的命令(在Docker容器外部)。请留神,每个Dockerfile中应该只有一个CMD指令。如果蕴含多个,则只有最初一个才会失效。

当初,咱们曾经定义了Dockerfile,咱们将应用以下Docker命令从该Dockerfile中构建镜像(应用Visual Studio Code的Terminal或在Windows上应用CMD):

docker build -t node-user-service:dev .

请留神Docker命令开端的小圆点,这意味着咱们正在从当前目录构建镜像,因而请确保您位于Dockerfile所在的同一文件夹中(在本例中,是repo的根文件夹)。

要在本地运行镜像,咱们能够应用以下命令:

docker run -p 3000:3000 node-user-service:dev  

若要将此镜像推送到咱们的Azure容器镜像仓库,咱们必须应用以下格局标记它<container-registry-login-service>/<image-name>:<tag>:,在本例中如下所示:

docker tag node-user-service:dev stupidsimplekubernetescontainerregistry.azurecr.io/node-user-service:dev

最初一步是应用以下Docker命令将其推送到咱们的容器镜像仓库中:

docker push stupidsimplekubernetescontainerregistry.azurecr.io/node-user-service:dev

应用部署脚本创立Pod

NodeJs后端

接下来,定义Kubernetes Deployment脚本,该脚本将主动为咱们治理Pod。

apiVersion: apps/v1  kind: Deployment  metadata:    name: node-user-service-deployment  spec:    selector:      matchLabels:        app: node-user-service-pod    replicas: 3    template:      metadata:        labels:          app: node-user-service-pod      spec:        containers:          - name: node-user-service-container            image: stupidsimplekubernetescontainerregistry.azurecr.io/node-user-service:dev            resources:              limits:                memory: "256Mi"                cpu: "500m"            imagePullPolicy: Always            ports:              - containerPort: 3000

Kubernetes API能够查问和操作Kubernetes集群中对象的状态(例如Pod、命名空间、ConfigMap等)。如第一行中所指定,这个API的以后稳固版本为1。

在每个Kubernetes .yml脚本中,咱们必须应用kind关键字定义Kubernetes资源类型(Pods、Deployments、Service等)。因而,你能够看到,咱们在第2行中定义了咱们想应用Deployment资源。

Kubernetes容许您向资源中增加一些元数据。这样一来,您就能够更轻松地辨认、过滤和参考资源。

在第5行中,咱们定义了该资源的标准。在第8行中,咱们指定此Deployment应仅利用于标签为app:node-user-service-pod的资源中,在第9行中能够看出咱们想要创立同一Pod的3个正本。

Template(从第10行开始)定义了Pod。在这里,咱们将标签app:node-user-service-pod增加到每个Pod。这样,Deployment将辨认它们。在第16和17行中,咱们定义了应在pod外部运行哪种Docker容器。如您在第17行中看到的那样,咱们将应用Azure容器镜像仓库中的Docker镜像,该镜像是在上一节中构建并推送的。

咱们还能够为Pod定义资源限度,防止Pod资源有余(当其中一个Pod应用所有资源而其余Pod无奈应用它们时)。此外,当您为Pod中的容器指定资源申请时,调度程序将应用此信息来决定将Pod搁置在哪个节点上。当您为容器指定资源限度时,kubelet会强制执行这些限度,从而不容许运行中的容器应用超出您设置的资源限度。kubelet还至多保留该系统资源的“申请”量。请留神,如果您没有足够的硬件资源(例如CPU或内存),则永远无奈调度pod。

最初一步是定义用于通信的端口。在本例中,咱们应用端口3000。此端口号应与Dockerfile中裸露的端口号雷同。

MongoDB

MongoDB数据库的Deployment脚本十分类似。惟一的区别是咱们必须指定卷挂载(数据会被保留到节点上的文件夹中)。

apiVersion: apps/v1  kind: Deployment  metadata:    name: user-db-deployment  spec:    selector:      matchLabels:        app: user-db-app    replicas: 1    template:      metadata:        labels:          app: user-db-app      spec:        containers:          - name: mongo            image: mongo:3.6.4            command:              - mongod              - "--bind_ip_all"              - "--directoryperdb"            ports:              - containerPort: 27017            volumeMounts:              - name: data                mountPath: /data/db            resources:              limits:                memory: "256Mi"                cpu: "500m"        volumes:          - name: data            persistentVolumeClaim:              claimName: static-persistence-volume-claim-mongo

在本例中,咱们间接从DockerHub应用了官网MongoDB镜像(第17行)。在第24行中定义了卷装置。在探讨Kubernetes长久卷时,咱们将在下一篇文章中解释最初四行。

创立用于网络拜访的服务

当初咱们曾经启动了Pod,并开始定义容器之间以及与内部世界的通信。为此,咱们须要定义一个服务。Service与Deployment之间的关系是一对一的,因而对于每个Deployment,咱们都应该有一个Service。Deployment还能够治理Pod的生命周期,并且负责监控它们,而Service负责启用对一组Pod的网络拜访。

apiVersion: v1  kind: Service  metadata:    name: node-user-service  spec:    type: ClusterIP    selector:      app: node-user-service-pod    ports:      - port: 3000        targetPort: 3000

这个.yml脚本的重要局部是selector,它定义了如何辨认要从此Service援用的Pod(由Deployment创立)。在第8行中咱们能够看到的,Selector 为app:node-user-service-pod,因为先前定义的Deployment中的Pod被标记为这样。另一个重要的事件是定义容器端口和服务端口之间的映射。在这种状况下,传入申请将应用第10行中定义的3000端口,并将它们路由到第11行中定义的端口。

MongoDB pod的Kubernetes Service脚本十分类似。咱们只须要更新Selector和端口。

apiVersion: v1  kind: Service  metadata:    name: user-db-service  spec:    clusterIP: None    selector:      app: user-db-app    ports:      - port: 27017        targetPort: 27017

配置内部流量

为了与外界通信,咱们须要定义一个Ingress Controller并应用Ingress Kubernetes资源指定路由规定。

要配置NGINX ingress controller,咱们将应用能够以下链接中的脚本:

https://github.com/CzakoZoltan08/StupidSimpleKubernetes-AKS/blob/master/manifest/ingress-controller/nginx-ingress-controller-deployment.yml

这是一个通用脚本,无需批改即可利用(具体解释NGINX Ingress Controller不在本文探讨范畴之内)。

下一步是定义“负载均衡器”,该负载均衡器将用于应用公共IP地址路由内部流量(云提供商提供负载均衡器)。

kind: Service  apiVersion: v1  metadata:    name: ingress-nginx    namespace: ingress-nginx    labels:      app.kubernetes.io/name: ingress-nginx      app.kubernetes.io/part-of: ingress-nginx  spec:    externalTrafficPolicy: Local    type: LoadBalancer    selector:      app.kubernetes.io/name: ingress-nginx      app.kubernetes.io/part-of: ingress-nginx    ports:      - name: http        port: 80        targetPort: http      - name: https        port: 443        targetPort: https

当初咱们曾经启动并运行了Ingress controller和负载均衡器,于是咱们能够定义Ingress Kubernetes资源来指定路由规定。

apiVersion: extensions/v1beta1  kind: Ingress  metadata:    name: node-user-service-ingress    annotations:      kubernetes.io/ingress.class: "nginx"      nginx.ingress.kubernetes.io/rewrite-target: /$2  spec:    rules:      - host: stupid-simple-kubernetes.eastus2.cloudapp.azure.com        http:          paths:            - backend:                serviceName: node-user-service                servicePort: 3000              path: /user-api(/|$)(.*)            # - backend:            #     serviceName: nestjs-i-consultant-service            #     servicePort: 3001            #   path: /i-consultant-api(/|$)(.*)

在第6行中,咱们定义了Ingress Controller类型(这是Kubernetes的预约义值;Kubernetes以后反对和保护GCE和nginx controller)。

在第7行中,咱们定义了重写指标规定,在第10行中,咱们定义了主机名。

对于应该从内部拜访的每个服务,咱们应该在门路列表中增加一个条目(从第13行开始)。在此示例中,咱们仅为NodeJS用户服务后端增加了一个条目,可通过端口3000对其进行拜访。/ user-api惟一标识咱们的服务,因而任何以stupid-simple-kubernetes.eastus2.cloudapp azure.com/user-api结尾的申请将被路由到此NodeJS后端。如果要增加其余服务,则必须更新此脚本(请参见正文掉的代码)。

利用.yml脚本

要利用这些脚本,咱们将应用kubectl。利用文件的kubectl命令如下:

kubectl apply -f

在本例中,如果你在Stupid Simple Kubernetes repo的根文件夹中,您须要执行以下命令:

kubectl apply -f .\manifest\kubernetes\deployment.yml  kubectl apply -f .\manifest\kubernetes\service.yml  kubectl apply -f .\manifest\kubernetes\ingress.yml  kubectl apply -f .\manifest\ingress-controller\nginx-ingress-controller-deployment.yml  kubectl apply -f .\manifest\ingress-controller\ngnix-load-balancer-setup.yml  

利用这些脚本后,所有准备就绪,进而咱们能够从内部调用后端(如应用Postman)。

总结

在本教程中,咱们学习了如何在Kubernetes中创立各种资源,例如Pod、Deployment、Services、Ingress和Ingress Controller。咱们应用MongoDB数据库创立了一个NodeJS后端,并应用3个pod的正本容器化并部署了NodeJS和MongoDB容器。

在下一篇文章中,咱们将理解长久保留数据的问题,并将介绍Kubernetes中的长久卷。

作者简介

Czako Zoltan,一位经验丰富的全栈开发人员,在前端,后端,DevOps,物联网和人工智能等多个畛域都领有丰盛的教训。