systemctl和service命令之间的区别

systemd给我们提供了一套systemctl命令集,主要用于在启动时启用服务。我们还可以使用systemctl来启动、停止、重新加载、重启和检查服务的状态。
例如,我们可以使用sudo systemctl enable service_name,并且service_name将自动在启动时启动。我们还可以禁用服务,使其不在启动时启动。 servicesystemctl命令之间唯一的区别是systemctl可以用于在运行时启用服务的启动吗?我们可以在任何服务上使用systemctl吗?还有哪些其他重要的区别?

我认为你选择了错误的答案,就我个人而言。 - Evan Carroll
2个回答

service命令是一个包装脚本,允许系统管理员启动、停止和检查服务的状态,而不用太担心实际使用的init系统。在systemd引入之前,它是对/etc/init.d脚本和Upstart的initctl命令的包装,现在它也是对这两个以及systemctl的包装。

使用源代码,卢克!

它会检查Upstart:

# Operate against system upstart, not session
unset UPSTART_SESSION
if [ -r "/etc/init/${SERVICE}.conf" ] && which initctl >/dev/null \
   && initctl version 2>/dev/null | grep -q upstart \
   && initctl status ${SERVICE} 2>/dev/null 1>/dev/null
then
   # Upstart configuration exists for this job and we're running on upstart

如果那不起作用,它会寻找systemd。
if [ -d /run/systemd/system ]; then
   is_systemd=1
fi

...

# When this machine is running systemd, standard service calls are turned into
# systemctl calls.
if [ -n "$is_systemd" ]
then

如果那也失败了,它会退回到System V的/etc/init.d脚本:
run_via_sysvinit() {
   # Otherwise, use the traditional sysvinit
   if [ -x "${SERVICEDIR}/${SERVICE}" ]; then
      exec env -i LANG="$LANG" LANGUAGE="$LANGUAGE" LC_CTYPE="$LC_CTYPE" LC_NUMERIC="$LC_NUMERIC" LC_TIME="$LC_TIME" LC_COLLATE="$LC_COLLATE" LC_MONETARY="$LC_MONETARY" LC_MESSAGES="$LC_MESSAGES" LC_PAPER="$LC_PAPER" LC_NAME="$LC_NAME" LC_ADDRESS="$LC_ADDRESS" LC_TELEPHONE="$LC_TELEPHONE" LC_MEASUREMENT="$LC_MEASUREMENT" LC_IDENTIFICATION="$LC_IDENTIFICATION" LC_ALL="$LC_ALL" PATH="$PATH" TERM="$TERM" "$SERVICEDIR/$SERVICE" ${ACTION} ${OPTIONS}
   else
      echo "${SERVICE}: unrecognized service" >&2
      exit 1
   fi
}

...
run_via_sysvinit

由于service命令只是一个相当简单的包装器,与实际的初始化系统相比,它只支持有限的一部分操作。
为了在不同版本的Ubuntu上实现可移植性,用户可以可靠地使用service命令来启动、停止、重启或检查服务的状态。然而,对于更复杂的任务,可能需要直接使用实际的命令,例如initctlsystemctl/etc/init.d脚本。
此外,作为一个包装器,在某些情况下,service脚本还可能比直接等效的命令执行更多的操作。例如:
  • 它总是在一个干净的环境中执行/etc/init.d脚本。(请注意上面run_via_sysvinit函数中env命令调用。)
  • 对于Upstart系统,它将restart映射为stop/start的组合,因为如果服务尚未运行,纯粹的initctl restart会出错。
  • 在停止与systemd服务相关联的套接字时,它会停止套接字:

    case "${ACTION}" in
      restart|status)
         exec systemctl $sctl_args ${ACTION} ${UNIT}
      ;;
      start|stop)
         # 对于SysV用户来说,遵循最小惊奇原则:
         # 当运行"service foo stop"并且foo恰好是一个具有一个或多个.socket文件的服务时,我们也会停止.socket单元。
         # 需要更多控制权的用户将直接使用systemctl。
    
在服务配置文件中直接启用了新兴服务(或通过覆盖禁用),而System V脚本则通过update-rc.d命令(管理/etc/rc*目录中的符号链接)来启用或禁用,因此service命令从未参与启用或禁用引导时的服务。

1奇怪,service --status-all 命令没有显示我使用 systemctl 安装的服务。 - jjxtra

systemctl

可以实现的远不止你提到的这些,还有:

  • systemd向后兼容SysV。
  • 并行加载服务
  • 它提供按需激活服务
  • 它基于依赖关系
  • 我认为还有更多...

systemd使用单元(unit)进行工作,有不同类型的单元:目标(target),服务(service),套接字(socket)等。 目标和运行级别(runlevel)的概念相同,它们是一组单元。

您可以使用systemctl设置或获取默认系统目标。

systemctl get-default

你可以进入其他目标。
systemctl isolate multiuser.target

其他目标包括:多用户、图形化、救援、紧急、重启和关机。
正如你所说,你可以使用 systemctl 来管理服务,我还知道一些与服务管理相关的其他命令,它们包括:
# Restarts a service only if it is running.
systemctl try-restart name.service

# Reloads configuration if it's possible.
systemctl reload name.service

# try to reload but if it's not possible restarts the service
systemctl reload-or-restart name.service

你可以使用它来了解服务的状态。
systemctl status name.service

systemctl is-active name.service # running
systemctl is-enabled name.service # will be activated when booting
systemctl is-failed name.service # failed to load

您可以对服务进行屏蔽或取消屏蔽:
systemctl mask name.service
systemctl unmask name.service

当你屏蔽一个服务时,它将与/dev/null链接,因此其他服务无法手动或自动激活/启用它(你应该先取消屏蔽)。
systemctl的另一个用途是列出单元:
systemctl list-units

列出所有类型的单位,已加载并处于活动状态。
服务单位列表:
systemctl list-units --type=service

或者列出所有可用的单位,而不仅仅是已加载和激活的单位。
systemctl list-unit-files

您可以创建别名甚至控制远程机器。
systemctl --host ravexina@192.168.56.4 list-units

另一方面,服务只做它应该做的事情,管理服务,与他人的事务无关 ;)

3那是一个完美的回答,有什么事情是service可以做而systemctl不能做的吗? - luv.preet
1我不知道有什么,我觉得看一下服务手册页面会很有帮助。 - Ravexina
2有几个明显的区别。语法是其中之一。另一个是据我所知,SystemV脚本从未涉及套接字。Systemd试图处理网络相关的事务也是一个事实,并且这是经常被批评的一个方面。总体而言,systemd试图做的不仅仅是启动服务。 - Sergiy Kolodyazhnyy
1我想在这里投诉systemd隐藏了启动失败的日志信息。在没有systemd之前,使用service start命令可以让我立即看到为什么我的服务无法启动。但是有了systemd后,我必须查看四五个不同的日志才能找到问题所在。虽然如此,我的评论毫无疑问是题外话,可能会被删除。 - Ross Presser
18就我所见,这个回答似乎没有提到service命令的任何内容,难道这不是问题的一部分吗? - ilkkachu
@RossPresser,service foo statussystemctl status foo)通常会提供有用的输出信息。 - ilkkachu
@Ravexina 你说,systemd 使用单元(units)来运行服务,这意味着它将服务视为单元。那么这会对 systemd 的本质有什么不同?如果答案很长,请在问题中添加编辑并解释。 - luv.preet
@luv.preet 这超出了这个问题的范围,需要进行详细解释。不过你可以运行以下命令:systemctl --list-units -t service 选择一个服务,然后运行:systemctl cat name-of-that-service.service。将其与传统的 sys v 脚本进行比较。 - Ravexina
我个人希望能看到更多关于政治动态的内容,如果你对此有任何了解的话。这不合理,systemctl 真是太棒了。服务包装器糟透了。Upstart 已经死了。为什么还要拖延呢?我可能完全错了,也许这不是一个政治决定,但它确实让人感到可疑。 - Evan Carroll