共计 7317 个字符,预计需要花费 19 分钟才能阅读完成。
在之前的文章中,咱们理解了 Kubernetes 中的基本概念,其硬件构造,不同的软件组件(例如 Pod、Deployment、StatefulSet、Services、Ingress 和 Persistent Volumes),并理解了如何在服务之间与内部进行通信。
在本文中,咱们将理解到:
- 应用 MongoDB 数据库创立 NodeJS 后端
- 编写 Dockerfile 来容器化咱们的应用程序
- 创立 Kubernetes Deployment 脚本以启动 Pod
- 创立 Kubernetes Service 脚本以定义容器与外界之间的通信接
- 部署 Ingress Controller 以申请路由
- 编写 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,物联网和人工智能等多个畛域都领有丰盛的教训。