热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

[译]Kubernetes分布式应用部署和人脸识别app实例

原文地址:KUBERNETESDISTRIBUTEDAPPLICATIONDEPLOYMENTWITHSAMPLEFACERECOGNITIONAPP原文作者:skarlso译文出
  • 原文地址:KUBERNETES DISTRIBUTED APPLICATION DEPLOYMENT WITH SAMPLE FACE RECOGNITION APP
  • 原文作者:skarlso
  • 译文出自:掘金翻译计划

技术分享图片

在这个例子中,接收器通过共享数据库集群来存储图像路径。当数据库存储图像路径成功后,接收器实例就能从数据库服务中接收图像 ID。此应用程序是基于在持久层提供实体对象唯一标识的模型的。一旦 ID 产生,接收器会向 NSQ 发送一个消息。到这里,接收器的工作就完成了。

图像处理器

下面是激动人心的开始。当图像处理器第一次运行时,它会创建两个 Go 协程(routine)。 他们是:

Consume

这是一个 NSQ 消费者。它有三个必要的工作。首先,它能够监听队列中的消息。其次,当其接收到消息后,会将收到的 ID 添加到第二个例程处理的线程安全的 ID 切片中去。最后,它通过 sync.Condition 告知第二个协程有工作要做。

ProcessImages

该例程处理 ID 切片,直到切片完全耗尽。一旦切片消耗完,例程将暂停而不是等待 channel。以下是处理单个 ID 的步骤:

  • 与人脸识别服务建立 gRPC 连接(在下面人脸识别章节解释)
  • 从数据库中取回图像记录
  • 设置 断路器 的两个函数
    • 函数 1: 运行 RPC 方法调用的主函数
    • 函数 2: 对断路器的 Ping 进行健康检查
  • 调用函数 1,发送图像路径到人脸识别服务。服务需要能够访问该路径。最好能像 NFS 一样进行文件共享
  • 如果调用失败,更新图像记录的状态字段为“FAILED PROCESSING”
  • 如果成功,将会返回数据库中与图片相关的人物名。它会执行一个 SQL 的连接查询,获取到相关的人物 ID
  • 更新数据库中图片记录的状态字段为“PROCESSED”,以及人物字段为识别出的人物 ID

这个服务可以被复制,换句话说,可以同时运行多个服务。

断路器

虽然这是一个不需要太大精力就能够复制资源的系统,但仍可能存在状况,例如网络故障、服务间的通信问题。因此我在 gRRC 调用上实现了一个小小的断路器作为乐趣。

它是这样工作的:

技术分享图片NSQ

NSQ 是一个极好的基于 Go 语言的队列。它可伸缩并且在系统上具有最小的占用空间。它还具有消费者用来接收消息的查找服务,以及发送者在发送消息时使用的守护程序。

NSQ 的理念是守护进程应该与发送者应用程序一起运行。这样,发件人只会发送到本地主机。但守护进程连接到查找服务,他们就是这样实现全局队列。

这就意味着,有多少个发送者,有需要部署多少个 NSQ 守护进程。由于守护进程的资源要求很小,不会影响主应用程序的需求。

配置

为了尽可能灵活,以及使用 Kubernetes 的 ConfigSet,我在开发中使用 .env 文件来存储配置,如数据库服务的位置或 NSQ 的查找地址。 在生产中,这意味着在 Kubernetes 环境中,我将使用环境变量。

人脸识别应用程序总结

这就是我们即将部署的应用程序的架构。它的所有组件都是可变的,只能通过数据库,队列和 gRPC 进行耦合。由于更新机制的工作原因,这在部署分布式应用程序时非常重要。我将在“部署”部分中介绍该部分。

在 Kubernetes 中部署应用

基础

什么 Kubernetes?

我将在这里介绍一些基础知识,但不会过多介绍细节。如果你想了解更多,可阅读的整本书:Kubernetes Up And Running。另外,如果你足够大胆,你可以看看这个文档:Kubernetes Documentation。

Kubernetes 是一个容器化的服务和应用程序管理平台。它容易扩展,可管理一大堆容器,最重要的是,它可以通过基于 yaml 的模板文件高度配置。人们经常将 Kubernetes 与Docker 集群进行比较,但 Kubernetes 确实不止于此!例如:它可以管理不同的容器。你可以使用 Kubernetes 来对LXC 进行管理和编排,同时也可以使用相同的方式管理 Docker。它提供了一个高于管理已部署服务和应用程序集群的层。怎么样?让我们快速浏览一下 Kubernetes 的构建模块吧。

在 Kubernetes 中,您将描述应用程序的期望状态,Kubernetes 会做一些事情,使之达到这个状态。状态可能是部署、暂停、重复两次等等。

Kubernetes 的基础知识之一是它为所有组件使用标签和注解。Services,Deployments,ReplicaSets,DaemonSets,一切都能够被标记。考虑以下情况。为了确定哪个 pod 属于哪个应用程序,我们将会使用了一个名为 app:myapp 的标签。假设您已部署了此应用程序的两个容器; 如果您从其中一个容器中移除标签 app,则 Kubernetes 只会检测到一个标签,因此会启动一个新的 myapp 实例。

Kubernetes Cluster

对于 Kuberenetes 的工作,需要有 Kubernetes 集群的存在。配置集群可能是非常痛苦的,但幸运的是,帮助就在眼前。Minikube 在本地为我们配置一个带有一个节点的集群。AWS 有一个以 Kubernetes 集群形式运行的测试服务,其中您唯一需要做的就是请求节点并定义你的部署。Kubernetes 集群组件的文档在此处:Kubernetes Cluster Components。

Nodes

一个节点就是一台工作主机。它可以是任何事物,例如物理机、虚拟机以及各种云服务提供的虚拟资源。

Pods

Pods 是一个逻辑上分组的容器,也就意味着一个 Pod 可以容纳多个容器。一个 Pod 在创建后会获得自己的 DNS 和虚拟 IP 地址,这样Kubernetes 就可以为其平衡流量。你很少需要直接处理容器,即使在调试时(比如查看日志),通常也会调用 kubectl logs deployment / your-app -f 而不是查看特定的容器。尽管有可能会调用 -c container_name-f 参数会持续显示日志文件的末尾部分。

Deployments

在 Kubernetes 中创建任何类型的资源时,它将在后台使用 Deployment。一个 Deployment 对象描述当前应用程序的期望状态。这东西可以用来变换 Pod 或 Service 的状态,更新或推出新版的应用。您不直接控制 ReplicaSet(如稍后所述),但可以控制 Deployment 对象来创建和管理 ReplicaSet。

Services

默认情况下,Pod 会得到一个 IP 地址。然而,因为 Pods 在 Kubernetes 中是一个不稳定的东西,所以你需要更持久的东西。队列、mysql、内部API、前端,这些需要长时间运行并且需要在一个静态的,不变的IP或最好是 DNS 记录之后。

为此,Kubernetes 提供可定义可访问模式的 Services。负载均衡,简单 IP 或内部 DNS。

Kubernetes 如何知道服务是否正确运行?你可以配置运行状况检查和可用性检查。运行状况检查将检查容器是否正在运行,但这并不意味着你的服务正在运行。为此,你需要在您的应用程序中对可用的端点进行可用性检查。

由于 Services 非常重要,我建议你稍后在这里阅读它们:Services。预先提醒,这部分文档内容很多,有 24 个 A4 大小的页面,内容包含网络、服务和发现。但是这对于你是否决定要在生产环境中使用 Kubernetes 是至关重要的。

DNS / Service Discovery

如果您在集群中创建服务,该服务将获取由特殊的Kubernetes Deployments 对象(被称作为 kube-proxy 和 kube-dns)提供的在 Kubernetes 中的 DNS 记录。这两个对象在集群中提供了服务发现。如果您运行了mysql服务并设置了 clusterIP:none,那么集群中的每个人都可以通过 ping mysql.default.svc.cluster.local 来访问该服务。 其中:

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

该域名可以通过自定义来更改。要访问集群外部的服务,必须有 DNS 提供者,再使用Nginx(例如)将IP地址绑定到记录。可以使用以下命令查询服务的公共IP地址:

  • NodePort – kubectl get -o jsOnpath="{.spec.ports[0].nodePort}" services mysql
  • LoadBalancer – kubectl get -o jsOnpath="{.spec.ports[0].LoadBalancer}" services mysql

Template Files

像 Docker Compose、TerraForm 或其他服务管理工具一样,Kubernetes 也提供了配置模板的基础设施。这意味着你很少需要手工做任何事情。

例如,请看下面使用 yaml 文件来配置 nginx 部署的模板:

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) 添加可识别此部署的元数据以及使用 label 创建每一个资源 (3)
  • (4) 然后描述所需要的状态规格。
  • (5) 对于 nginx 应用程序,包含 3 个 replicas
  • (6) 这是关于容器的模板定义。这里配置的 Pod 包含一个 name 为 nginx 的容器。其中,使用 1.7.9 版本的 nginx 镜像(这个例子中使用的是 Docker),暴露的端口号为:80

ReplicaSet

ReplicaSet 是低级复制管理器。 它确保为应用程序运行正确数量的复制。 但是,当部署处于较高级别,应始终管理 ReplicaSets。你很少需要直接使用 ReplicaSets,除非您有一个需要控制复制细节的特殊案例。

DaemonSet

还记得我说的Kubernetes是如何持续使用标签的吗?DaemonSet 是一个控制器,用于确保守护程序应用程序始终在具有特定标签的节点上运行。

例如:您希望所有标有 loggermission_critical 的节点运行记录器/审计服务守护程序。然后你创建一个 DaemonSet,并给它一个名为 loggermission_critical 的节点选择器。Kubernetes 将寻找具有该标签的节点。始终确保它将有一个守护进程的实例在其上运行。因此,在该节点上运行的每个实例都可以在本地访问该守护进程。

在我的应用程序中,NSQ 守护进程可能是一个 DaemonSet。为了确保它在具有接收器组件的节点上运行,我采用 receiver 标记一个节点,并用 receiver 应用程序选择器指定一个 DaemonSet。

DaemonSet 具有 ReplicaSet 的所有优点。它是可扩展的并由Kubernetes管理它。这意味着,所有的生命周期事件都由 Kube 处理,确保它永不消亡,并且一旦发生,它将立即被替换。

Scaling

在 Kubernetes 中做扩展很简单。ReplicaSets 负责管理 Pod 的实例数量,如 nginx 部署中所看到的,使用“replicas:3”设置。我们应该以允许 Kubernetes 运行它的多个副本的方式编写我们的应用程序。

当然这些设置是巨大的。你可以指定哪些复制必须在什么节点上运行,或者在各种等待时间等待实例出现的时间。你可以在这里阅读关于此主题的更多信息:Horizontal Scaling 和此处:Interactive Scaling with Kubernetes,当然还有一个 ReplicaSet 控件的详细信息 所有的 scaling 都可以在 Kubernetes 中实现。

Kubernetes 总结

这是一个处理容器编排的便利工具。 它的基本单位是具有分层的架构的 Pods。顶层是 Deployments,通过它处理所有其他资源。它高度可配置,提供了一个用于所有调用的 API,因此比起运行 kubectl,你可以编写自己的逻辑将信息发送到 Kubernetes API。

Kubernetes 现在支持所有主要的云提供商,它完全是开源的,随意贡献!如果你想深入了解它的工作方式,请查看代码:Kubernetes on Github。

Minikube

我将使用 Minikube。Minikube 是一个本地 Kubernetes 集群模拟器。尽管模拟多个节点并不是很好,但如果只是着手去学习并在本地折腾一下的话,这种方式不需要任何的开销,是极好的。Minikube是基于虚拟机的,如果需要的话,可以使用 VirtualBox 等进行微调。

所有我将要使用的 kube 模板文件可以在这里找到:Kube files。

注意:如果稍后想要使用 scaling 但注意到复制总是处于“Pending”状态,请记住 minikube 仅使用单个节点。它可能不允许同一节点上有多个副本,或者只是明显耗尽了资源。您可以使用以下命令检查可用资源:

kubectl get nodes -o yaml

创建容器

Kubernetes 支持大部分容器。我将要使用 Docker。对于我构建的所有服务,存储库中都包含一个 Dockerfile。我鼓励你去研究它们。他们大多数都很简单。对于 Go 服务,我正在使用最近引入的多阶段构建。Go 服务是基于 Alpine Linux 的。人脸识别服务是 Python实现的。NSQ 和 MySQL 正在使用他们自己的容器。

上下文

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

部署应用

Pods 和 Services 概述:

技术分享图片

它会在 / unknown_people 下寻找名为 unknown220.jpg 的图像,在 unknown_folder 中找到与未知图像中的人相对应的图像,并返回匹配图像的名称。

查看日志,你会看到如下内容:

# Receiver
? curl -d '{"path":"/unknown_people/unknown219.jpg"}' http://192.168.99.100:30251/image/post
got path: {Path:/unknown_people/unknown219.jpg}
image saved with id: 4
image sent to nsq

# Image Processor
2018/03/26 18:11:21 INF    1 [images/ch] querying nsqlookupd http://nsqlookup.default.svc.cluster.local:4161/lookup?topic=images
2018/03/26 18:11:59 Got a message: 4
2018/03/26 18:11:59 Processing image id:  4
2018/03/26 18:12:00 got person:  Hannibal
2018/03/26 18:12:00 updating record with person id
2018/03/26 18:12:00 done

这样,所有服务就部署完成了。

前端

最后,还有一个小型的 web 应用程序,它能够方便地展示数据库中的信息。这也是一个面向公众的接收服务,其参数与接收器相同。

它看起来像这样:

技术分享图片

在这里,客户端是 curl。通常情况下,如果客户端是个服务,我会改一下,在新的路径抛出 404 时可以再试试老的路径。

为简洁起见,我不修改 NSQ 和其他用来批量图像处理的操作,他们仍然会一个一个接收。这就当作业留给你们来做了。

新的镜像

要执行滚动更新,我必须首先从接收器服务创建一个新镜像。

docker build -t skarlso/kube-receiver-alpine:v1.1 .

一旦完成,我们可以开始推出更改。

滚动更新

在 Kubernetes 中,您可以通过多种方式配置滚动更新:

手动更新

如果我在我的配置文件中使用了一个名为 v1.0 的容器版本,那么更新只是简单地调用:

kubectl rolling-update receiver --image:skarlso/kube-receiver-alpine:v1.1

如果在部署期间出现问题,我们总是可以回滚。

kubectl rolling-update receiver --rollback

它将恢复以前的版本。 不需要大惊小怪,没有任何麻烦。

应用一个新的配置文件

手动更新的问题在于它们不在源代码控制中。

考虑一下:由于手动进行“快速修复”,一些服务器得到了更新,但没有人目睹它,并且没有记录。另一个人出现并对模板进行更改并将模板应用到群集。所有服务器都会更新,然后突然出现服务中断。

长话短说,更新后的服务器已经被覆盖,因为该模板没有反映手动完成的工作。

推荐的方法是更改??模板以使用新版本,并使用 apply 命令应用模板。

Kubernetes 建议使用 ReplicaSets 进行部署应处理分发这意味着滚动更新必须至少有两个副本。如果少于两个副本存在,则更新将不起作用(除非 maxUnavailable 设置为 1)。我增加了 yaml 的副本数量。我还为接收器容器设置了新的镜像版本。

    replicas: 2
...
    spec:
        containers:
        - name: receiver
        image: skarlso/kube-receiver-alpine:v1.1
...

看看处理情况,这是你应该看到的:

? kubectl rollout status deployment/receiver-deployment
Waiting for rollout to finish: 1 out of 2 new replicas have been updated...

您可以通过指定模板的 strategy 部分添加其他部署配置设置,如下所示:

strategy:
type: RollingUpdate
rollingUpdate:
    maxSurge: 1
    maxUnavailable: 0

有关滚动更新的更多信息,请参见以下文档:Deployment Rolling Update, Updating a Deployment, Manage Deployments, Rolling Update using ReplicaController。

MINIKUBE 的用户注意:由于我们在具有一个节点和一个应用程序副本的本地机器上执行此操作,我们必须将 maxUnavailable 设置为 1; 否则 Kubernetes 将不允许更新发生,并且新版本将保持 Pending 状态。这是因为我们不允许存在没有运行容器的服务,这基本上意味着服务中断。

Scaling

用 Kubernetes 来 scaling 比较容易。由于它正在管理整个集群,因此基本上只需将一个数字放入所需副本的模板中即可使用。

迄今为止这是一篇很棒的文章,但时间太长了。我正在计划编写一个后续行动,我将通过多个节点和副本真正扩展 AWS 的功能; 再加上 Kops 部署 Kubernetes 集群。敬请期待!

清理

kubectl delete deployments --all
kubectl delete services -all

写在最后

女士们,先生们。我们用 Kubernetes 编写,部署,更新和扩展了(当然还不是真的)分布式应用程序。

如果您有任何问题,请随时在下面的评论中讨论。我非常乐意解答。

我希望你享受阅读它,虽然这很长, 我正在考虑将它分成多篇博客,但是一个整体的单页指南是有用的,并且可以很容易地找到,保存和打印。

感谢您的阅读。

  • 本文https://github.com/xitu/gold-miner/blob/master/TODO1/kubernetes-distributed-application.md
  • 译者:maoqyhz
  • 校对者:cf020031308、HCMY
  • 如果发现译文存在错误或其他需要改进的地方,欢迎到 掘金翻译计划 对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 本文永久链接 即为本文在 GitHub 上的 MarkDown 链接。

[译]Kubernetes 分布式应用部署和人脸识别 app 实例


推荐阅读
  • malloc 是 C 语言中的一个标准库函数,全称为 memory allocation,即动态内存分配。它用于在程序运行时申请一块指定大小的连续内存区域,并返回该区域的起始地址。当无法预先确定内存的具体位置时,可以通过 malloc 动态分配内存。 ... [详细]
  • 本文详细介绍了Linux系统中用于管理IPC(Inter-Process Communication)资源的两个重要命令:ipcs和ipcrm。通过这些命令,用户可以查看和删除系统中的消息队列、共享内存和信号量。 ... [详细]
  • NX二次开发:UFUN点收集器UF_UI_select_point_collection详解
    本文介绍了如何在NX中使用UFUN库进行点收集器的二次开发,包括必要的头文件包含、初始化和选择点集合的具体实现。 ... [详细]
  • 本文介绍了如何在 ASP.NET 中设置 Excel 单元格格式为文本,获取多个单元格区域并作为表头,以及进行单元格合并、赋值、格式设置等操作。 ... [详细]
  • LDAP服务器配置与管理
    本文介绍如何通过安装和配置SSSD服务来统一管理用户账户信息,并实现其他系统的登录调用。通过图形化交互界面配置LDAP服务器,确保用户账户信息的集中管理和安全访问。 ... [详细]
  • 如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:1)延时时间较长,且资源占用率高 ... [详细]
  • 网络爬虫的规范与限制
    本文探讨了网络爬虫引发的问题及其解决方案,重点介绍了Robots协议的作用和使用方法,旨在为网络爬虫的合理使用提供指导。 ... [详细]
  • 使用 Git Rebase -i 合并多个提交
    在开发过程中,频繁的小改动往往会生成多个提交记录。为了保持代码仓库的整洁,我们可以使用 git rebase -i 命令将多个提交合并成一个。 ... [详细]
  • Manacher算法详解:寻找最长回文子串
    本文将详细介绍Manacher算法,该算法用于高效地找到字符串中的最长回文子串。通过在字符间插入特殊符号,Manacher算法能够同时处理奇数和偶数长度的回文子串问题。 ... [详细]
  • 本文介绍了多种开源数据库及其核心数据结构和算法,包括MySQL的B+树、MVCC和WAL,MongoDB的tokuDB和cola,boltDB的追加仅树和mmap,levelDB的LSM树,以及内存缓存中的一致性哈希。 ... [详细]
  • Python多线程详解与示例
    本文介绍了Python中的多线程编程,包括僵尸进程和孤儿进程的概念,并提供了具体的代码示例。同时,详细解释了0号进程和1号进程在系统中的作用。 ... [详细]
  • 本文介绍了 AngularJS 中的 $compile 服务及其用法,通过示例代码展示了如何使用 $compile 动态编译和链接 HTML 元素。 ... [详细]
  • [c++基础]STL
    cppfig15_10.cppincludeincludeusingnamespacestd;templatevoidprintVector(constvector&integer ... [详细]
  • ZooKeeper 入门指南
    本文将详细介绍ZooKeeper的工作机制、特点、数据结构以及常见的应用场景,包括统一命名服务、统一配置管理、统一集群管理、服务器动态上下线和软负载均衡。 ... [详细]
  • 自动验证时页面显示问题的解决方法
    在使用自动验证功能时,页面未能正确显示错误信息。通过使用 `dump($info->getError())` 可以帮助诊断和解决问题。 ... [详细]
author-avatar
没得名儿呀没名字
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有