3

入门指南丨上手理解Deployment、Services和Ingress

 3 years ago
source link: http://dockone.io/article/2434347
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

入门指南丨上手理解Deployment、Services和Ingress


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

在本文中,我们将了解到:
  1. 使用MongoDB数据库创建NodeJS后端
  2. 编写Dockerfile来容器化我们的应用程序
  3. 创建Kubernetes Deployment脚本以启动Pod
  4. 创建Kubernetes Service脚本以定义容器与外界之间的通信接
  5. 部署Ingress Controller以请求路由
  6. 编写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/tas ... ndows

在本教程中使用的Kubectl命令可以在Kubectl cheat sheet(https://kubernetes.io/docs/ref ... heet/)中找到。

在本教程中,我们将使用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/0 ... t-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/CzakoZoltan ... t.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,物联网和人工智能等多个领域都拥有丰富的经验。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK