提供:ZStack云计算
系列教程
本教程为CoreOS上手指南系列九篇中的第三篇。
内容介绍
CoreOS为我们提供了一套跨越多服务器环境的Docker容器管理平台,而其中的fleet服务则能够显著简化整套集群的管理难度。
Fleet允许用户将Docker容器作为服务对整体集群进行管理。它既作为接口存在,同时亦作为各集群成员中systemd init系统的抽象层。用户可以设定约束条件,从而对服务的运行方式加以限定。通过这种方式,管理员能够要求特定应用程序运行在同一或者不同主机之上,并以此实现基础设施调整。
在今天的教程中,我们将了解fleet并学习利用fleetctl工具控制该守护进程。
先决条件
要完成本篇教程,大家首先需要拥有一套可用CoreOS集群。
在之前的系列教程如何利用DigitalOcean创建一套CoreOS集群当中,我们已经完成了集群创建工作。
此集群配置包含三个节点。它们能够利用专有网络接口实现彼此通信。这三台节点亦拥有公共接口以运行公共服务。各节点名称分别为:
- coreos-1
- coreos-2
- coreos-3
在集群准备就绪后,下面继续这场fleet之旅。
处理服务单元文件
在探讨fleetctl工具之前,我们应当首先聊聊服务单元文件。
单元文件由systemd init系统用于描述每项可用服务,定义对其进行管理的必要命令并设定服务启动时确保系统处于正常状态的各关联性信息。其中fleet守护进程构建在systemd基础之上,从而立足于集群层面进行服务管理。有鉴于此,它使用的systemd单元文件与标准版本略有不同。
为了进一步了解fleet单元文件,请参阅深度解析一文。在今天的教程内,我们只会对这些文件的格式进行概述。我们还会提供一个示例单元文件以帮助大家了解fleetctl。
Fleet单元文件各区段解析
大多数单元文件都包含以下几个基础区段:
- Unit: 此区段用于提供与该单元相关的普通信息,且与单元的“type”无关。其中包括元数据信息及关联性信息。其在fleet中主要用于提供描述并指定该单元如何与其它其它服务单元对接。
- Unit Type Section: fleet守护进程能够容纳多种不同单元类型,包括:
- Service
- Socket
- Device
- Mount
- Automount
- Timer
- Path
如果该类型已经拥有特定选项,则允许其中包含一个与类型相关的区段。Service区段类型最为常见,其用于定义特定类型的属性。对于Service单元而言,这些属性通常包括定义命令的启动与停止,或者以前置及后置方式启动或停止命令。
- X-Fleet: 此区段用于提供特定fleet配置选项。具体来讲,这意味着大家可以指定某项服务必须或者绝不可以特定方式进行调度,具体条件包括设备ID、当前正在运行的服务以及元数据信息等等。
单元文件的一般格式如下:
[Unit]Generic_option_1Generic_option_2[Service]Service_specific_option_1Service_specific_option_2[X-Fleet]Fleet_option_1Fleet_option_2
服务单元文件示例
要开始本篇教程,我们需要首先获取单元文件。大家可通过CoreOS快速上手页面中获取。在任一CoreOS设备中输入:
vim hello.service
而后,输入我们的示例服务文件:
[Unit]Description=My ServiceAfter=docker.service[Service]TimeoutStartSec=0ExecStartPre=-/usr/bin/docker kill helloExecStartPre=-/usr/bin/docker rm helloExecStartPre=/usr/bin/docker pull busyboxExecStart=/usr/bin/docker run --name hello busybox /bin/sh -c "while true; do echo Hello World; sleep 1; done"ExecStop=/usr/bin/docker stop hello
下面来看其具体作用。
在[Unit]区段设定一条描述,意味着我们告知systemd此服务只能在docker.service单元启动之后开始运行。这是因为我们的单元需要配合Docker才能正常起效。
而在[Service]区段,我们禁用启动超时,而后设置一系列操作以完成服务启动前需要首先运行的组件。其中ExecStartPre会在主ExecStart操作之前执行。如果其由=-调用,则表明无论其是否成功启动皆不会对服务本身造成影响。这一点非常重要,因为我们的预启动操作基本上清除了任何先前正在运行的服务。如果找不到已经在运行的服务,则操作自然会失败——但由于其仅仅属于清理流程,因此我们不希望其影响到服务的正常执行。
最后的pre-start区段负责提取运行命令所需要的基础busybox镜像。由于这项操作具有 必要性,因此我们不可使用=-语法。接下来,我们利用该镜像启动一套容器,并以初始循环每秒输出一次“Hello World”。其停止操作则会直接关闭此容器。
如果大家希望了解更多与fleet文件开发相关的知识,请查阅我们的fleet单元文件指南。
基本设备管理命令
先来介绍fleetctl工具。作为一款集群管理工具,fleetctl将成为我们管理设备集群的主要接口。其中大部分语法都直接照搬自systemctl——systemd的管理工具。
作为第一步,我们利用以下命令获取一份集群成员清单:
fleetctl list-machines
MACHINE IP METADATA
14ffe4c3... 10.132.249.212 -
1af37f7c... 10.132.249.206 -
9e389e93... 10.132.248.177 -
如大家所见,每台可用设备都被罗列了出来。其中每个成员在启动时都使用cloud-config文件对自身进行引导,生成一个惟一设备ID并借此区分各个节点。这部分信息被写入至/etc/machine-id文件当中。
在默认情况下,fleet会使用设备的公共IPv4地址实现不同成员间的通信。不过在我们的cloud-config文件当中,也可以要求fleet使用专有接口进行通信。以上输出结果正是这些IP地址。
其中“METADATA”一列目前还是空白,我们可以在cloud-config文件内的元数据属性中为其添加任意键-值对。如下所示:
#cloud-config
. . .
coreos:
fleet:
public-ip: $private_ipv4
metadata: region=europe,public_ip=$public_ipv4
如果大家在cloud-config文件中这样设置以引导全部设备,则输出结果应如下所示:
MACHINE IP METADATA
14ffe4c3... 10.132.249.212 public_ip=104.131.36.200,region=europe
1af37f7c... 10.132.249.206 public_ip=104.131.15.192,region=europe
9e389e93... 10.132.248.177 public_ip=104.131.15.192,region=europe
这部分额外数据可在管理工作当中用于快速从节点中提取信息,但其同时亦可在服务定义中用于指向特定主机。
为了接入集群中的特定设备,大家可以使用fleetctl ssh命令。如此一来,我们就能够根据设备ID或者与给定单元名称相对应的设备识别所接入的设备身份。
举例来说,如果大家拥有一个名为nginx.service的运行中单元,则可通过以下命令直接接入运行该服务的对应主机:
fleetctl ssh nginx
运行后,我们会直接进入对应主机中的shell会话。大家也可以在远程主机上运行单一命令,具体方式与运行普通ssh可执行文件一样。举例来说,要从/etc/environment文件(基于cloud-config参数以及可用网络接口)当中获取CoreOS设定的COREOS_PRIVATE_IPV4与COREOS_PUBLIC_IPV4两条变量,大家可以使用以下命令:
fleetctl ssh nginx cat /etc/environment
COREOS_PRIVATE_IPV4=10.132.249.212
COREOS_PUBLIC_IPV4=104.131.29.80
服务管理
在其它可用于fleetctl的命令中,大部分与服务管理相关。
启动一项服务
启动一项服务需要涉及多个步骤。该服务文件必须被载入至fleet当中,从而保证其感知到目标单元。接下来,其需要被调度至集群中的特定设备之上,最后才能完成启动。每个步骤都需要使用fleetctl命令,而这些命令分别负责执行各个阶段的对应操作。
大家只可以使用submit命令将我们的单元文件提交至fleet。通过这种方式,fleet会将该文件内容读取至内存,以备后续操作使用。
fleetctl submit hello.service
我们的hello.service文件现在已经为fleet所感知。要查看已经提交完成的单元文件,大家可以使用以下命令:
fleetctl list-unit-files
UNIT HASH DSTATE STATE TMACHINE
hello.service 0d1c468 inactive inactive -
如大家所见,该单元文件显示如上,但尚未被调度至任何主机或者实际启动。
要查看fleet已经识别出的单元文件内容,大家可以使用以下命令:
fleetctl cat hello.service
[Unit]
Description=My Service
After=docker.service
[Service]
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker kill hello
ExecStartPre=-/usr/bin/docker rm hello
ExecStartPre=/usr/bin/docker pull busybox
ExecStart=/usr/bin/docker run --name hello busybox /bin/sh -c "while true; do echo Hello World; sleep 1; done"
ExecStop=/usr/bin/docker stop hello
这样大家就能查看fleet所感知的当前文件内容了。
注意:submit命令是幂等的,就是说在进行重复提交时,fleet将不会更新内存内单元文件。如果大家需要更新自己的单元文件,则必须将其彻底移除,而后重新提交。我们将在后面具体进行讨论。
在单元提交完成后,下一步是将其调度至某台设备。在单元调度过程中,fleet引擎会检查该单元以保证其运行在最合适的集群节点之上。具体结果取决于该单元中[X-Fleet]区段的约束条件以及集群中各台设备的当前负载量。当该单元被调度完成后,其将被传递至特定设备并加入至本地systemd实例当中。
使用load命令以加载并调度该单元:
fleetctl load hello.service
Unit hello.service loaded on 14ffe4c3.../10.132.249.212
如果大家之前还没有以手动方式载入单元,则此流程会在当前目录中搜索合适的文件名称并进行自动加载。
现在,如果我们检查自己的单元文件,就会发现其已经被加载完毕。我们甚至能够查看其被调度至哪台设备上:
fleetctl list-unit-files
UNIT HASH DSTATE STATE TMACHINE
hello.service 0d1c468 loaded loaded 14ffe4c3.../10.132.249.212
这也是我们第一次使用list-units命令。该命令用于显示任意运行中或者已调度的单元及其状态:
fleetctl list-units
UNIT MACHINE ACTIVE SUB
hello.service 14ffe4c3.../10.132.249.212 inactive dead
要启动一个单元,大家可以使用start命令。其会根据单元文件内的start命令定义在特定设备上启动该单元:
fleetctl start hello.service
Unit hello.service launched on 14ffe4c3.../10.132.249.212
再次检查list-unit-files:
fleetctl list-unit-files
UNIT HASH DSTATE STATE TMACHINE
hello.service 0d1c468 launched launched 14ffe4c3.../10.132.249.212
在以上输出结果中,我们可以看到该服务已经启动完成。其中DSTATE列所示为“理想状态”,而STATE则指示实际状态。如果二者相符,则意味着操作已经成功。
下面再次查看list-units:
fleetctl list-units
UNIT MACHINE ACTIVE SUB
hello.service 14ffe4c3.../10.132.249.212 active running
在这里我们可以看到与systemd状态相关的信息。其直接收集自本地守护进程,因此能够帮助我们更好地掌握本地系统获取到的服务状态。其中ACTIVE列为该单元的一般性状态,而SUB则为更为较低层级的状态。
停止一项服务
以上各条命令都拥有一条与之对应的反义命令。
举例来说,我们可以使用stop命令停止一项运行中的服务。在执行后,本地设备的systemd实例将执行单元定义中的停止指令:
fleetctl stop hello.service
Unit hello.service loaded on 14ffe4c3.../10.132.249.212
如大家所见,该服务已经恢复至已载入状态。这意味着其仍被加载至设备的systemd当中,但已经不再继续运行。我们可以通过以下命令进行确认:
fleetctl list-unit-files
UNIT HASH DSTATE STATE TMACHINE
hello.service 0d1c468 loaded loaded 14ffe4c3.../10.132.249.212
要移除该设备systemd中的单元,且同时保证其在fleet中的可用性,我们可以对该单元进行unload。如果该单元目前正处于活动状态,则会在被卸载前首先停止:
fleetctl unload hello.service
如果检查该状态,可以看到其现在已被标记为非活动状态。另外目标设备一项亦被留空:
fleetctl list-unit-files
UNIT HASH DSTATE STATE TMACHINE
hello.service 0d1c468 inactive inactive -
如果我们需要将该单元从fleet中完全移除,则可使用destroy命令。其会停止并卸载该单元,而后将其从fleet中移除:
fleetctl destroy hello.service
如果我们修改某个单元文件,则必须摧毁fleet中的现有单元,而后再重新提交/启动。
获取单元状态
大家应该已经了解到几种获取单元状态信息的方式了。
举例来说,list-units会列出全部当前被调度至某设备上的单元:
fleetctl list-units
UNIT MACHINE ACTIVE SUB
hello.service 14ffe4c3.../10.132.249.212 active running
而list-unit-files则提供一套包含_全部_fleet已知单元的清单。其还会提供理想与实际状态信息:
fleetctl list-unit-files
UNIT HASH DSTATE STATE TMACHINE
hello.service 0d1c468 launched launched 14ffe4c3.../10.132.249.212
要获取更为具体的已启动单元信息,我们还可以使用其它几条命令。其中status命令会将返回目标主机上运行中单元的systemctl状态:
fleetctl status hello.service
● hello.service - My Service
Loaded: loaded (/run/fleet/units/hello.service; linked-runtime)
Active: active (running) since Mon 2014-09-08 21:51:22 UTC; 3min 57s ago
Process: 7630 ExecStartPre=/usr/bin/docker pull busybox (code=exited, status=0/SUCCESS)
Process: 7618 ExecStartPre=/usr/bin/docker rm hello (code=exited, status=0/SUCCESS)
Process: 7609 ExecStartPre=/usr/bin/docker kill hello (code=exited, status=0/SUCCESS)
Main PID: 7638 (docker)
CGroup: /system.slice/hello.service
└─7638 /usr/bin/docker run --name hello busybox /bin/sh -c while true; do echo Hello World; sleep 1; done
Sep 08 21:55:11 coreos-3 docker[7638]: Hello World
Sep 08 21:55:12 coreos-3 docker[7638]: Hello World
Sep 08 21:55:13 coreos-3 docker[7638]: Hello World
Sep 08 21:55:14 coreos-3 docker[7638]: Hello World
Sep 08 21:55:15 coreos-3 docker[7638]: Hello World
Sep 08 21:55:16 coreos-3 docker[7638]: Hello World
Sep 08 21:55:17 coreos-3 docker[7638]: Hello World
Sep 08 21:55:18 coreos-3 docker[7638]: Hello World
Sep 08 21:55:19 coreos-3 docker[7638]: Hello World
Sep 08 21:55:20 coreos-3 docker[7638]: Hello World
如大家所见,我们最终证明示例单元的输出结果正在正常显示。
同样的,如果大家请在相关设备上查看该服务的journal条目,则可使用journal命令:
fleetctl journal hello.service
-- Logs begin at Mon 2014-09-08 14:22:14 UTC, end at Mon 2014-09-08 21:55:47 UTC. --
Sep 08 21:55:38 coreos-3 docker[7638]: Hello World
Sep 08 21:55:39 coreos-3 docker[7638]: Hello World
Sep 08 21:55:40 coreos-3 docker[7638]: Hello World
Sep 08 21:55:41 coreos-3 docker[7638]: Hello World
Sep 08 21:55:42 coreos-3 docker[7638]: Hello World
Sep 08 21:55:43 coreos-3 docker[7638]: Hello World
Sep 08 21:55:44 coreos-3 docker[7638]: Hello World
Sep 08 21:55:45 coreos-3 docker[7638]: Hello World
Sep 08 21:55:46 coreos-3 docker[7638]: Hello World
Sep 08 21:55:47 coreos-3 docker[7638]: Hello World
在默认情况下,其会显示最后十行。大家也可以通过添加–行参数对此进行调整:
fleetctl journal --lines 20 hello.service
大家也可以使用-f参数,其代表“follow”。通过添加-f参数的命令,系统会不断发回最新日志条目:
fleetctl journal -f hello.service
总结
通过学习如何使用fleet与fleetctl,大家可以轻松控制自己的CoreOS集群。我们的服务与容器亦可非常顺畅地在不同设备之间往来迁移。
在下一篇教程中,我们将更为深入地探讨how to create fleet unit files如何创建fleet单元文件。通过这种方式,大家能够创建出可充分发挥CoreOS架构优势的、灵活且强大的服务。
本文来源自DigitalOcean Community。英文原文:How To Use Fleet and Fleetctl to Manage your CoreOS Cluster By Justin Ellingwood
翻译:diradw