有状态应用的容器化

简介

应用容器技术(如Docker)为底层的应用组件提供了标准的封装和运行管理机制标准。

容器在快速部署的同时实现系统资源的高效利用。开发者可以通过使用容器来提升应用的可移植性,实现镜像管理的编码控制。运营团队也可以借助容器化技术实现应用部署和管理时运行单元的标准化。

然而,应用容器除了这些我们众所周知的优点之外,我们中很多人还有这这样的误解:应用容器的生命周期一般比较短暂,所以非常适合来做无状态的微服务,与之相反的状态应用的容器化则是不可能的。事实是否是这样呢?我们下面来看一下这个说法是否站得住脚。

应用状态的理解

应用状态就是应用组件完成他们的工作(即执行任务)时所需的数据。从软件的架构、编码的范式到编程语言本身都离不开应用状态的参与,应用状态实质上说明了着怎样去管理一个应用的行为(任务,操作等)和状态(数据)。

即使微服务风格的应用也是有状态的!在微服务架构中,每个服务都可以有多个用例并且每个服务都被设计为无状态化(stateless)的。这意味着每个服务实例并不会再操作中存储任何数据。也就是说,无状态化只是意味着服务实例可以从某些地方取回执行行为所需的所有应用状态。这一点是微服务应用重要的架构约束,它确保了服务的弹性化,即任何可用的服务实例可以用来执行任何任务。

一般来说,应用状态会通过数据库、缓存、文件或者其他形式转储,与之伴随而来的应用状态的切换也需要通过操作写回存储。

所以从这一点来看,所有的应用都是有状态的,但是只要应用的行为和其执行行为所需的数据实现完全分离,那么它就是无状态化的了。这个想法很好,但这并没有解决问题,而是把问题转移到了其他的地方——其他的组件如何管理应用状态?这个问题的答案依赖于我们讨论的状态类型。

为了解答这个问题,我们将一个应用可能的状态分为了五大类,下面让我们针对容器化时每一类状态需要解决的问题进行讨论。

  1. 持久性状态(Presistent state)
  2. 配置状态(Configuration state)
  3. 会话状态(Session state)
  4. 连接状态(Connection state)
  5. 集群状态(Cluster state)

容器化与持久性状态

在应用重启或者被关停时,应用的持久化状态也需要保留下来。因此这种类型的状态通常被存储在数据库的冗余层并且需要定期备份。

虽然应用和数据库放在相同的容器中是可行的,但是当你的应用组件变化非常频繁时,将他们分开会是更好的决定。并且应用和数据库分开之后,多个应用实例就可以共享其中的应用状态。

如果你的应用已经使用了外部数据库也不要紧,以服务的形式还是安装在虚拟机、物理机之上都可以,你只需要在保持当前架构的同时实现上层应用层的容器化即可。大多数的容器管理系统都是支持把数据库访问信息作为配置项传入应用层容器的(详见下面的“配置状态”)

或者,你可以选择容器化你的数据库!它可以为你带来快速恢复、快速备份以及其它数据层容器所具有的优点。这种解决方案里,你需要考虑一些与你的数据库相关的一些问题。

  1. 在同时考虑可用性和规模的情况下,数据库如何去管理它的集群与副本?这些副本是应该分配一个确定的角色还是应该作为新的成员动态地获得它的角色?
  2. 需要管理的数据量有多少?当新的子节点在数据库集群产生时,是否有必要实现完全的同步?
  3. 在以上基础上,当运行数据库软件的容器停机时,副本的数据是否需要留存?当主机停止运行时呢?

为了使数据可以在容器被终止的时候留存,你将需要一个在容器外管理数据的存储机制。利用主机的空间(Host Volume)并将主机的地址映射到容器就可以非常轻松地做到这一点。

与之相似的,为了使主机停机时数据也可以留存,你需要一个在主机外管理数据的存储机制。大多数的云平台支持共享式文件系统或者块存储,他们可以被独立管理并且可以灵活地任何主机上挂载或者卸载。如果你的容器的调配提供了生命周期事件来管理存储组件的话,那么实现这一点是十分容易的。

QQ20180108-094333.png

但是如果你的数据需要保持挂载在一个确定的容器怎么办呢?比方说如果你的客户中有一个需要管理大量的视频内容以至于它们不能被复制,这时候这个问题就很突出了。因为如果他们的容器挂掉了,需要在另一台主机上重启时,他们需要和之前一样同样可用的数据。

如果你有很多这样的应用,那么可以用卷(volume)插件来简化数据的编配。卷插件位于容器引擎的底层,可以帮助编配数据。许多的卷插件只是 IaaS/CMP 调用的一层简单包装罢了,但是还有一些提供了一系列丰富的特性,比方说 QoS 、分层存储以及企业级存储的支持,这些特性也许值得一看。

让我们总结一下可选策略各自对应的场合:

  • 主机卷(Host Volume):当数据库支持副本加入集群并可以实现与其他成员的同步时,这一策略的效果会很好,通常这时的数据库规模都比较小。
  • 共享式卷或共享文件系统:你的数据需要独立于主机存在。当你具有一个大的数据集且不想为一个新加入数据库的节点进行完全的数据同步时,这会是一个很好的选择。
  • 卷插件:当你的编配软件不支持外部系统的管理或者说你的应用在重启之后,数据需要被加载在同一个容器的时候。

容器化与配置状态

应用通常需要一些非域数据(non-domain)才可以正确配置。这就是配置状态,它可能是外部服务的 IP 地址,也可能是连接服务器所需的证书。

Heroku 推广的 12-factor app指南被大多数的Pass解决方案所应用,其中就规定了将配置数据存储在环境当中。在容器化的世界中,大多数的配置数据都被当做可以注入到容器中的环境变量来管理。

然而,一些机密数据(证书、密码、秘钥或者其他机密数据)最好还是通过其他安全的机制来处理以免这些数据被他人通过主机,网络或者存储方式获取或者看到。对于这类配置状态,像 KeyWhiz 和 Vault 这样的证书管理工具可以提供容器内使用的一次性验证令牌。还有一种选择是将卷插件和秘钥进行绑定来提供给容器化应用机密数据。

容器化与会话状态

当一个用户登录的时候,应用就会创建会话数据。它可以是提供给这个用户的一个验证秘钥或者其他的临时状态。在现在大多数流行的应用中,会话状态被存储在分布式缓存中或者一个可以被任何服务样例访问到的数据库中。

然而在传统的多页 Web 应用中,每个网页都需要获取服务端管理的会话状态。于是所有的用户对会话的请求都必须定向到相同的后端服务器,或者该用户就要被强制要求再次登录。也就是说这样的应用程序从一个指定的服务器请求“粘性会话”(sticky session),并且对这个客户端的会话请求总是需要路由到相同的服务。

这并不是容器化的问题,可以看到在虚拟机或者物理机上部署的应用服务器的请求要达到负载均衡时也会发生相同的问题。大多数的负载均衡也会提供支持粘性会话的选项。

在容器化的世界中,你的容器的 IP 地址可能与你的主机的 IP 地址有所不同。当你使用4-7层的负载均衡来处理带有状态化的会话数据的前端应用容器时,负载均衡器也要处理粘性会话。

容器的原生解决方案 (Nirmata’s Service Gateway)提供了粘性会话的支持,并且可以在容器跨主机重新部署时动态地更新路由信息 。

容器化与连接状态

一些应用可能需要协议来进行通信,比方说WebSocket,它作为一个通信实体被视作有状态的是因为在它构建的连接上可以交换数据。在这种定义下,可以看到像 HTTP 这样的协议就是无状态化的,因为服务器并不会从请求中记忆任何状态数据,任何其他的服务器也可以应答下一次的请求。

如果你的应用使用的是状态化的协议,容器的负载均衡方案也需要支持客户端对使用有状态协议的协议请求的路由。比方说当你使用 WebSocket 协议时,负载均衡需要维持在之前请求中建立的TCP 连接。同样的,这种特性在大多数基于容器的传统负载均衡中都是被支持的。

QQ20180108-095256.png

容器化与集群状态

为了可用性和规模要求,大多数的应用需要在一个集群中运行多个实例,这时候就需要共享集群成员关系以及他们的状态。这个状态并不需要一直被保持,但是当集群的成员关系发生变更时它应该做出及时的更新。

在集群应用中,每一个集群中的成员都需要知道其他成员以及它们的角色。在大多数先进的集群应用中,它们会使用一个成员的初始状态集(seed set,通常为它们的 IP 地址以及端口)来引导启动,之后成员以及它们的变化都可以被动态地管理。然而,还有一些集群服务在当成员信息变更需要传播的情况下需要手动更新重启。

这些情况在基于容器的编配系统下都是可以被解决的。比方说,最近 Kubernetes 就推出了 PetSet 的特性来支持状态化的集群。Nirmata 通过预先计算容器的布局并向所有的集群成员注入与之对应的唯一省份以及集群信息来支持集群系统的预编配。

其他类型的状态?

在与客户一起来容器化他们的应用的时候,我们遇到了各种各样有趣的场景。其中一个例子是某个应用通过读取本地的 MAC 地址,并用它来唯一标示它自己!很显然在这个场景下,如果容器在重启的时候得到了一个不同的 MAC 地址,这个方案就会崩溃。

幸运的是,Docker 现在已经支持指定容器的 MAC 地址。为了应对这些可能的情况,你需要确保你的编配系统具有足够的灵活性,来保证容器运行时可以指定用户所需的配置。

总结

在这篇文章中,我们讨论了应用状态的概念以及我们可能遇到不同应用状态,分析了在容器化的环境中怎样处理各种状态。在大多数的情况下我们都有几个选项可供选择。综上所述,虽然容器的生命周期是短暂的,但应用状态未必如此!

我写这篇文章的目标就是告诉给大家有状态的应用也是可以被容器化的。你觉得我做的怎么样呢?我们非常希望收到你的反馈和建议。如果你有一些问题,我也可以帮忙做出解答。

你可以访问这个网址来免费体验 Nirmata 的所有功能。

获取我们的免费电子书副本:传统容器的容器化

本文的版权归 ArrayZoneYour 所有,如需转载请联系作者。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏blackpiglet

在Play with Kubernetes平台上以测试驱动的方式部署Istio

翻译一篇 Istio 部署教程,原文链接:test-drive-your-first-istio-deployment-using-play-with-kube...

1582
来自专栏Java架构师历程

6、选择部署策略

本书主要介绍关于如何使用微服务构建应用程序,这是本书的第六章。第一章介绍了微服务架构模式,讨论了使用微服务的优点与缺点。之后的章节讨论了微服务架构的方方面面:使...

2063
来自专栏OneinStack

腾讯云主机上如何安装OneinStack镜像?

一,登录腾讯云"控制台",找到"云主机",勾选要安装的主机,然后选择"关机",如下图一所示

5580
来自专栏啸天"s blog

you-get一行命令下载所需音视频资源

1412
来自专栏Java编程技术

利用MongoDB 分片集群(Sharded Cluster)实现高并发大数据处理

考虑这样一个场景,有个数据量有10多亿数据的设备库,里面存放了注册的设备的信息,并且设备数据还可能会递增,然后业务集群需要对指定条件的设备群发信息,那么如何才能...

3232
来自专栏DevOps时代的专栏

测试微服务 VS 测试单体式应用

使用微服务比起使用单体式应用程序结构有许多优点。 但是微服务并不像单体式应用程序一样已经有确定的开发模式。 许多问题尚未解决,我们也还没有看到完善的“微服务方式...

2018
来自专栏前端知识分享

第105天:Ajax 客户端与服务器基本知识

- 按应用软件可分为:Apache服务器、Nginx 服务器、IIS服务器、Tomcat服务器、 weblogic服务器、WebSphere服务器、boss服务...

1061
来自专栏Rainbond开源「容器云平台」

Rainbond插件体系设计简介

过去几年,利用容器打包和部署代码的方式日益流行,越来越多企业开始测试或是已经在生产环境中运行了微服务架构应用,开始直接面对和解决分布式服务化架构演变中出现的各种...

3739
来自专栏FreeBuf

批量S2-045漏洞检测及利用

前言 S2-045远程代码执行漏洞的CNVD详细信息:http : //www.cnvd.org.cn/flaw/show/CNVD-2017-02474漏洞刚...

2735
来自专栏互联网大杂烩

OAuth协议

OAUTH 协议旨在为用户资源的授权访问提供一个安全,开放的标准。平台商通过OAUTH协议,提示用户对第三方软件厂商(ISV)进进行授权。 使得第三方软件厂商...

651

扫码关注云+社区

领取腾讯云代金券