找回密码
 骑士注册

QQ登录

微博登录

搜索
❏ 站外平台:

Linux中国开源社区 技术 查看内容

Kubernetes 分布式应用部署实战:以人脸识别应用为例

作者: Hannibal 译者: LCTT Andy Song

| 2018-07-30 18:24      

使用 Kubernetes 部署应用

基础知识

Kubernetes 是什么?

这里我会提到一些基础知识,但不会深入细节,细节可以用一本书的篇幅描述,例如 Kubernetes 构建与运行。另外,如果你愿意挑战自己,可以查看官方文档:Kubernetes 文档

Kubernetes 是容器化服务及应用的管理器。它易于扩展,可以管理大量容器;更重要的是,可以通过基于 yaml 的模板文件高度灵活地进行配置。人们经常把 Kubernetes 比作 Docker Swarm,但 Kubernetes 的功能不仅仅如此。例如,Kubernetes 不关心底层容器实现,你可以使用 LXC 与 Kubernetes 的组合,效果与使用 Docker 一样好。Kubernetes 在管理容器的基础上,可以管理已部署的服务或应用集群。如何操作呢?让我们概览一下用于构成 Kubernetes 的模块。

在 Kubernetes 中,你给出期望的应用状态,Kubernetes 会尽其所能达到对应的状态。状态可以是已部署、已暂停,有 2 个副本等,以此类推。

Kubernetes 使用标签和注释标记组件,包括服务、部署、副本组、守护进程组等在内的全部组件都被标记。考虑如下场景,为了识别 pod 与应用的对应关系,使用 app: myapp 标签。假设应用已部署 2 个容器,如果你移除其中一个容器的 app 标签,Kubernetes 只能识别到一个容器(隶属于应用),进而启动一个新的具有 myapp 标签的实例。

Kubernetes 集群

要使用 Kubernetes,需要先搭建一个 Kubernetes 集群。搭建 Kubernetes 集群可能是一个痛苦的经历,但所幸有工具可以帮助我们。Minikube 为我们在本地搭建一个单节点集群。AWS 的一个 beta 服务工作方式类似于 Kubernetes 集群,你只需请求节点并定义你的部署即可。Kubernetes 集群组件的文档如下:Kubernetes 集群组件

节点

节点node是工作单位,形式可以是虚拟机、物理机,也可以是各种类型的云主机。

Pod

Pod 是本地容器逻辑上组成的集合,即一个 Pod 中可能包含若干个容器。Pod 创建后具有自己的 DNS 和虚拟 IP,这样 Kubernetes 可以对到达流量进行负载均衡。你几乎不需要直接和容器打交道;即使是调试的时候,例如查看日志,你通常调用 kubectl logs deployment/your-app -f 查看部署日志,而不是使用 -c container_name 查看具体某个容器的日志。-f 参数表示从日志尾部进行流式输出。

部署

在 Kubernetes 中创建任何类型的资源时,后台使用一个部署deployment组件,它指定了资源的期望状态。使用部署对象,你可以将 Pod 或服务变更为另外的状态,也可以更新应用或上线新版本应用。你一般不会直接操作副本组 (后续会描述),而是通过部署对象创建并管理。

服务

默认情况下,Pod 会获取一个 IP 地址。但考虑到 Pod 是 Kubernetes 中的易失性组件,我们需要更加持久的组件。不论是队列,MySQL、内部 API 或前端,都需要长期运行并使用保持不变的 IP 或更好的 DNS 记录。

为解决这个问题,Kubernetes 提供了服务service组件,可以定义访问模式,支持的模式包括负载均衡、简单 IP 或内部 DNS。

Kubernetes 如何获知服务运行正常呢?你可以配置健康性检查和可用性检查。健康性检查是指检查容器是否处于运行状态,但容器处于运行状态并不意味着服务运行正常。对此,你应该使用可用性检查,即请求应用的一个特别接口endpoint

由于服务非常重要,推荐你找时间阅读以下文档:服务。严肃的说,需要阅读的东西很多,有 24 页 A4 纸的篇幅,涉及网络、服务及自动发现。这也有助于你决定是否真的打算在生产环境中使用 Kubernetes。

DNS / 服务发现

在 Kubernetes 集群中创建服务后,该服务会从名为 kube-proxykube-dns 的特殊 Kubernetes 部署中获取一个 DNS 记录。它们两个用于提供集群内的服务发现。如果你有一个正在运行的 MySQL 服务并配置 clusterIP: no,那么集群内部任何人都可以通过 mysql.default.svc.cluster.local 访问该服务,其中:

  • mysql – 服务的名称
  • default – 命名空间的名称
  • svc – 对应服务分类
  • cluster.local – 本地集群的域名

可以使用自定义设置更改本地集群的域名。如果想让服务可以从集群外访问,需要使用 DNS 服务,并使用例如 Nginx 将 IP 地址绑定至记录。服务对应的对外 IP 地址可以使用如下命令查询:

  • 节点端口方式 – kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services mysql
  • 负载均衡方式 – kubectl get -o jsonpath="{.spec.ports[0].LoadBalancer}" services mysql

模板文件

类似 Docker Compose、TerraForm 或其它的服务管理工具,Kubernetes 也提供了基础设施描述模板。这意味着,你几乎不用手动操作。

以 Nginx 部署为例,查看下面的 yaml 模板:

apiVersion: apps/v1
kind: Deployment #(1)
metadata: #(2)
  name: nginx-deployment
  labels: #(3)
    app: nginx
spec: #(4)
  replicas: 3 #(5)
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers: #(6)
      - name: nginx
        image: nginx:1.7.9
        ports:
        - containerPort: 80

在这个示例部署中,我们做了如下操作:

  • (1) 使用 kind 关键字定义模板类型
  • (2) 使用 metadata 关键字,增加该部署的识别信息
  • (3) 使用 labels 标记每个需要创建的资源
  • (4) 然后使用 spec 关键字描述所需的状态
  • (5) nginx 应用需要 3 个副本
  • (6) Pod 中容器的模板定义部分
  • 容器名称为 nginx
  • 容器模板为 nginx:1.7.9 (本例使用 Docker 镜像)

副本组

副本组ReplicaSet是一个底层的副本管理器,用于保证运行正确数目的应用副本。相比而言,部署是更高层级的操作,应该用于管理副本组。除非你遇到特殊的情况,需要控制副本的特性,否则你几乎不需要直接操作副本组。

守护进程组

上面提到 Kubernetes 始终使用标签,还有印象吗?守护进程组DaemonSet是一个控制器,用于确保守护进程化的应用一直运行在具有特定标签的节点中。

例如,你将所有节点增加 loggermission_critical 的标签,以便运行日志 / 审计服务的守护进程。接着,你创建一个守护进程组并使用 loggermission_critical 节点选择器。Kubernetes 会查找具有该标签的节点,确保守护进程的实例一直运行在这些节点中。因而,节点中运行的所有进程都可以在节点内访问对应的守护进程。

以我的应用为例,NSQ 守护进程可以用守护进程组实现。具体而言,将对应节点增加 recevier 标签,创建一个守护进程组并配置 receiver 应用选择器,这样这些节点上就会一直运行接收者组件。

守护进程组具有副本组的全部优势,可扩展且由 Kubernetes 管理,意味着 Kubernetes 管理其全生命周期的事件,确保持续运行,即使出现故障,也会立即替换。

扩展

在 Kubernetes 中,扩展是稀松平常的事情。副本组负责 Pod 运行的实例数目。就像你在 nginx 部署那个示例中看到的那样,对应设置项 replicas:3。我们可以按应用所需,让 Kubernetes 运行多份应用副本。

当然,设置项有很多。你可以指定让多个副本运行在不同的节点上,也可以指定各种不同的应用启动等待时间。想要在这方面了解更多,可以阅读 水平扩展Kubernetes 中的交互式扩展;当然 副本组 的细节对你也有帮助,毕竟 Kubernetes 中的扩展功能都来自于该模块。

Kubernetes 部分小结

Kubernetes 是容器编排的便捷工具,工作单元为 Pod,具有分层架构。最顶层是部署,用于操作其它资源,具有高度可配置性。对于你的每个命令调用,Kubernetes 提供了对应的 API,故理论上你可以编写自己的代码,向 Kubernetes API 发送数据,得到与 kubectl 命令同样的效果。

截至目前,Kubernetes 原生支持所有主流云服务供应商,而且完全开源。如果你愿意,可以贡献代码;如果你希望对工作原理有深入了解,可以查阅代码:GitHub 上的 Kubernetes 项目

Minikube

接下来我会使用 Minikube 这款本地 Kubernetes 集群模拟器。它并不擅长模拟多节点集群,但可以很容易地给你提供本地学习环境,让你开始探索,这很棒。Minikube 基于可高度调优的虚拟机,由 VirtualBox 类似的虚拟化工具提供。

我用到的全部 Kubernetes 模板文件可以在这里找到:Kubernetes 文件

注意:在你后续测试可扩展性时,会发现副本一直处于 Pending 状态,这是因为 minikube 集群中只有一个节点,不应该允许多副本运行在同一个节点上,否则明显只是耗尽了可用资源。使用如下命令可以查看可用资源:

kubectl get nodes -o yaml

构建容器

Kubernetes 支持大多数现有的容器技术。我这里使用 Docker。每一个构建的服务容器,对应代码库中的一个 Dockerfile 文件。我推荐你仔细阅读它们,其中大多数都比较简单。对于 Go 服务,我采用了最近引入的多步构建的方式。Go 服务基于 Alpine Linux 镜像创建。人脸识别程序使用 Python、NSQ 和 MySQL 使用对应的容器。

上下文

Kubernetes 使用命名空间。如果你不额外指定命名空间,Kubernetes 会使用 default 命名空间。为避免污染默认命名空间,我会一直指定命名空间,具体操作如下:

❯ kubectl config set-context kube-face-cluster --namespace=face
Context "kube-face-cluster" created.

创建上下文之后,应马上启用:

❯ kubectl config use-context kube-face-cluster
Switched to context "kube-face-cluster".

此后,所有 kubectl 命令都会使用 face 命名空间。

(LCTT 译注:作者后续并没有使用 face 命名空间,模板文件中的命名空间仍为 default,可能 face 命名空间用于开发环境。如果希望使用 face 命令空间,需要将内部 DNS 地址中的 default 改成 face;如果只是测试,可以不执行这两条命令。)

查看其它分页:
LCTT 译者
Andy Song 🌟🌟🌟🌟
共计翻译: 27.0 篇 | 共计贡献: 148
贡献时间:2018-03-26 -> 2018-08-21
访问我的 LCTT 主页 | 在 GitHub 上关注我


最新评论

我也要发表评论

返回顶部

分享到微信

打开微信,点击顶部的“╋”,
使用“扫一扫”将网页分享至微信。