CoreOS实践指南(三):系统服务管家Systemd

【编者按】作为一个操作系统,CoreOS 采用了高度精简的系统内核及外围定制,将许多原本需要复杂人工操作或者第三方软件支持的功能在操作系统级别进行了实现,同时剔除了其他对于服务器系统非核心的软件,比如GUI和包管理器。来自ThoughtWorks的软件工程师林帆将带来“漫步云端:CoreOS实践指南”系列文章,带大家了解CoreOS的精华和推荐的实践方法。本文为基础第三篇:系统服务管家Systemd。

作者简介:

林帆,生在80后尾巴的IT攻城狮,ThoughtWorks成都办公室CloudOps小组成员,平时喜欢在业余时间研究DevOps相关的应用,目前在备考AWS认证和推广Docker相关技术。

在系列教程的第一篇里我们已经提到了Systemd,它主要的设计目标是克服传统Linux主流启动程序SysVinit 固有的缺点,提高系统的启动速度。相比同类的 SysVinit 竞争者,例如Ubuntu 的 upstart,Systemd 的设计更加前卫,简单来说,它的设计思路借鉴了Mac系统的启动程序Launchd。事实上Systemd的作用远不仅是启动系统,它还接管了系统服务的启动、结束、状态查询和日志归档等职责,并支持定时任务和通过特定事件(如插入特定USB设备)和特定端口数据触发的任务。在CoreOS的世界里,推荐的做法是使用Systemd来管理所有用户服务,包括运行在应用容器(如Docker)中的服务。

值得指出的是,Systemd并不是CoreOS特有的服务。本质上说Systemd是没有依附于任何一个Linux发行版的独立项目,由于Systemd的作者Lennart Poettering 就职于红帽,整个项目实际由RedHat公司主导。虽然RedHat Linux直到2014年中旬才用上Systemd,但RedHat旗下的Fedora早在2011年时就已经引进了Systemd作为其启动管理程序了。

在开始使用Systemd之前,先了解一下Systemd有哪些特别之处。

Systemd 的设计理念
尽可能启动更少进程

当SysVinit 程序初始化系统的时,会将所有可能用到的后台服务进程全部运行起来。然而用户需要等待系统将所有服务都启动完成之后,才能够登录。这种做法会带来两个问题:系统的启动时间过长和系统资源的浪费。

Systemd 提供了服务按需启动的能力,使得特定的服务只有在被真正请求的时候才启动。特别是具体硬件相关的服务,比如蓝牙服务仅在蓝牙适配器被插入时才需要运行,打印服务仅在打印机连接或程序要打印时才需要运行,甚至sshd服务也只需要在用户使用ssh连接到服务器时才需要启动。这种能力是建立在对Systemd对DBus总线或特定Socket端口监听的特性上的,这种设计相比于传统启动程序具有颠覆性的进步。

尽可能将更多进程并行启动

在SysVinit的时代,将每个服务项目编号的方式依次执行启动脚本。后来Ubuntu的Upstart解决了没有直接依赖的启动项之间的并行启动。而Systemd通过Socket缓存、DBus缓存和建立临时挂载点等方法进一步解决了启动进程之间的依赖,做到了所有系统服务并发启动,这一设计同样是Systemd独具特色的创意。当然,对于用户自定义的服务,Systemd允许配置其启动依赖项目,从而确保服务按必要的顺序运行,稍后会详细描述具体的使用方法。

Systemd启动模型与其它启动模型的对比

采用 Cgroup 跟踪和管理进程的生命周期

Cgroup的全称是controller group,是将任意进程进行分组化管理的Linux内核功能,最初由Google的工程师提出,从Linux内核版本2.6.24正式启用。拿Android来说,它的应用程序隔离就是使用的这种技术。而很长一段时间里,在更广阔的服务器领域,一直并没有一种主流的服务管理程序能够充分利用这种早已在手机端带来广泛好处的特性。

而Systemd正是Cgroup方面的行家,它的出现正好弥补了这个领域的缺漏。通过Cgroup,Systemd不仅实现了服务之间的访问隔离,还能够限制特定应用程序对系统资源访问配额(比如CPU的用量、内存的量),以及精确的管理服务的生命周期。在这篇文章的后面部分会讲述相关操作具体的做法。

统一管理服务日志使用Systemd 必须知道的还有它的伙伴:Journald日志服务,这个服务的设计初衷是克服现有syslog服务的日志内容易伪造和日志格式不统一等缺点,而它现在已经是Systemd的一个标准子服务了。Journald用二进制格式保存所有日志信息,用户需要使用 journalctl 命令来查看日志信息。在这篇文章的后面会介绍如何查看服务的日志。 

第一个Hello World服务Unit和Target

先介绍两个概念,Unit和Target。

Unit是Systemd管理服务的基本单元,可以认为每个服务就是一个Unit,并使用一个Unit文件定义。Unit文件中需要包含相应服务的描述、属性以及需要运行的命令。在CoreOS中服务运行的命令通常是一系列的容器操作,而将具体的服务进程封装在容器中。

Target是Systemd中用于指定服务启动组的方式(相当于SysVinit中的“运行级别”,如果不清楚这个概念也没有关系,搜索“Linux运行级别”可以查到很多相关文章)。每次系统启动的时候都会运行与当前系统相同级别Target关联的所有服务,如果服务不需要跟随系统自动启动,则完全可以忽略这个Target的内容。通常来说我们大多数的Linux用户平时使用的都是“多用户模式”这个级别,对应的Target值为“multi-user.target”。

Hello World服务的Unit文件

只说不做假把式,现在我们来用Systemd创建一个简单的系统服务。

在这个系列的上一节内容里,我们创建了一个由3个CoreOS虚拟机节点组成的集群,在这节中,我们只需要使用到其中的任意一个,比如coreo-01节点。首先使用ssh连接进入这个节点(这种方法适用于Linux/Mac用户,对于Windows用户需使用Putty客户端, 具体参考)。

vagrant ssh core-01

登录成功后提示符变成 “core@core-01 ~ $” ,祝贺你又向CoreOS迈出了重要一步,接下来就可以开始在CoreOS里面玩耍了。

Systemd约定,服务的Unit文件需放置在 /etc/systemd/system 或  /usr/lib/systemd/system 目录中,但由于在CoreOS的后一个目录是只读分区(整个/usr目录挂载的都是只读的系统分区),因此我们通常会将用户定义的Unit服务文件放在在/etc/systemd/system目录中。进入这个目录,新建一个叫“hello.service”的文件,内容入下。

[Unit] 

Description=Hello World 

After=docker.service 

Requires=docker.service 

[Service] 

TimeoutStartSec=0 

ExecStartPre=-/usr/bin/docker kill busybox1 

ExecStartPre=-/usr/bin/docker rm busybox1 

ExecStartPre=/usr/bin/docker pull busybox 

ExecStart=/usr/bin/docker run --name busybox1 busybox /bin/sh -c "while true; do echo Hello World; sleep 1; done" 

ExecStop=”/usr/bin/docker kill busybox1” 

[Install] 

WantedBy=multi-user.target

在这个Unit文件里,我们首先为这个服务提供了一行简短的描述,然后指明它需要依赖docker的服务,并且要在docker服务运行以后才能运行。整个Unit文件是用的ini文件风格的分组配置格式,最开始的这段配置被放在了Unit组里面。在接下来的Service组中,使用ExecStart和ExecStop属性分别指定了服务运行时和结束时需要执行的命令。最后在Install组的配置中,我们指定了服务所属的Target为multi-user.target。

这里需要注意两个地方,首先ExecStart属性只能包含一条主要命令,而在这个属性的前后可以分别使用ExecStartPre和ExecStartPost指定更多的辅助命令,ExecStop同理。有些辅助命令会加上一个减号,表示忽略这些命令的出错(因为有些“辅助”命令本来就不一定成功,比如尝试清空一个文件,但文件可能不存在)。其次TimeoutStartSec=0这行的目的是将Systemd的服务启动超时检查关闭,对于docker应用这样做是必须的,因为docker在运行时可能会需要下载或更新镜像文件,使得服务启动时间变得很长,这样可以防止Systemd认为服务启动失败而将进程误杀。 

启动服务

有了Unit文件,现在就可以启动Hello World服务了,在控制台输入以下命令:

sudo systemctl start hello.service

Tip:这个名字末尾的 .service 后缀是可以省略的,因为systemctl默认的后缀就是 .service。关于Unit文件后缀的含义,会在后续进阶篇的文章里详细说明。

Systemd会自动找到 /usr/lib/systemd/system 目录中的 hello.service 文件,并启动其中定义的服务。如果之前创建的Unit文件是放在其他目录下的,这里需要使用文件的完整路径。首次运行的时候需要等待一段时间,因为docker需要从网络上下载需要的镜像。启动完成后可以通过“systemctl list-units”命令查看服务是否已经在运行(这个命令接受一个可选参数作为服务名的过滤条件,如果不带任何参数则输出所有服务)。

core@core-01 ~ $ sudo systemctl list-units hello* 

UNIT  LOAD  ACTIVE  SUB  DESCRIPTION 

hello.service  loaded  active  running  Hello World

我们还可以通过“systemctl enable”命令来将服务指定为在系统启动时自动启动。

sudo systemctl enable hello.service

此时就用到了之前定义的Target组,实际上enable操作只是创建了一个连接文件到指定的Target组的目录下面。通过下面命令可以证实。

core@core-01 ~ $ ls -l /etc/systemd/system/multi-user.target.wants/hello.service 

/etc/systemd/system/multi-user.target.wants/hello.service -> /etc/systemd/system/hello.service系统启动时,会自动运行其所在Target级别相应的目录里所有链接的服务。 

日志管理

至此,我们的第一个服务已经在后台哈皮的玩耍了,可是说好的“echo Hello World”呢?我们从头到尾都没有见到服务的任何输出啊。

其实我们启动的服务已经在后台默默的输出“Hello World”了。

Systemd通过其标准日志服务Journald将其管理的所有后台进程打印到到std:out(即控制台)的输出重定向到了日志文件。日志文件是二进制格式的,因此必须使用特定的工具才能查看。Journald提供了配套的程序Journalctl用于处理日志内容。Journalctl的使用非常简单,默认不带任何参数的时候会输出系统和所有后台进程的混合日志,常用的参数有--dmesg用于查看内核输出的日志,--system用于查看系统输出的日志,--unit加上Unit的名字来指定输出特定Unit的日志,例如以下命令。

journalctl --unit hello.service其他还有一些比较实用的参数,比如使用 --follow 实时跟踪日志输出,使用 --since 和 --until 指定显示的日志时间区间等,可以通过 journalctl --help 命令获得完整的参数说明。

时间: 2024-08-02 15:35:35

CoreOS实践指南(三):系统服务管家Systemd的相关文章

CoreOS实践指南(八):Unit文件详解

注:本文首发于CSDN,转载请标明出处. [编者按]在"漫步云端:CoreOS实践指南"系列的前几篇文章中,ThoughtWorks的软件工程师林帆主要介绍了CoreOS及其相关组件和使用,其中已经提到了使用 Unit 文件配置 Systemd 管理的系统服务的方式,本文将详细讲解 Unit 文件具体的格式和可用的参数. 作者简介: 林帆,生在80后尾巴的IT攻城狮,ThoughtWorks成都办公室CloudOps小组成员,平时喜欢在业余时间研究DevOps相关的应用,目前在备考AW

CoreOS实践指南(七):Docker容器管理服务

注:本文首发于CSDN,转载请标明出处. [编者按]在"漫步云端:CoreOS实践指南"系列的前几篇文章中,ThoughtWorks的软件工程师林帆主要介绍了CoreOS及其相关组件和使用.说到CoreOS,不得不提Docker.当Docker还名不见经传的时候,CoreOS创始人Alex就凭着敏锐直觉,预见了这个项目的价值,将Docker做为了这个系统支持的第一套应用程序隔离方案.本文将主要介绍在具体的场景下,如何在CoreOS中恰当的管理Docker容器. 作者简介: 林帆,生在8

漫步云端:CoreOS实践指南(一)

[编者按]Docker和CoreOS都是硅谷创业孵化器的优秀"毕业生",据说两家老板的私交很好,Docker做容器引擎,CoreOS做容器管理,合作得非常愉快,只是随着Rocket的发布逐步"分道扬镳".虽然Docker和CoreOS都在求"简",但是Docker的"简"是力求用户能达到最简便地使用,CoreOS的"简"是追求极致的轻量化,究竟哪个将是Container技术的未来,其实也很难说.今天开始,来

CoreOS实践指南(六):分布式数据存储Etcd(下)

注:本文首发于CSDN,转载请标明出处. [编者按]在"漫步云端:CoreOS实践指南"系列第五篇: 分布式数据存储Etcd(上)中,ThoughtWorks的软件工程师林帆从系统运维工作者的角度介绍了Etcd的操作和API的使用.本文为分布式数据存储Etcd的下篇.Etcd是CoreOS生态系统中处于连接各个节点通信和支撑集群服务协同运作的核心地位的模块,这篇文章将主要介绍Etcd的RESTful API.如果说Etcd数据存储服务是CoreOS分布式架构的基石,那么Etcd的RES

深入浅出CoreOS(三):Systemd和Fleet

本文讲的是深入浅出CoreOS(三):Systemd和Fleet,[编者的话]Systemd并不是CoreOS特有的服务.本质上说Systemd是没有依附于任何一个Linux发行版的独立项目,但是很多发行版Linux都在青睐Systemd管理服务的优势,所以CoreOS选择了它.Fleet是管理CoreOS和部署app的工具.有了Fleet,你就可以把整个CoreOS集群当做一台节点来处理.让我们一起学习关于此方面的内容. 这是深入浅出CoreOS系列文章中的第三篇,也是最后一篇. 在上一篇文章

《面向对象设计实践指南:Ruby语言描述》目录—导读

内容提要 面向对象设计实践指南:Ruby语言描述 本书是对"如何编写更易维护.更易管理.更讨人喜爱且功能更为强大的Ruby应用程序"的全面指导.为帮助读者解决Ruby代码难以更改和不易扩展的问题,作者在书中运用了多种功能强大和实用的面向对象设计技术,并借助大量简单实用的Ruby示例对这些技术进行全面解释. 全书共9章,主要包含的内容有:如何使用面向对象编程技术编写更易于维护和扩展的Ruby代码,单个Ruby类所应包含的内容,避免将应该保持独立的对象交织在一起,在多个对象之间定义灵活的接

《术以载道——软件过程改进实践指南》目录—导读

内容提要 术以载道--软件过程改进实践指南 软件过程改进(Software Process Improvement,SPI)是指帮助软件企业建立过程管理.识别改进点.持续优化过程体系.CMMI表示Capabi lity Maturity Mode Integration(能力成热度集成模型),提供了一个指导企业实施过程改进的框架,CMMI是实现过程改进标的一种有效手段和方法. 本书是作者软件工程经验.过程改进经验与CMMI咨询经验的总结,从实践者的角度出发,涉及到了实施CMMI的方方面面,包括C

《数据整理实践指南》一第2章 是我的问题还是数据的问题

第2章 是我的问题还是数据的问题 数据整理实践指南 Kevin Fink 假设给你一份未知来源的数据集,如何确定数据是否有用呢? 这种情况并不少见,给了你一份数据集,却无法提供关于数据来源.如何收集.字段含义等方面的诸多信息.事实上,收到这样的数据可能再正常不过了.在很多情况下,收到的数据可能经过了很多人的处理和加工,和收集的原始数据已经差别甚大,确实也没有人知道这些数据是什么含义了.在本章中,我将一步步引导你如何理解数据.验证数据并最终把数据集转换成可用的信息.特别地,我将探讨洞察数据的特殊方

《面向对象设计实践指南:Ruby语言描述》—第1章 1.3节设计行为

1.3 设计行为 面向对象设计实践指南:Ruby语言描述 随着常见设计原则和模式的出现与传播,所有的OOD问题可能都已被解决.既然基础的规则都已知道,那么设计面向对象的软件还会有多难呢? 事实证明,它非常难.如果将软件理解为可定制的家具,那么原则和模式便像是木工的工具.了解软件在完成后会是什么样子,并不能让它自我构建成那个样子.应用程序之所以存在,是因为有程序员使用了这些工具.最终的结果可能是,它要么成为一个漂亮的橱柜,要么成为一张摇摇晃晃的椅子.具体是哪一种结果,则取决于程序员使用设计工具的经