如何使用FleetUnit文件为CoreOS集群创建灵活的服务
状态: 已弃用
原因: 2016年12月22日,CoreOS宣布不再维护fleet; 在 2017 年 2 月之前,fleet 将收到安全更新和错误修复,届时它将从 CoreOS 中删除。 该项目建议使用 Kubernetes 来满足所有集群需求。
请参阅: 有关在没有队列的情况下在 CoreOS 上使用 Kubernetes 的指导,请参阅 CoreOS 上的 Kubernetes 文档。
介绍
CoreOS 安装利用许多工具使集群和 Docker 包含的服务易于管理。 虽然 etcd
涉及连接单独的节点并为全局数据提供一个区域,但大多数实际的服务管理和管理任务都涉及使用 fleet
守护程序。
在 上一篇指南 中,我们介绍了 fleetctl
命令用于操作服务和集群成员的基本用法。 在该指南中,我们简要介绍了fleet 用于定义服务的单元文件,但这些是用于提供工作服务以学习 fleetctl
的简化示例。
在本指南中,我们将深入探索 fleet
单元文件,以了解如何创建它们以及使您的服务在生产中更加健壮的一些技术。
先决条件
为了完成本教程,我们将假设您已按照我们的 集群指南 中的描述配置了 CoreOS 集群。 这将为您留下三个这样命名的服务器:
- coreos-1
- coreos-2
- coreos-3
尽管本教程的大部分内容将集中在单元文件的创建上,但这些机器稍后将用于演示某些指令的调度影响。
我们还将假设您已阅读我们关于 如何使用fleetctl 的指南。 您应该具备 fleetctl
的工作知识,以便您可以将这些单元文件与集群一起提交和使用。
完成这些要求后,继续阅读本指南的其余部分。
单元文件部分和类型
因为fleet
的服务管理方面主要依赖于各个本地系统的systemd
init系统,所以使用systemd
单元文件来定义服务。
虽然服务是迄今为止使用 CoreOS 配置的最常见的单元类型,但实际上还有其他可以定义的单元类型。 这些是传统 systemd
单元文件可用的子集。 这些类型中的每一个都由用作文件后缀的类型标识,例如 example.service
:
- service:这是最常见的单元文件类型。 它用于定义可以在集群中的一台机器上运行的服务或应用程序。
- socket:定义有关套接字或类套接字文件的详细信息。 其中包括网络套接字、IPC 套接字和 FIFO 缓冲区。 这些用于在文件上看到流量时调用服务以启动。
- device:定义有关 udev 设备树中可用设备的信息。 Systemd 将根据需要在各个主机上根据 udev 规则为内核设备创建这些。 这些通常用于订购问题,以确保在尝试安装之前设备可用。
- mount:定义设备的挂载点信息。 它们以它们引用的挂载点命名,斜线替换为破折号。
- automount:定义一个自动挂载点。 它们遵循与安装单元相同的命名约定,并且必须伴随相关的安装单元。 这些用于描述按需和并行安装。
- timer:定义与另一个单元关联的定时器。 当达到此文件中定义的时间点时,相关单元将启动。
- path:定义一个可以被监控的基于路径的激活的路径。 这可用于在对某个路径进行更改时启动另一个单元。
尽管这些选项都可用,但服务单元将最常使用。 在本指南中,我们将仅讨论服务单元配置。
单元文件是以点和上述后缀之一结尾的简单文本文件。 在内部,它们按部分组织。 对于 fleet
,大多数单元文件将具有以下一般格式:
[Unit] generic_unit_directive_1 generic_unit_directive_2 [Service] service_specific_directive_1 service_specific_directive_2 service_specific_directive_3 [X-Fleet] fleet_specific_directive
单元文件中的节标题和其他所有内容都区分大小写。 [Unit]
部分用于定义有关单元的通用信息。 所有单元类型通用的选项通常放置在此处。
[Service]
部分用于设置特定于服务单元的指令。 上面的大多数(但不是全部)单元类型都有与单元类型特定信息相关的部分。 查看 通用 systemd 单元文件手册页 以获取指向不同单元类型的链接以查看更多信息。
[X-Fleet]
部分用于设置与 fleet
一起使用的单元的调度要求。 使用此部分,您可以要求某些条件为真,以便将单元安排在主机上。
构建主要服务
对于本节,我们将从 在 CoreOS 上运行服务的基本指南中描述的单元文件的变体开始。 该文件名为 apache.1.service
,如下所示:
[Unit] Description=Apache web server service # Requirements Requires=etcd.service Requires=docker.service Requires=apache-discovery.1.service # Dependency ordering After=etcd.service After=docker.service Before=apache-discovery.1.service [Service] # Let processes take awhile to start up (for first run Docker containers) TimeoutStartSec=0 # Change killmode from "control-group" to "none" to let Docker remove # work correctly. KillMode=none # Get CoreOS environmental variables EnvironmentFile=/etc/environment # Pre-start and Start ## Directives with "=-" are allowed to fail without consequence ExecStartPre=-/usr/bin/docker kill apache ExecStartPre=-/usr/bin/docker rm apache ExecStartPre=/usr/bin/docker pull username/apache ExecStart=/usr/bin/docker run --name apache -p ${COREOS_PUBLIC_IPV4}:80:80 \ username/apache /usr/sbin/apache2ctl -D FOREGROUND # Stop ExecStop=/usr/bin/docker stop apache [X-Fleet] # Don't schedule on the same machine as other Apache instances X-Conflicts=apache.*.service
我们从 [Unit]
部分开始。 这里的基本思想是描述单元并放置依赖信息。 我们从一组要求开始。 我们在这个例子中使用了硬性要求。 如果我们希望 fleet
尝试启动其他服务,但不停止失败,我们可以使用 Wants
指令来代替。
之后,我们明确列出了需求的顺序。 这很重要,以便在需要时可以使用必备服务。 这也是我们自动启动我们将要构建的 sidekick etcd 宣布服务的方式。
对于 [Service]
部分,我们关闭服务启动超时。 第一次在主机上运行服务时,必须从 Docker 注册表中拉取容器,这将计入启动超时。 这默认为 90 秒,这通常是足够的时间,但对于更复杂的容器,它可能需要更长的时间。
然后我们将 killmode 设置为 none。 这是因为正常的终止模式(控制组)有时会导致容器删除命令失败(尤其是当 Docker 的 --rm
选项尝试时)。 这可能会导致下次重新启动时出现问题。
我们拉入环境文件,以便我们可以访问 COREOS_PUBLIC_IPV4
,如果在创建期间启用了私有网络,则可以访问 COREOS_PRIVATE_IPV4
环境变量。 这些对于配置 Docker 容器以使用其特定主机的信息非常有用。
ExecStartPre
行用于清除之前运行的任何剩余部分,以确保执行环境干净。 我们在其中的前两个上使用 =-
表示 systemd
应该忽略并在这些命令失败时继续。 正因为如此,Docker 会尝试杀死和删除以前的容器,但如果找不到任何容器也不会担心。 最后一次预启动用于确保正在运行最新版本的容器。
实际的启动命令会启动 Docker 容器并将其绑定到主机的公共 IPv4 接口。 这使用了环境文件中的信息,使得切换接口和端口变得很简单。 该进程在前台运行,因为如果正在运行的进程结束,容器将退出。 stop 命令尝试优雅地停止容器。
[X-Fleet]
部分包含一个简单的条件,它强制 fleet
在尚未运行另一个 Apache 服务的机器上安排服务。 这是一种通过强制重复服务在不同机器上启动来使服务高度可用的简单方法。
构建主要服务的基本要点
在上面的示例中,我们介绍了一个相当基本的配置。 但是,我们可以从中吸取很多教训,以帮助我们总体上构建服务。
构建主要服务时要记住的一些行为:
- 依赖和排序的单独逻辑:使用
Requires=
或Wants=
指令布置依赖关系,具体取决于如果无法满足依赖关系,您正在构建的单元是否应该失败。 使用单独的After=
和Before=
行分开订购,以便您在需求发生变化时轻松调整。 将依赖项列表与排序分开可以帮助您在出现依赖项问题时进行调试。 - 使用单独的进程处理服务注册:您的服务应该使用
etcd
注册,以利用服务发现和允许的动态配置功能。 然而,这应该由一个单独的“sidekick”容器处理,以保持逻辑分离。 这将使您能够从外部角度更准确地报告服务的健康状况,而这正是其他组件所需要的。 - 注意服务超时的可能性:考虑调整
TimeoutStartSec
指令以允许更长的启动时间。 将此设置为“0”将禁用启动超时。 这通常是必要的,因为有时 Docker 必须拉取映像(在首次运行或发现更新时),这可能会增加初始化服务的大量时间。 - 如果您的服务没有干净地停止,请调整 KillMode:如果您的服务或容器似乎停止不干净,请注意
KillMode
选项。 将此设置为“无”有时可以解决停止后容器未删除的问题。 这在您命名容器时尤其重要,因为如果在之前的运行中留下了同名容器,Docker 将会失败。 查看关于 KillMode 的 文档以获取更多信息 - 启动前清理环境:与上项相关,请务必在每次启动时清理之前的Docker容器。 您不应假定服务的先前运行已按预期退出。 如果不需要清理,这些清理行应使用
=-
说明符以允许它们静默失败。 虽然您应该正常停止使用docker stop
的容器,但您应该在清理期间使用docker kill
。 - 拉入并使用主机特定信息进行服务可移植性:如果您需要将服务绑定到特定的网络接口,请拉入
/etc/environment
文件以访问[X190X ] 和COREOS_PRIVATE_IPV4
(如果已配置)。 如果您需要知道运行服务的机器的主机名,请使用%H
systemd 说明符。 要了解有关可能的说明符的更多信息,请查看 systemd 说明符文档 。 在[X-Fleet]
部分中,只有%n
、%N
、%i
和%p
说明符有效。
构建 Sidekick 公告服务
现在我们对构建主要服务时要记住的内容有了一个很好的了解,我们可以开始研究传统的“sidekick”服务。 这些 Sidekick 服务与主服务相关联,并用作向 etcd
注册服务的外部点。
该文件在主单元文件中被引用,称为 apache-discovery.1.service
,如下所示:
[Unit] Description=Apache web server etcd registration # Requirements Requires=etcd.service Requires=apache.1.service # Dependency ordering and binding After=etcd.service After=apache.1.service BindsTo=apache.1.service [Service] # Get CoreOS environmental variables EnvironmentFile=/etc/environment # Start ## Test whether service is accessible and then register useful information ExecStart=/bin/bash -c '\ while true; do \ curl -f ${COREOS_PUBLIC_IPV4}:80; \ if [ $? -eq 0 ]; then \ etcdctl set /services/apache/${COREOS_PUBLIC_IPV4} \'{"host": "%H", "ipv4_addr": ${COREOS_PUBLIC_IPV4}, "port": 80}\' --ttl 30; \ else \ etcdctl rm /services/apache/${COREOS_PUBLIC_IPV4}; \ fi; \ sleep 20; \ done' # Stop ExecStop=/usr/bin/etcdctl rm /services/apache/${COREOS_PUBLIC_IPV4} [X-Fleet] # Schedule on the same machine as the associated Apache service X-ConditionMachineOf=apache.1.service
我们启动 sidekick 服务的方式与我们启动主要服务的方式大致相同。 在讨论依赖信息和排序逻辑之前,我们描述了该单元的用途。
这里的第一个新项目是 BindsTo=
指令。 该指令使该单元遵循发送到所列单元的启动、停止和重新启动命令。 基本上,这意味着一旦将这两个单元加载到 fleet
中,我们就可以通过操纵主单元来管理这两个单元。 这是一种单向机制,因此控制 Sidekick 不会影响主机。
对于 [Service]
部分,我们再次获取 /etc/environment
文件,因为我们需要它保存的变量。 此实例中的 ExecStart=
指令基本上是一个简短的 bash
脚本。 它尝试使用公开的接口和端口连接到主要服务。
如果连接成功,则使用etcdctl
命令在etcd
中的/services/apache
中设置主机公网IP地址的密钥。 this 的值是一个 JSON 对象,其中包含有关服务的信息。 密钥设置为在 30 秒后过期,因此如果此设备意外停机,etcd
中不会留下陈旧的服务信息。 如果连接失败,由于无法验证服务是否可用,因此会立即删除密钥。
这个循环包括一个 20 秒的睡眠命令。 这意味着每 20 秒(在 30 秒 etcd
键超时之前),本机重新检查主机是否可用并重置键。 这基本上刷新了密钥上的 TTL,使其在 30 秒内被视为有效。
在这种情况下,停止命令只会导致手动删除密钥。 由于 BindsTo=
指令,当主机的停止命令镜像到本机时,这将导致服务注册被删除。
对于 [X-Fleet]
部分,我们需要确保该单元与主单元在同一台服务器上启动。 虽然这不允许该单元报告远程机器的服务可用性,但重要的是 BindsTo=
指令正常运行。
构建 Sidekick 服务的基本要点
在构建这个伙伴时,我们可以看到一些我们应该记住的事情,作为这些类型单位的一般规则:
- 检查主机的实际可用性:实际检查主机的状态很重要。 不要仅仅因为 Sidekick 已经初始化就认为主机可用。 这取决于主要单元的设计和功能是什么,但是您的检查越稳健,您的注册状态就越可信。 检查可以是对单元有意义的任何内容,从检查
/health
端点到尝试使用客户端连接到数据库。 - 循环注册逻辑以定期重新检查:在启动时检查服务的可用性很重要,但定期重新检查也很重要。 这可以捕获意外服务故障的实例,尤其是当它们以某种方式导致容器不停止时。 通过权衡快速发现的重要性与主机上的额外负载,必须根据您的需要调整周期之间的暂停。
- 向 etcd 注册时使用 TTL 标志以在失败时自动注销 :sidekick 单元的意外故障可能导致
etcd
中的发现信息过时。 为避免您的服务的注册状态和实际状态之间发生冲突,您应该让您的密钥超时。 使用上面的循环结构,您可以在超时间隔之前刷新每个键,以确保在 Sidekick 运行时该键实际上永远不会过期。 循环中的睡眠间隔应设置为略小于超时间隔,以确保此功能正常运行。 - 向 etcd 注册有用的信息,而不仅仅是确认:在您第一次迭代 Sidekick 期间,您可能只对在单元启动时准确地注册到
etcd
感兴趣。 但是,这是为其他服务提供大量有用信息以供使用的错失良机。 虽然您现在可能不需要此信息,但当您构建其他能够从etcd
读取值以用于自己的配置的组件时,它将变得更加有用。etcd
服务是一个全局键值存储,所以不要忘记通过提供键信息来利用它。 在 JSON 对象中存储详细信息是传递多条信息的好方法。
通过牢记这些注意事项,您可以开始构建强大的注册单元,该单元将能够智能地确保 etcd
具有正确的信息。
特定于机队的注意事项
虽然 fleet
单元文件在很大程度上与传统的 systemd
单元文件没有什么不同,但还有一些额外的功能和缺陷。
最明显的区别是添加了一个名为 [X-Fleet]
的部分,可用于指导 fleet
如何做出调度决策。 可用的选项有:
- X-ConditionMachineID:这可用于指定要加载单元的确切机器。 提供的值是完整的机器 ID。 可以通过检查
/etc/machine-id
文件或通过fleetctl
通过发出list-machines -l
命令从集群的单个成员检索此值。 需要完整的 ID 字符串。 如果您正在运行数据目录保存在特定机器上的数据库,则可能需要这样做。 除非您有特定的理由使用它,否则请尽量避免使用它,因为它会降低单元的灵活性。 - X-ConditionMachineOf:此指令可用于在加载指定单元的同一台机器上调度此单元。 这对于辅助单位或将相关单位集中在一起很有帮助。
- X-Conflicts:这与上面的声明相反,因为它指定了这个单元不能被安排在一起的单元文件。 这对于通过启动同一服务的多个版本(每个版本都在不同的机器上)来轻松配置高可用性很有用。
- X-ConditionMachineMetadata:用于根据可用机器的元数据指定调度要求。 在
fleetctl list-machines
输出的“METADATA”列中,您可以看到已为每个主机设置的元数据。 要设置元数据,请在初始化服务器实例时将其传递到您的cloud-config
文件中。 - Global:这是一个特殊的指令,它接受一个布尔参数,指示是否应该在集群中的所有机器上安排它。 只有元数据条件可以与该指令一起使用。
这些附加指令在定义服务应如何在可用机器上运行时给予管理员更大的灵活性和权力。 在 fleetctl load
阶段将它们传递给特定机器的 systemd
实例之前对它们进行评估。
这给我们带来了在 fleet
中使用相关单元时需要注意的下一个问题。 fleetctl
实用程序不会评估单元文件的 [X-Fleet]
部分之外的依赖性要求。 当在 fleet
中使用伴随单元时,这会导致一些有趣的问题。
这意味着,虽然 fleetctl
工具将采取必要的步骤使目标单元进入所需的状态,根据给定的命令根据需要逐步完成提交、加载和启动过程,但它不会做这对于单元的依赖关系。
因此,如果您同时提交了主单元和辅助单元,但未加载,则在 fleet
中,键入 fleetctl start main.service
将加载然后尝试启动 main.service
单元。 但是,由于 sidekick.service
单元尚未加载,并且由于 fleetctl
不会评估依赖信息以使依赖单元通过加载和启动过程,因此 main.service
单元将失败。 这是因为一旦机器的 systemd
实例处理了 main.service
单元,当 it 评估依赖关系时,它将无法找到 sidekick.service
。 sidekick.service
单元从未加载到机器上。
为避免在处理伴随单元时出现这种情况,您可以同时手动启动服务,而不是依赖 BindsTo=
指令将 Sidekick 置于运行状态:
fleetctl start main.service sidekick.service
另一种选择是确保在主单元运行时至少加载 Sidekick 单元。 加载阶段是选择一台机器并将单元文件提交到本地 systemd
实例。 这将确保满足依赖关系并且 BindsTo=
指令将能够正确执行以启动第二个单元:
fleetctl load main.service sidekick.service fleetctl start main.service
如果您的相关单元没有正确响应您的 fleetctl
命令,请记住这一点。
实例和模板
使用 fleet
时最强大的概念之一是单元模板。
单元模板依赖于 systemd
称为“实例”的功能。 这些是在运行时通过处理模板单元文件创建的实例化单元。 模板文件在很大程度上与常规单元文件非常相似,只是做了一些小的修改。 但是,如果正确使用,这些功能非常强大。
模板文件可以通过文件名中的 @
来识别。 虽然传统服务采用这种形式:
unit.service
模板文件可能如下所示:
unit@.service
当一个单元从模板实例化时,它的实例标识符放在 @
和 .service
后缀之间。 此标识符是管理员选择的唯一字符串:
unit@instance_id.service
基本单元名称可以通过 %p
说明符从单元文件中访问。 类似地,可以使用 %i
访问给定的实例标识符。
主机文件作为模板
这意味着您可以创建一个名为 apache@.service
的模板,而不是使用我们之前看到的内容创建名为 apache.1.service
的主单元文件:
[Unit] Description=Apache web server service on port %i # Requirements Requires=etcd.service Requires=docker.service Requires=apache-discovery@%i.service # Dependency ordering After=etcd.service After=docker.service Before=apache-discovery@%i.service [Service] # Let processes take awhile to start up (for first run Docker containers) TimeoutStartSec=0 # Change killmode from "control-group" to "none" to let Docker remove # work correctly. KillMode=none # Get CoreOS environmental variables EnvironmentFile=/etc/environment # Pre-start and Start ## Directives with "=-" are allowed to fail without consequence ExecStartPre=-/usr/bin/docker kill apache.%i ExecStartPre=-/usr/bin/docker rm apache.%i ExecStartPre=/usr/bin/docker pull username/apache ExecStart=/usr/bin/docker run --name apache.%i -p ${COREOS_PUBLIC_IPV4}:%i:80 \ username/apache /usr/sbin/apache2ctl -D FOREGROUND # Stop ExecStop=/usr/bin/docker stop apache.%i [X-Fleet] # Don't schedule on the same machine as other Apache instances X-Conflicts=apache@*.service
如您所见,我们已将 apache-discovery.1.service
依赖项修改为 apache-discovery@%i.service
。 这意味着如果我们有一个名为 apache@8888.service
的单元文件的实例,这将需要一个名为 apache-discovery@8888.service
的 Sidekick。 %i
已替换为实例标识符。 在这种情况下,我们使用标识符来保存有关我们服务运行方式的动态信息,特别是 Apache 服务器可用的端口。
为了使这项工作正常进行,我们正在更改 docker run
参数,该参数将容器的端口公开到主机上的端口。 在静态单元文件中,我们使用的参数是${COREOS_PUBLIC_IPV4}:80:80
,将容器的80端口映射到公共IPv4接口上主机的80端口。 在此模板文件中,我们将其替换为 ${COREOS_PUBLIC_IPV4}:%i:80
,因为我们使用实例标识符来告诉我们要使用哪个端口。 实例标识符的明智选择可能意味着您的模板文件具有更大的灵活性。
Docker 名称本身也已修改,因此它也使用基于实例 ID 的唯一容器名称。 请记住,Docker 容器不能使用 @
符号,因此我们必须从单元文件中选择不同的名称。 我们修改了在 Docker 容器上运行的所有指令。
在 [X-Fleet]
部分中,我们还修改了调度信息以识别这些实例化单元,而不是我们之前使用的静态类型。
作为模板的 Sidekick 单元
我们可以通过类似的过程来调整我们的伙伴单元以进行模板化。
我们的新伙伴单元将被称为 apache-discovery@.service
,看起来像这样:
[Unit] Description=Apache web server on port %i etcd registration # Requirements Requires=etcd.service Requires=apache@%i.service # Dependency ordering and binding After=etcd.service After=apache@%i.service BindsTo=apache@%i.service [Service] # Get CoreOS environmental variables EnvironmentFile=/etc/environment # Start ## Test whether service is accessible and then register useful information ExecStart=/bin/bash -c '\ while true; do \ curl -f ${COREOS_PUBLIC_IPV4}:%i; \ if [ $? -eq 0 ]; then \ etcdctl set /services/apache/${COREOS_PUBLIC_IPV4} \'{"host": "%H", "ipv4_addr": ${COREOS_PUBLIC_IPV4}, "port": %i}\' --ttl 30; \ else \ etcdctl rm /services/apache/${COREOS_PUBLIC_IPV4}; \ fi; \ sleep 20; \ done' # Stop ExecStop=/usr/bin/etcdctl rm /services/apache/${COREOS_PUBLIC_IPV4} [X-Fleet] # Schedule on the same machine as the associated Apache service X-ConditionMachineOf=apache@%i.service
我们已经完成了要求和绑定到主单元进程的实例化版本而不是静态版本的相同步骤。 这将使实例化的 sidekick 单元与正确的实例化主单元匹配。
在 curl
命令期间,当我们检查服务的实际可用性时,我们将静态端口 80 替换为即时 ID,以便它连接到正确的位置。 这是必要的,因为我们在 Docker 命令中为我们的主机更改了端口暴露映射。
我们还将记录的“端口”修改为 etcd
,以便它使用相同的实例 ID。 通过此更改,在 etcd
中设置的 JSON 数据是完全动态的。 它将获取主机名、IP 地址和正在运行服务的端口。
最后,我们再次更改 [X-Fleet]
部分中的条件。 我们需要确保这个过程与主单元实例在同一台机器上启动。
从模板实例化单元
要从模板文件实际实例化单元,您有几个不同的选项。
fleet
和 systemd
都可以处理符号链接,这使我们可以选择使用模板文件的完整实例 ID 创建链接,如下所示:
ln -s apache@.service apache@8888.service ln -s apache-discovery@.service apache-discovery@8888.service
这将创建两个链接,称为 apache@8888.service
和 apache-discovery@8888.service
。 它们中的每一个都具有 fleet
和 systemd
现在运行这些单元所需的所有信息。 但是,它们被指向模板,以便我们可以在一个地方进行所需的任何更改。
然后我们可以使用 fleetctl
提交、加载或启动这些服务,如下所示:
fleetctl start apache@8888.service apache-discovery@8888.service
如果您不想创建符号链接来定义您的实例,另一种选择是将模板本身提交到 fleetctl
,如下所示:
fleetctl submit apache@.service apache-discovery@.service
您可以直接在 fleetctl
中从这些模板中实例化单元,只需在运行时分配实例标识符即可。 例如,您可以通过键入以下命令运行相同的服务:
fleetctl start apache@8888.service apache-discovery@8888.service
这消除了对符号链接的需要。 一些管理员更喜欢链接机制,因为这意味着您可以随时使用实例文件。 它还允许您将目录传递给 fleetctl
,以便立即启动所有内容。
例如,在您的工作目录中,您的模板文件可能有一个名为 templates
的子目录,而实例化链接版本可能有一个名为 instances
的子目录。 您甚至可以为非模板单元设置一个名为 static
的单元。 你可以这样做:
mkdir templates instances static
然后,您可以将静态文件移动到 static
并将模板文件移动到 templates
:
mv apache.1.service apache-discovery.1.service static mv apache@.service apache-discovery@.service templates
从这里,您可以创建所需的实例链接。 让我们在端口 5555
、6666
和 7777
上运行我们的服务:
cd instances ln -s ../templates/apache@.service apache@5555.service ln -s ../templates/apache@.service apache@6666.service ln -s ../templates/apache@.service apache@7777.service ln -s ../templates/apache-discovery@.service apache-discovery@5555.service ln -s ../templates/apache-discovery@.service apache-discovery@6666.service ln -s ../templates/apache-discovery@.service apache-discovery@7777.service
然后,您可以通过键入以下内容一次启动所有实例:
cd .. fleetctl start instances/*
这对于快速启动您的服务非常有用。
结论
至此,您应该对如何为 fleet
构建单元文件有了相当的了解。 通过利用单元文件中可用的一些动态特性,您可以确保您的服务均匀分布,接近它们的依赖关系,并使用 etcd
注册有用的信息。
在 稍后的指南 中,我们将介绍如何配置您的容器以使用您在 etcd
中注册的信息。 这可以帮助您的服务建立实际部署环境的工作知识,以便将请求传递到后端的适当容器。