据说有12个因素定义了云原生应用程序。也有人说Kubernetes专为云原生计算而设计。那么如何使用Kubernetes创建12要素应用程序?让我们来看看到底什么是十二因子应用程序,以及它们与Kubernetes的关系。
什么是12 因素应用?
十二因子应用程序是Heroku创建的软件即服务架构的宣言。这个想法是,为了真正适合SaaS并避免软件侵蚀的问题-随着时间的流逝,未更新的应用程序将与最新的操作系统,安全补丁等不同步-应遵循一个应用程序这12条原则:
- 基准代码
在修订控制中跟踪一个代码库,许多部署 - 依赖
明确声明和隔离依赖项 - 配置
将配置存储在环境中 - 后端服务
将支持服务视为附加资源 - 构建,发布,运行
严格分开的构建和运行阶段 - 进程
将应用程序作为一个或多个无状态进程执行 - 端口绑定
通过端口绑定导出服务 - 并发
通过流程模型进行横向扩展 - 易处理
通过快速启动和正常关闭最大程度地提高鲁棒性 - 开发环境和线上环境等价
保持开发,测试和生产环境尽可能相似 - 日志
将日志视为事件流 - 管理进程
一次性运行管理/管理任务
让我们看一下这一切对Kubernetes应用程序的意义。
原则 I. 基准代码
12因子应用程序的原则1是“一份基础代码库,通过版本管理,实现多个部署”。
对于Kubernetes应用程序,该原理实际上已嵌入到容器编排本身的本质中。通常,您使用git repo之类的源代码控制存储库创建代码,然后将特定版本的镜像存储在Docker Hub中。当您定义要作为Kubernetes Pod,Deployment,DaemonSet的一部分进行编排的容器时,还可以指定镜像的特定版本,如下所示:
...
spec:
containers:
- name: AcctApp
image: acctApp:v3
...
这样,您可能会在不同的部署中运行多个版本的应用程序。
应用程序的运行方式也可能有所不同,具体取决于配置信息。
原则 II. 依赖
12因素应用程序的原则2是“显式声明和隔离依赖项”。
实际上,要确保满足应用程序的依赖关系。对于12因子应用程序,这不仅包括确保可以使用特定于应用程序的库,还不包括指望操作系统,并假设系统库(例如curl)在那里。 12因子应用程序必须是独立的。
这包括确保应用程序足够隔离,不会受到主机上可能安装的冲突库的影响。
幸运的是,如果应用程序确实有任何特定或不寻常的系统要求,则容器可以轻松满足这两个要求。容器包括应用程序所依赖的所有依赖关系,并且还提供了容器在其中运行的合理隔离的环境。 (与流行的看法相反,容器环境不是完全隔离的,但是在大多数情况下,它们足够好。)
对于模块化且依赖于其他组件(例如HTTP服务和日志提取器)的应用程序,Kubernetes提供了一种将所有这些组件组合到单个Pod中的方法,以实现适当封装这些组件的环境。
原则 III. 配置
12因素应用程序的原则3是“在环境中存储配置”。
该原理背后的思想是,应用程序应完全独立于其配置。换句话说,您应该能够将其移动到另一个环境,而无需改变源代码。
一些开发人员通过创建某种类型的配置文件,指定详细信息(例如目录,主机名和数据库凭据)来实现此目标。这是一项改进,但是确实存在有人将配置文件签入源代码控制存储库的风险。
相反,有12个因子的应用程序将其配置存储为环境变量。正如宣言所述,它们“不太可能被偶然检查到存储库中”,并且它们独立于操作系统。
Kubernetes使您可以通过Downward API在清单中指定环境变量,但是由于这些清单本身确实受到检查的int源代码控制,所以这不是一个完整的解决方案。
相反,您可以指定环境变量应由Kubernetes ConfigMap或Secrets的内容填充,这些内容可以与应用程序分开保存。例如,您可以将Pod定义为:
如您所见,此Pod接收三个环境变量SECRET_USERNAME,SECRET_PASSWORD和CONFIG_VERSION,前两个来自引用的Kubernetes Secrets,第三个来自Kubernetes ConfigMap。这使您可以将它们保留在配置文件之外。
当然,仍然存在有人对用于创建这些对象的文件进行错误处理的风险,但是将它们放在一起并制定安全的处理策略比清除散布在部署中的数十个配置文件要大。
而且,社区中的一些人指出,即使环境变量由于其自身的原因也不一定是安全的。例如,如果应用程序崩溃,则可能会将所有环境变量保存到日志中,甚至将其传输到另一个服务。 DiogoMónica指出了一种可与Kubernetes一起使用的名为Keywhiz的工具,可创建安全的秘密存储。
原则 IV. 后端服务
12因素应用程序的原则4是“将后端服务作为附加资源”。
在12因子应用程序中,不属于核心应用程序的任何服务(例如数据库,外部存储或消息队列)都应作为服务(通过HTTP或类似请求)进行访问,并在配置中指定,以便可以更改服务源,而不会影响应用程序的核心代码。
例如,如果您的应用程序使用消息队列系统,则应该能够从RabbitMQ更改为ZeroMQ(或ActiveMQ甚至其他功能),而无需更改配置信息。
对于基于Kubernetes的应用程序,此要求有两个含义。
首先,这意味着您必须考虑应用程序如何接收(和分发)信息。例如,如果您有一个支持数据库,那么即使将其复制到其他实例,您也不想拥有一个本地Mysql实例。相反,您希望有一个单独的容器来处理数据库操作,并使这些操作可通过API调用。这样,如果您需要更改为PostgreSQL或远程托管的MySQL服务器,则可以创建一个新的容器镜像,更新Pod定义,然后重新启动Pod(或更可能是由Deployment或StatefulSet管理它)。
同样,如果您将凭据或地址信息存储在ConfigMap支持的环境变量中,则可以更改该信息并替换Pod。
请注意,这两个示例均假设尽管您未对源代码(甚至主应用程序的容器镜像)进行任何更改,但仍需要替换Pod;做到这一点的能力实际上是12因素应用程序的另一项原则。
Principle V. 构建,发布,运行
12 Factor App的原则5是“严格分开的构建和运行阶段”。
如今,很难想象会有这样的情况,但是十二要素应用程序必须具有单独的构建阶段。换句话说,您应该能够构建或编译代码,然后将其与特定的配置信息结合起来以创建特定的发行版,然后有意地运行该发行版。
发布应该是可识别的。您应该可以说“此部署正在运行此应用程序的1.14版本”或类似的内容,就像我们说我们在运行“ OpenStack Ocata版本”或“ Kubernetes 1.6”一样。它们也应该是不变的。任何更改应导致新版本。如果这听起来令人生畏,请记住,当我们说“应用程序”时,我们不再在谈论大型的整体发行版。取而代之的是,我们谈论的是非常具体的微服务,每个微服务都有其自己的发行版,并且可以在不引起使用服务错误的情况下提高发行版。
所有这些都是为了让应用程序运行时,该“运行”过程可以完全自动化。十二因子应用程序需要能够以自动化方式运行,因为它们需要能够在出现问题时重新启动。
将其转换为Kubernetes领域,我们已经说过,该应用程序需要存储在源代码管理中,然后使用其所有依赖项进行构建。这就是您的构建过程。我们讨论了分离配置信息,因此需要将其与构建结合在一起以发布版本。自动运行应用程序或应用程序的多个副本的能力正是Kubernetes像Deployments,ReplicaSets和DaemonSets那样构造的。
原则 VI. 进程
12因素应用程序的原则6是“将应用程序作为一个或多个无状态进程执行”。
无状态进程是云本机应用程序背后的核心思想。每个十二要素应用程序都需要在单独的,无共享的流程中运行。这意味着,每当您需要保留信息时,就需要将其存储在数据库等支持服务中。
如果您是云应用程序编程的新手,那么这看似简单。许多开发人员习惯于“粘性”会话,并在下一个请求将到达同一服务器的情况下将信息存储在会话中。但是,在云应用程序中,绝对不能做这个假设。
相反,如果您运行的是托管特定Pod的多个副本的基于Kubernetes的应用程序,则必须假定后续请求可以到达任何地方。要解决此问题,您将需要使用某种后备卷或数据库来实现持久性。
对此原则的一个警告是,Kubernetes StatefulSets可以使您创建具有稳定网络身份的Pod,因此从理论上讲,您可以将请求定向到特定Pod。从技术上讲,如果该过程实际上没有存储状态,并且可以删除和重新创建Pod并仍能正常运行,那么它可以满足此要求。
原则 VII. 端口绑定
12 Factor App的原则7是“通过端口绑定导出服务”。
在我们假设不同功能由不同进程处理的环境中,很容易就可以通过诸如HTTP之类的协议来实现这些功能的连接,因此,通常在Web服务器(如Apache)之后运行应用程序或Tomcat。但是,十二要素应用程序不应该以这种方式依赖于其他应用程序。请记住,每个功能都应处于自己的进程中,与其他所有事物隔离。相反,《 12因子应用宣言》建议添加一个Web服务器库或与应用本身类似的东西,以便该应用可以在已定义的端口上等待请求,无论是使用HTTP还是其他协议。
在基于Kubernetes的应用程序中,这部分是通过应用程序本身的体系结构完成的,部分是通过确保应用程序具有所有依赖项作为创建应用程序所基于的基础容器的一部分来完成的。
原则 VIII. 并发
12 Factor App的原则8是“通过进程模型进行横向扩展”。
在编写包含十二个要素的应用程序时,请确保将其设计为横向扩展而不是纵向扩展。这意味着,为了增加容量,您应该能够向运行该应用程序的计算机添加更多实例,而不是添加更多内存或CPU。请注意,这特别意味着能够在其他计算机上启动其他进程,幸运的是,这是Kubernetes的一项关键功能。
原则 IX. 易处理
12 Factor App的原则9是“通过快速启动和平稳关闭来最大化鲁棒性”。
似乎该原理是针对容器和基于Kubernetes的应用程序量身定制的。进程应为一次性的想法意味着,在任何时候,一个应用程序都可能死亡,并且不会因为任何其他事情要代替它,因为它会重新启动而对用户造成影响,或者两者兼而有之。
当然,容器是基于此原理构建的,即使面对问题(例如ReplicaSets),Kubernetes结构也可以管理多个实例并保持一定级别的可用性,从而构成了完整的部署。
原则 X. 开发环境和线上环境等价
12因素应用程序的原则10是“保持开发,测试和生产尽可能相似”。
这似乎是另一条原则,但似乎比大多数人认为的要深。从表面上看,这确实意味着您应具有尽可能相同的开发,阶段和生产环境。实现此目的的一种方法是使用Kubernetes命名空间,使您能够(理论上)在相同的实际集群上针对相同的实际系统运行代码,同时仍保持环境分离。在某些情况下,您还可以使用Minikube或kubeadm-dind-cluster之类的工具来创建生产系统的近克隆。
不过,从更深层次上讲,如《十二个因子》应用宣言所说,它涉及三种不同类型的“鸿沟”:
- 时间鸿沟:开发人员可能需要花费数天,数周甚至数月的时间才能完成生产的代码。
- 人员方面的鸿沟:开发人员编写代码,由运维工程师进行部署。
- 工具之间的鸿沟:开发人员可能正在使用Nginx,SQLite和OS X之类的堆栈,而生产部署则使用Apache,MySQL和Linux。
这里的目标是创建一个持续集成/持续部署的情况,在这种情况下,更改几乎可以立即投入生产(当然,在测试之后!),由编写该更改的开发人员进行部署,以便他们可以实际使用相同的版本在生产中看到它。实际编写代码的工具,以最大程度地减少环境之间的兼容性错误的可能性。
当然,其中一些因素不在Kubernetes的范围内。例如,人员缺口是一个文化问题。但是,时间和工具上的差距可以通过两种方式来弥补。
对于时间间隔,基于Kubernetes的应用程序当然基于容器,而容器本身是基于存储在版本控制系统中的镜像的,因此它们适合CI / CD。还可以通过滚动更新来更新它们,如果出现问题可以回滚,因此它们非常适合这种环境。
就工具差距而言,基于Kubernetes的应用程序的体系结构使管理变得更加容易,既可以通过简化本地依赖关系将其包含在各种镜像中,也可以通过模块化应用程序以使外部支持服务成为可能。标准化。
原则 XI. 日志
12 Factor App的原则11是“将日志作为事件流处理”。
尽管大多数传统应用程序将日志信息存储在文件中,但十二要素应用程序却将其作为事件流定向到stdout。执行环境负责收集这些事件。这可能就像将stdout重定向到文件一样简单,但是在大多数情况下,它涉及使用日志路由器(例如Fluentd)并将日志保存到Hadoop或服务(例如Splunk)。
在Kubernetes中,您至少有两个选择可以进行自动日志记录捕获:如果您使用的是Google Cloud,则为Stackdriver Logging;如果您不使用的是,则为Elasticsearch。
原则 XII. 管理进程
12 Factor App的原则12是“将管理/管理任务作为一次性进程运行”。
该原则涉及将管理任务(如迁移数据库或检查记录)与应用程序的其余部分分开。尽管它们是分开的,但是它们仍必须在与应用程序相同的环境中运行,并且在与应用程序相同的基本代码和配置下运行,并且它们的代码必须与应用程序一起提供,以防止漂移。
您可以在基于Kubernetes的应用程序中以多种不同方式实现此功能,具体取决于应用程序本身的大小和规模。例如,对于小型任务,您可以使用kubectl exec在特定的容器上进行操作,也可以使用Kubernetes作业来运行独立的应用程序。但是,对于涉及变更编排的更复杂的任务,您还可以使用Kubernetes Helm。
您在实际开发中遵守多少这些因素?
除非您仍在构建桌面应用程序,否则您很有可能会遇到至少一些十二要素应用程序的基本原则。但是,您可能还会发现至少一两个可能会更加努力地工作。