网络研讨会系列:在 Kubernetes 中部署和扩展微服务

<$>[note] 本文补充了关于部署和管理云中的集装箱工作负载的Webinar系列(https://go.digitalocean.com/containers-and-microservices-webinars-series)。该系列涵盖了集装箱的基本内容,包括管理集装箱生命周期,部署多集装箱应用程序,扩展工作负载,以及与Kubernetes合作。

本教程包括系列第五个会话中的概念和命令,在Kubernetes中部署和扩展微服务

[youtube LS57ul_cTsA 480 854 ]

介绍

Kubernetes是一个开源集装箱编排工具,用于管理集装箱应用程序. 在本系列的上一本教程中,您了解了Kubernetes的构建要素。

在本教程中,您将应用以前的教程的概念来构建,部署和管理Kubernetes中的端到端微服务应用程序。本教程中您将使用的样本Web应用程序是用Node.js编写的全部列表应用程序,该应用程序使用MongoDB作为数据库。

您将从 Dockerfile 构建此应用程序的容器图像,将图像推到 Docker Hub,然后将其部署到您的集群中。

前提条件

要完成本教程,您将需要:

步骤 1 – 使用 Dockerfile 构建图像

我们将开始通过将Web应用程序包装成Docker图像。

首先,转到您的主目录,然后使用Git从GitHub上的官方存储库克隆本教程的样本Web应用程序。

1cd ~
2git clone https://github.com/janakiramm/todo-app.git

从 Dockerfile 构建容器图像. 使用 -t 交换机以注册表用户名、图像名和可选标签来标记图像。

1docker build -t sammy/todo .

输出证实图像已成功构建并适当标记。

 1[secondary_label Output]
 2Sending build context to Docker daemon  8.238MB
 3Step 1/7 : FROM node:slim
 4 ---> 286b1e0e7d3f
 5Step 2/7 : LABEL maintainer = "[email protected]"
 6 ---> Using cache
 7 ---> ab0e049cf6f8
 8Step 3/7 : RUN mkdir -p /usr/src/app
 9 ---> Using cache
10 ---> 897176832f4d
11Step 4/7 : WORKDIR /usr/src/app
12 ---> Using cache
13 ---> 3670f0147bed
14Step 5/7 : COPY ./app/ ./
15 ---> Using cache
16 ---> e28c7c1be1a0
17Step 6/7 : RUN npm install
18 ---> Using cache
19 ---> 7ce5b1d0aa65
20Step 7/7 : CMD node app.js
21 ---> Using cache
22 ---> 2cef2238de24
23Successfully built 2cef2238de24
24Successfully tagged sammy/todo-app:latest

通过运行 docker 图像命令来验证图像是否被创建。

1docker images

您可以看到图像的大小以及自创建以来的时间。

1[secondary_label Output]
2REPOSITORY                                       TAG                 IMAGE ID            CREATED             SIZE
3sammy/todo-app                                   latest              81f5f605d1ca        9 minutes ago       236MB

接下来,将您的图像推到 Docker Hub 上的公共注册表. 要做到这一点,请登录到您的 Docker Hub 帐户:

1docker login

一旦您提供身份证,请使用您的 Docker Hub 用户名标记您的图像:

1docker tag your_docker_hub_username/todo-app

然后将图像推到 Docker Hub:

1docker push

您可以通过在您的 Web 浏览器中搜索 Docker Hub来验证新图像是否可用。

随着Docker图像被推到注册表,让我们为Kubernetes包装应用程序。

步骤 2 – 在 Kubernetes 中部署 MongoDB Pod

该应用程序使用MongoDB存储通过Web应用程序创建的任务列表. 要在Kubernetes中运行MongoDB,我们需要将其包装为Pod。

创建一个名为 db-pod.yaml 的新的 YAML 文件:

1nano db-pod.yaml

添加以下代码,该代码定义了一个基于 MongoDB 的 Pod 容器。我们暴露了 27017 端口,这是 MongoDB 使用的标准端口. 请注意,该定义包含标签 名称应用程序

 1[label db-pod.yaml]
 2apiVersion: v1
 3kind: Pod
 4metadata:
 5  name: db
 6  labels:
 7    name: mongo
 8    app: todoapp
 9
10spec:
11      containers:
12      - image: mongo
13        name: mongo
14        ports:
15        - name: mongo
16          containerPort: 27017
17
18        volumeMounts:
19          - name: mongo-storage
20            mountPath: /data/db
21
22      volumes:
23          - name: mongo-storage
24            hostPath:
25              path: /data/db

数据存储在名为mongo-storage的卷中,该卷被绘制到节点的/data/db位置. 有关Volumes的更多信息,请参阅官方的 Kubernetes volumes documentation

运行以下命令来创建一个Pod。

1kubectl create -f db-pod.yml

你会看到这个输出:

1[secondary_label Output]
2pod "db" created

现在检查Pod的创建。

1kubectl get pods

输出显示了Pod并表示它正在运行:

1[secondary_label Output]
2NAME      READY     STATUS    RESTARTS   AGE
3db   1/1       Running   0          2m

让我们让这个Pod对集群的内部消费者可用。

创建一个名为「db-service.yaml」的新文件,其中包含定义 MongoDB 服务的此代码:

 1[label db-service.yaml]
 2apiVersion: v1
 3kind: Service
 4metadata:
 5  name: db
 6  labels:
 7    name: mongo
 8    app: todoapp
 9
10spec:
11  selector:
12    name: mongo
13
14  type: ClusterIP
15  ports:
16    - name: db
17      port: 27017
18      targetPort: 27017

该服务发现了相同的名称空间中的所有 Pods,这些 Pods 与名称:db的标签相匹配。

我们指出,服务可通过声明类型:ClusterIP在集群内可见。

保存文件并离开编辑器,然后使用kubectl将其提交到集群中。

1kubectl create -f db-service.yml

您将看到此输出,表示服务已成功创建:

1[secondary_label Output]
2service "db" created

让我们获得Pod可用的端口。

1kubectl get services

你会看到这个输出:

1[secondary_label Output]
2NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)     AGE
3db           ClusterIP   10.109.114.243   <none>        27017/TCP   14s
4kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP     47m

从这个输出中,你可以看到服务在端口 27017上可用。网页应用程序可以通过该服务访问MongoDB。当它使用主机名 db时,在Kubernetes内运行的DNS服务将解决与服务相关的ClusterIP地址。

有了数据库 Pod 和服务,让我们为 Web 应用程序创建一个 Pod。

步骤 3 – 部署 Node.JS Web App 作为一个 Pod

让我们将您在本教程的第一步创建的Docker图像包装为Pod,并部署到集群中。

创建一个新的 YAML 文件,名为 web-pod.yaml:

1nano web-pod.yaml

添加以下代码,该代码定义了基于sammy/todo-app Docker 图像的一个容器的 Pod。

 1[label web-pod.yaml]
 2apiVersion: v1
 3kind: Pod
 4
 5metadata:
 6  name: web
 7  labels:
 8    name: web
 9    app: todoapp
10
11spec:
12  containers:
13    - image: sammy/todo-app
14      name: myweb
15      ports:
16        - containerPort: 3000

请注意,该定义包含标签名称应用程序

运行以下命令来创建 Pod:

1kubectl create -f web-pod.yaml
1[secondary_label Output]
2pod "web" created

让我们来验证Pod的创建:

1kubectl get pods
1[secondary_label Output]
2NAME      READY     STATUS    RESTARTS   AGE
3db        1/1       Running   0          8m
4web       1/1       Running   0          9s

请注意,我们有 MongoDB 数据库和 Web 应用程序作为 Pods 运行。

现在,我们将使WebPod可供公共互联网使用。

服务内部或外部暴露了一组Pod。让我们定义一个服务,使WebPod公开可用。我们将通过NodePort暴露它,这是一种系统,使Pod通过在集群的每个节点上打开的任意端口可访问。

创建一个名为web-service.yaml的新文件,其中包含该应用程序的服务定义代码:

 1apiVersion: v1
 2kind: Service
 3metadata:
 4  name: web
 5  labels:
 6    name: web
 7    app: todoapp
 8
 9spec:
10  selector:
11    name: web
12  type: NodePort
13  ports:
14   - name: http
15     port: 3000
16     targetPort: 3000
17     protocol: TCP

该服务在同一个名称空间中发现所有匹配标签名为web的 Pods. YAML 文件的选择器部分明确定义了这一关联。

我们通过类型:NodePort声明来指定服务类型为NodePort

使用kubectl将此提交到集群中。

1kubectl create -f web-service.yml

您将看到此输出,表示服务已成功创建:

1[secondary_label Output]
2service "web" created

让我们获得Pod可用的端口。

1kubectl get services
1[secondary_label Output]
2NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
3db           ClusterIP   10.109.114.243   <none>        27017/TCP        12m
4kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          59m
5web          NodePort    10.107.206.92    <none>        3000:30770/TCP   12s

从这个输出中,我们可以看到服务在端口30770上可用,让我们尝试连接到一个工人节点。

通过使用 DigitalOcean 控制台获取与您的 Kubernetes 集群关联的 Worker 节点之一的公共 IP 地址。

DigitalOcean console showing worker nodes

一旦您获得了IP地址,请使用弯曲命令将HTTP请求发送到端口30770上的一个节点:

1curl http://your_worker_ip_address:30770

你会看到类似于此的输出:

 1[secondary_label Output]
 2<!DOCTYPE html>
 3<html>
 4  <head>
 5    <title>Containers Todo Example</title>
 6    <link rel='stylesheet' href='/stylesheets/screen.css' />
 7    <!--[if lt IE 9]>
 8    <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
 9    <![endif]-->
10  </head>
11  <body>
12    <div id="layout">
13<h1 id="page-title">Containers Todo Example</h1>
14<div id="list">
15  <form action="/create" method="post" accept-charset="utf-8">
16    <div class="item-new">
17      <input class="input" type="text" name="content" />
18    </div>
19  </form>
20</div>
21      <div id="layout-footer"></div>
22    </div>
23    <script src="/javascripts/ga.js"></script>
24  </body>
25</html>

您已经定义了 Web Pod 和一个服务,现在让我们看看使用 Replica Sets 来扩展它。

步骤5 – 扩展 Web 应用程序

复制集确保在集群中始终运行最少数量的Pod。当一个Pod被包装为复制集时,Kubernetes 将始终运行规格中定义的最少数量的Pod。

让我们删除当前的Pod,并通过复制集重新创建两个Pod。如果我们离开了运行的Pod,它将不会是复制集的一部分。

首先,删除现有的Pod。

1kubectl delete pod web
1[secondary_label Output]
2pod "web" deleted

现在创建一个新的 replika set 声明. replika set 的定义与pod 相同. 关键的区别是它包含了 replika元素,该元素定义了需要运行的pods 的数量。

创建web-rs.yaml文件,并将此代码添加到文件中:

 1apiVersion: extensions/v1beta1
 2kind: ReplicaSet
 3metadata:
 4  name: web
 5  labels:
 6    name: web
 7    app: todoapp
 8
 9spec:
10  replicas: 2
11  template:
12    metadata:
13      labels:
14        name: web
15    spec:
16      containers:
17      - name: web
18        image: sammy/todo-app
19        ports:
20        - containerPort: 3000

保存并关闭文件。

现在创建复制套件:

1kubectl create -f web-rs.yaml
1[secondary_label Output]
2replicaset "web" created

然后检查Pods的数量:

1kubectl get pods
1[secondary_label Output]
2NAME        READY     STATUS    RESTARTS   AGE
3db          1/1       Running   0          18m
4web-n5l5h   1/1       Running   0          25s
5web-wh6nf   1/1       Running   0          25s

当我们通过 NodePort 访问服务时,请求将发送到由 Replica Set 管理的 Pods 之一。

让我们通过删除其中一个Pod来测试复制集的功能,看看会发生什么:

1kubectl delete pod web-wh6nf
1[secondary_label Output]
2pod "web-wh6nf" deleted

再来看看子:

1kubectl get pods
1[secondary_label Output]
2NAME        READY     STATUS              RESTARTS   AGE
3db          1/1       Running             0          19m
4web-n5l5h   1/1       Running             0          1m
5web-wh6nf   1/1       Terminating         0          1m
6web-ws59m   0/1       ContainerCreating   0          2s

一旦Pod被删除,Kubernetes就创建了另一个,以确保所需的计数保持。

我们可以扩展 replika set 以运行额外的 web Pods。

运行以下命令将 Web 应用程序扩展到 10 个 Pods。

1kubectl scale rs/web --replicas=10
1[secondary_label Output]
2replicaset "web" scaled

点击查看 Pod count:

1kubectl get pods

你会看到这个输出:

 1[secondary_label Output]
 2NAME        READY     STATUS              RESTARTS   AGE
 3db          1/1       Running             0          22m
 4web-4nh4g   1/1       Running             0          21s
 5web-7vbb5   1/1       Running             0          21s
 6web-8zd55   1/1       Running             0          21s
 7web-f8hvq   0/1       ContainerCreating   0          21s
 8web-ffrt6   1/1       Running             0          21s
 9web-k6zv7   0/1       ContainerCreating   0          21s
10web-n5l5h   1/1       Running             0          3m
11web-qmdxn   1/1       Running             0          21s
12web-vc45m   1/1       Running             0          21s
13web-ws59m   1/1       Running             0          2m

Kubernetes已经启动了扩展WebPod的过程,当请求通过NodePort到达服务时,它会被路由到复制集中的一个Pod。

当流量和负载下降时,我们可以回到两个Pod的原始配置。

1kubectl scale rs/web --replicas=2
1[secondary_label Output]
2replicaset "web" scaled

此命令會終止除兩個外的所有 Pods。

1kubectl get pods
 1[secondary_label Output]
 2NAME        READY     STATUS        RESTARTS   AGE
 3db          1/1       Running       0          24m
 4web-4nh4g   1/1       Terminating   0          2m
 5web-7vbb5   1/1       Terminating   0          2m
 6web-8zd55   1/1       Terminating   0          2m
 7web-f8hvq   1/1       Terminating   0          2m
 8web-ffrt6   1/1       Terminating   0          2m
 9web-k6zv7   1/1       Terminating   0          2m
10web-n5l5h   1/1       Running       0          5m
11web-qmdxn   1/1       Terminating   0          2m
12web-vc45m   1/1       Terminating   0          2m
13web-ws59m   1/1       Running       0          4m

要验证复制件集的可用性,请尝试删除其中一个Pod,并检查计数。

1kubectl delete pod web-ws59m
1[secondary_label Output]
2pod "web-ws59m" deleted
1kubectl get pods
1[secondary_label Output]
2NAME        READY     STATUS              RESTARTS   AGE
3db          1/1       Running             0          25m
4web-n5l5h   1/1       Running             0          7m
5web-ws59m   1/1       Terminating         0          5m
6web-z6r2g   0/1       ContainerCreating   0          5s

只要 Pod 數量發生變化,Kubernetes 就會調整它以匹配 YAML 檔案中定義的數量。 當 Replica Set 中的 Web Pod 之一被刪除時,會立即創建另一個 Pod 以保持所需數量。

您可以使用以下命令删除本教程中创建的所有对象:

1kubectl delete -f db-pod.yaml -f db-service.yaml -f web-rs.yaml -f web-service.yaml
1[secondary_label Output]
2pod "db" deleted
3service "db" deleted
4replicaset "web" deleted
5service "web" deleted

结论

在本教程中,您将系列中涵盖的所有概念应用于包装,部署和扩展微服务应用程序。

在本系列的下一部分中,您将学习如何通过运行它作为StatefulSet来使MongoDB高度可用。

Published At
Categories with 技术
comments powered by Disqus