如何在 Linux 中创建 Systemd 服务?
suiw9 2024-10-31 16:04 20 浏览 0 评论
1. 写在前面
在 Linux 中,有多种方法可以将程序作为后台服务运行,如 crontab、.bashrc 等,本文将首先介绍 systemd 基本情况,并通过二个简单的示例介绍如何编写 systemd 服务脚本,实现 Linux 服务的自启动、启动、停止和重启管理。
2. Systemd 介绍
2.1 什么是 Systemd?
systemd 是 Linux 系统的一组基本构建块。于 2010 年首次推出,用于取代传统的 System V init 系统。它旨在提高启动速度,更有效地管理系统服务。如今,systemd 已成为许多流行 Linux 发行版的默认系统,包括 Ubuntu、Fedora 和 Red Hat Enterprise Linux等。
几乎所有版本的 Linux 都自带 systemd,但如果你的系统没有自带 systemd,可以通过运行以下命令安装:
sudo apt-get install -y systemd
注意:-y 标志表示快速安装软件包和依赖项;
查看 systemd 的版本:systemd --version
root@jpzhang-dev:~# systemd --version
-----------------------------------------------------------------------------------
systemd 245 (245.4-4ubuntu3.23)
+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=hybrid
在 systemd 之前,Linux 的启动一直采用 init 进程,如用下面的命令启动服务:
sudo /etc/init.d/apache2 start
service apache2 start
这种方法有两个缺点:
- 一、是启动时间长:init 进程是串行启动,只有前一个进程启动完,才会启动下一个进程。
- 二、是启动脚本复杂:init 进程只是执行启动脚本,不管其他事情,脚本需要自己处理各种情况,这往往使得脚本变得很长。
2.2 Systemd 是守护进程吗?
systemd 并不是一个守护进程。相反,它是一个为 Linux 提供大量系统组件的软件套件。其中主要组件是一个 "系统和服务管理器",可作为引导用户空间和管理用户进程的系统。还能替代各种守护进程和实用程序,从设备、登录管理以及网络连接管理和事件记录。
设计目标:在不同的 Linux 发行版中实现服务配置和行为的标准化,为系统的启动和管理提供一套完整的解决方案。根据 Linux 惯例,字母 d 是守护进程(daemon)的缩写。Systemd 这个名字的含义,就是它要守护整个系统。使用了 Systemd,就不需要再用 init 了。Systemd 取代了 initd,成为系统的第一个进程(PID 等于 1),其他进程都是它的子进程。
2.3 Systemd 的主要功能
systemd 有很多功能,比如: 积极并行化操作、方便按需启动守护进程、使用 Linux 控制组监控进程、管理挂载点和自动挂载点,以及实现复杂的基于事务依赖关系的服务控制逻辑。
此外,还支持 SysV 和 LSB 启动脚本,可替代 SysVinit,提供一个日志守护进程和用于管理基本系统配置的实用程序。
2.4 系统管理命令汇总
Systemd 并不是一个命令,而是一组命令,涉及到系统管理各个方面;
systemctl:systemd 的主要命令,用于管理系统;
sudo systemctl reboot # 重启系统
sudo systemctl poweroff # 关闭系统,切断电源
sudo systemctl halt # CPU 停止工作
sudo systemctl suspend # 暂停系统
sudo systemctl hibernate # 让系统进入冬眠状态
sudo systemctl hybrid-sleep # 让系统进入交互式休眠状态
sudo systemctl rescue # 启动进入救援状态(单用户状态)
systemd-analyze: 用于查看启动耗时
systemd-analyze # 查看启动耗时
systemd-analyze blame # 查看每个服务的启动耗时
systemd-analyze critical-chain # 显示瀑布状的启动过程流
systemd-analyze critical-chain docker.service # 显示指定服务的启动流
hostnamectl: 查看当前主机的信息
hostnamectl # 显示当前主机的信息
sudo hostnamectl set-hostname xxx # 设置主机名
localectl: 查看本地化设置
localectl # 查看本地化设置
sudo localectl set-locale LANG=en_GB.utf8 # 设置本地化参数
sudo localectl set-keymap en_GB
timedatectl: 查看当前时区设置
timedatectl # 查看当前时区设置
timedatectl list-timezones # 显示所有可用的时区
sudo timedatectl set-timezone America/New_York # 设置当前时区
sudo timedatectl set-time YYYY-MM-DD
sudo timedatectl set-time HH:MM:SS
loginctl:查看当前登录的用户
loginctl list-sessions # 列出当前 session
loginctl list-users # 列出当前登录用户
loginctl show-user jpzhang # 列出显示指定用户的信息
2.5 Unit
Systemd 可以管理所有系统资源,不同的资源统称为 Unit(单位);
2.5.1 Unit 种类
一共分成 12 种:
Service unit # 系统服务
Target unit # 多个 Unit 构成的一个组
Device Unit # 硬件设备
Mount Unit # 文件系统的挂载点
Automount Unit # 自动挂载点
Path Unit # 文件或路径
Scope Unit # 不是由 Systemd 启动的外部进程
Slice Unit # 进程组
Snapshot Unit # Systemd 快照,可以切回某个快照
Socket Unit # 进程间通信的 socket
Swap Unit # swap 文件
Timer Unit # 定时器
systemctl list-units 命令可以查看当前系统的所有 Unit:
systemctl list-units # 列出正在运行的 Unit
systemctl list-units --all # 列出所有 Unit,包括没有找到配置文件的或者启动失败的
systemctl list-units --all --state=inactive # 列出所有没有运行的 Unit
systemctl list-units --failed # 列出所有加载失败的 Unit
systemctl list-units --type=service # 列出所有正在运行的、类型为 service 的 Unit
2.5.2 Unit 状态
systemctl status 命令用于查看系统状态和单个 Unit 的状态;
systemctl status # 显示系统状态
sysystemctl status docker.service # 显示单个 Unit 的状态
systemctl -H jpzhang@10.20.3.215 status docker.service # 显示远程主机的某个 Unit 的状态
除了 systemctl 命令,status 还提供了三个查询状态的简单方法,主要供脚本内部的判断语句使用。
sudo systemctl is-active docker.service # 显示某个 Unit 是否正在运行
sudo systemctl is-failed docker.service # 显示某个 Unit 是否处于启动失败状态
sudo systemctl is-enabled docker.service # 显示某个 Unit 服务是否建立了启动链接
2.5.3 Unit 管理
对于用户来说,最常用的是下面这些命令,用于启动和停止 Unit(主要是 service);
sudo systemctl start docker.service # 立即启动一个服务
sudo systemctl stop docker.service # 立即停止一个服务
sudo systemctl restart docker.service # 重启一个服务
sudo systemctl kill docker.service # 杀死一个服务的所有子进程
sudo systemctl reload docker.service # 重新加载一个服务的配置文件
sudo systemctl daemon-reload # 重载所有修改过的配置文件
sudo systemctl show docker.service # 显示某个 Unit 的所有底层参数
sudo systemctl show -p CPUShares docker.service # 显示某个 Unit 的指定属性的值
sudo systemctl set-propertydocker.service CPUShares=500 # 设置某个 Unit 的指定属性
2.5.4 依赖关系
Unit 之间存在依赖关系:A 依赖于 B,就意味着 Systemd 在启动 A 的时候,同时会去启动 B。有些依赖是 Target 类型(详见下文),默认不会展开显示。如果要展开 Target,就需要使用 –all 参数;
systemctl list-dependencies --all xxx # 命令列出一个 Unit 的所有依赖。
2.6 Target
启动操作系统时,需要启动大量的 Unit。如果每一次启动,都要一一写明本次启动需要哪些 Unit,显然非常不方便。Systemd 的解决方案就是 Target。简单说,Target 就是一个 Unit 组,包含许多相关的 Unit 。启动某个 Target 的时候,Systemd 就会启动里面所有的 Unit。从这个意义上说,Target 这个概念类似于”状态点”,启动某个 Target 就好比启动到某种状态。传统的 init 启动模式里面,有 RunLevel 的概念,跟 Target 的作用很类似。不同的是,RunLevel 是互斥的,不可能多个 RunLevel 同时启动,但是多个 Target 可以同时启动。
systemctl list-unit-files --type=target # 查看当前系统的所有 Target
systemctl list-dependencies multi-user.target # 查看一个 Target 包含的所有 Unit
systemctl get-default # 查看启动时的默认 Target
sudo systemctl set-default multi-user.target # 设置启动时的默认 Target
# 切换 Target 时,默认不关闭前一个 Target 启动的进程
# systemctl isolate 命令改变这种行为
sudo systemctl isolate multi-user.target # 关闭前一个 Target 里面所有不属于后一个 Target 的进程
2.7 日志管理
Systemd 统一管理所有 Unit 的启动日志。带来的好处就是,可以只用 journalctl 一个命令,查看所有日志(内核日志和应用日志),日志的配置文件是 /etc/systemd/journald.conf,journalctl 功能强大,用法非常多。
sudo journalctl # 查看所有日志(默认情况下 ,只保存本次启动的日志)
sudo journalctl -k # 查看内核日志(不显示应用日志)
sudo journalctl -b # 查看系统本次启动的日志
sudo journalctl -b -0
sudo journalctl -b -1 # 查看上一次启动的日志(需更改设置)
sudo journalctl --since="2024-03-20 18:17:16" # 查看指定时间的日志
sudo journalctl --since "20 min ago"
sudo journalctl --since yesterday
sudo journalctl --since "2024-03-10" --until "2024-03-30 03:00"
sudo journalctl --since 09:00 --until "1 hour ago"
sudo journalctl -n # 显示尾部的最新 10 行日志
sudo journalctl -n 20 # 显示尾部指定行数的日志
sudo journalctl -f # 实时滚动显示最新日志
sudo journalctl /usr/lib/systemd/systemd # 查看指定服务的日志
sudo journalctl _PID=1 # 查看指定进程的日志
sudo journalctl /usr/bin/bash # 查看某个路径的脚本的日志
sudo journalctl _UID=33 --since today # 查看指定用户的日志
sudo journalctl -u docker.service # 查看某个 Unit 的日志
sudo journalctl -u docker.service --since today
sudo journalctl -u docker.service -f # 实时滚动显示某个 Unit 的最新日志
sudo journalctl -u docker.service -u atd.service --since today # 合并显示多个 Unit 的日志
# 查看指定优先级(及其以上级别)的日志,共有 8 级
# 0: emerg
# 1: alert
# 2: crit
# 3: err
# 4: warning
# 5: notice
# 6: info
# 7: debug
sudo journalctl -p err -b
sudo journalctl --no-pager # 日志默认分页输出,--no-pager 改为正常的标准输出
sudo journalctl -b -u docker.service -o json # 以 JSON 格式(单行)输出
sudo journalctl -b -u docker.serviceqq -o json-pretty # 以 JSON 格式(多行)输出,可读性更好
sudo journalctl --disk-usage # 显示日志占据的硬盘空间
sudo journalctl --vacuum-size=1G # 指定日志文件占据的最大空间
sudo journalctl --vacuum-time=1years # 指定日志文件保存多久
3. 在 Linux 中创建 Systemd 服务
systemd 服务在 unit 文件中定义(unit 是服务和系统资源,如设备、套接字、挂载点等的表示形式)。自定义服务 unit 文件应存储在 /etc/systemd/system/ 目录中,扩展名必须是 .service。例如,自定义 test-app 服务使用 /etc/systemd/system/test-app.service unit文件。
unit 文件是一种纯文本 ini-style 文件,以 .service 结尾,由 Unit、Service 和 Install 三部分组成;
- [Unit] => 启动顺序与依赖关系;
- [Service] => 启动行为定义;
- [Install] => 服务安装定义;
例如:
[Unit]
Description=test # 简单描述服务
After=network.target # 描述服务类别,表示本服务需要在network服务启动后在启动
Before=xxx.service # 表示需要在某些服务启动之前启动,After和Before字段只涉及启动顺序,不涉及依赖关系
[Service]
Type=forking # 设置服务的启动方式
User=USER # 设置服务运行的用户
Group=USER # 设置服务运行的用户组
WorkingDirectory=/PATH # 设置服务运行的路径(cwd)
KillMode=control-group # 定义systemd如何停止服务
Restart=no # 定义服务进程退出后,systemd的重启方式,默认是不重启
ExecStart=/start.sh # 服务启动命令,命令需要绝对路径(采用sh脚本启动其他进程时Type须为forking)
[Install]
WantedBy=multi-user.target # 多用户
3.1 在 Linux 中创建自定义 Systemd 服务文件
3.1.1 示例1:定义使用 Gunicorn 运行 django 应用程序的服务
要在 systemd 下以服务形式运行应用程序、或脚本,可以按如下方法创建一个新的 systemd 服务。
首先,在 /etc/systemd/system/ 下创建名为 django-myapps.service 的服务 unit 文件(切记用服务或应用程序的实际名称替换 django-myapps):
vi /etc/systemd/system/django-myapps.service
以下配置用于定义使用 Gunicorn(UNIX 下 Python WSGI HTTP 服务器)运行 django 应用程序的服务。
创建 django 应用:django-admin startproject myapps
/etc/systemd/system/django-myapps.service:
[Unit]
Description=Gunicorn daemon for serving myapps
After=network.target
[Service]
User=root
Group=root
WorkingDirectory=/home/workspace/examples/myapps
Environment="PATH=/home/workspace/py-env/py3.11-dev-env/bin"
ExecStart=/home/workspace/py-env/py3.11-dev-env/bin/gunicorn --worker-class=gevent -w 2 -b 0.0.0.0:8000 myapps.wsgi:application --log-level=info --access-logfile=/tmp/gunicorn/access.log --error-logfile=/tmp/gunicorn/error.log
ExecReload=/bin/kill -s HUP $MAINPID
RestartSec=5
[Install]
WantedBy=multi-user.target
简要介绍上述配置指令:
- Description: 指定服务的描述;
- After: 定义了与 network.target 的关系, 在这种情况下,django-myapps.service 会在 network.target 启动后启动;
- User: 指定服务运行用户;
- Group: 指定服务运行组;
- WorkingDirectory: 设置执行服务的工作目录;
- Environment: 设置执行服务环境变量;
- ExecStart: 定义启动该服务时要执行的命令及其参数;
- ExecReload: 定义触发服务配置重载时要执行的命令;
- WantedBy: 当使用 systemctl enable 命令启用 django-myapps.service unit时,在列出的每个unit的 .wants/ 或 .requires/ 目录中创建一个符号链接,本例中为 multi-user.target;
保存 django-myapps.service 文件并关闭,运行以下命令,重新加载 systemd:
# sudo systemctl daemon-reload
注意:在编辑 unit 文件后需要运行此命令;
启动/激活服务:
# systemctl start django-myapps.service
ubuntu@jpzhang-dev:~/workspace/examples/myapps/myapps$ systemctl start django-myapps.service
==== AUTHENTICATING FOR org.freedesktop.systemd1.manage-units ===
启动“django-myapps.service”需要认证。
Authenticating as: Ubuntu (jpzhang)
Password:
==== AUTHENTICATION COMPLETE ===
浏览器访问即可打开默认 django 页面;
检查服务状态:
# systemctl status django-myapps.service
ubuntu@jpzhang-dev:~/workspace/examples/myapps/myapps$ systemctl status django-myapps.service
● django-myapps.service - Gunicorn daemon for serving myapps
Loaded: loaded (/etc/systemd/system/django-myapps.service; disabled; vendor preset: enabled)
Active: active (running) since Sun 2024-04-28 17:41:00 CST; 4s ago
Main PID: 320060 (gunicorn)
Tasks: 3 (limit: 38470)
Memory: 77.3M
... ...
系统启动时启动:
使用 systemctl enable 命令设置启动时启动,同时可以使用 systemctl is-enable 命令检查服务是否已启用,如下所示:
# 开启随系统启动而启动
# systemctl enable django-myapps.service
# 检查是否开启
# systemctl is-enabled django-myapps.service
或者,也可以同时启用和启动服务。
# systemctl enable --now django-myapps.service
停止/停用该服务:
# systemctl stop django-myapps.service
重启服务:
# systemctl restart django-myapps.service
禁用服务:
使用 systemctl disable 命令禁用服务,以防止它在系统启动时启动,通过 systemctl is-enable 命令检查服务是否已禁用:
# systemctl disable django-myapps.service
# systemctl is-disabled django-myapps.service
或者,也可以同时禁用和停止它:
# systemctl disable --now django-myapps.service
3.1.2 示例2:定义使用 python 脚本的服务
将 python 脚本作为后台服务运行,这样即使服务器因某种原因重启,脚本也能在后台运行。
注意:除了 Python 脚本其他脚本配置方式一样,这里仅通过 Python 举例说明;
准备一个测试脚本 test.py:
import time
from datetime import datetime
while True:
with open("/tmp/timestamp.txt", "a") as f:
f.write("The current timestamp is: " + str(datetime.now()))
f.close()
time.sleep(10)
上述脚本将每隔 10 秒在文件中写入当前的时间戳;
创建 unit 文件:
vi /etc/systemd/system/python-test.service
添加内容如下:
[Unit]
Description=My test python service
After=multi-user.target
[Service]
Type=simple
Restart=always
ExecStart=/home/workspace/py-env/py3.11-dev-env/bin/python3.11 /home/workspace/examples/test.py
[Install]
WantedBy=multi-user.target
重载修改过的配置文件:sudo systemctl daemon-reload
启动 Python 脚本服务:
启动:
sudo systemctl start python-test.service
查看状态:
sudo systemctl status python-test.service
检查时间戳输出:
ubuntu@jpzhang-dev:~/workspace/examples$ tail -f /tmp/timestamp.txt
The current timestamp is: 2024-04-28 18:03:14.978850The current timestamp is: 2024-04-28 18:03:24.979337
其他命令与上节一样,这里不在继续说明;
感谢您花时间阅读文章!
相关推荐
- 你要如何学习写一个数据库内核(如何实现一个最简单的数据库)
-
数据库这个方向上还有许多细分方向,每个细分方向上都有许多知识。...
- 每个大数据架构师都需要的6个基本技能
-
为了成为一名出色的大数据架构师,首先必须成为一名数据架构师,但这两种角色的职责各有不同。数据分为结构化和非结构化两种。尽管大数据为各种规模的组织提供了许多洞察和分析的机会,但处理起来非常困难,并且需...
- 警惕!Spring Data MongoDB SpEL表达式注入漏洞风险通告
-
漏洞描述近日,亚信安全CERT监控到SpringDataMongoDB存在表达式注入漏洞(CVE-2022-22980),该漏洞源于SpringDataMongoDB应用程序在使用带有SpEL...
- 既然有MySQL了,为什么还要有MongoDB?
-
大家好,我是哪吒,最近项目在使用MongoDB作为图片和文档的存储数据库,为啥不直接存MySQL里,还要搭个MongoDB集群,麻不麻烦?...
- 分布式系统核心概念及实现(分布式核心原理解析)
-
一、分布式系统核心概念1.分布式系统的定义分布式系统是由多个独立的计算机(节点)通过网络连接,协同完成任务的系统。这些节点可以是物理机、虚拟机或容器。...
- nosql之mongodb(nosql数据库是国产的吗)
-
什么是MongoDB?MongoDB是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。...
- 如何治理非结构化数据?(非结构化化数据)
-
据调查,当前企业80%的数据为非结构化数据或半结构化数据,而结构化数据是他们管理的重点,非结构化数据却被忽视。然而,非结构化数据也有着它的价值。那么,如何治理非结构化数据?IDC调研显示,目前企业中8...
- Cloudera收购大数据加密初创企业Gazzang
-
Hadoop供应商Cloudera刚刚收购了专门研究下一代数据存储环境加密技术技术的初创企业Gazzang,但交易细节并未透露。这是Cloudera的第一笔重大收购。Gazzang成立于20...
- 全网最全95道MongoDB面试题1万字详细解析
-
1、mongodb是什么?MongoDB是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。在高负载的情况下,添加更多的节点,可以保证服务器性能。MongoDB旨在给WEB应...
- mongodb——视图(mongodb object)
-
MongoDB视图是一个可查询的对象,其内容由其他集合或视图上的聚合管道定义。MongoDB不会将视图内容持久化到磁盘。当客户端查询视图时,MongoDB可以要求客户端拥有查询视图的权限。MongoD...
- mongodb的优缺点及应用场景(mongodb 优点 应用场景)
-
一、MongoDB是什么1、维基百科MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。...
- 5款Syslog集中系统日志常用工具对比推荐
-
一、为何要集中管理Syslog?Syslog由Linux/Unix系统及其他网络设备生成,广泛分布于整个网络。因其包含关键信息,可用于识别网络中的恶意活动,所以必须对其进行持续监控。将Sys...
- 跨平台、多数据库支持的开源数据库管理工具——DBeaver
-
简介今天给大家推荐一个开源的数据库管理工具——DBeaver。它支持多种数据库系统,包括Mysql、Oracle、PostgreSQL、SLQLite、SQLServer等。DBeaver的界面友好...
- 强烈推荐!数据库管理工具:Navicat Premium 16.3.2 (64位)
-
NavicatPremium,一款集数据迁移、数据库管理、SQL/查询编辑、智能设计、高效协作于一体的全能数据库开发工具。无论你是MySQL、MariaDB、MongoDB、SQLServer、O...
- 3 年 Java 程序员还玩不转 MongoDB,网友:失望
-
一、什么场景使用MongoDB?...
你 发表评论:
欢迎- 一周热门
-
-
Linux:Ubuntu22.04上安装python3.11,简单易上手
-
宝马阿布达比分公司推出独特M4升级套件,整套升级约在20万
-
MATLAB中图片保存的五种方法(一)(matlab中保存图片命令)
-
别再傻傻搞不清楚Workstation Player和Workstation Pro的区别了
-
Linux上使用tinyproxy快速搭建HTTP/HTTPS代理器
-
如何提取、修改、强刷A卡bios a卡刷bios工具
-
Element Plus 的 Dialog 组件实现点击遮罩层不关闭对话框
-
日本组合“岚”将于2020年12月31日停止团体活动
-
SpringCloud OpenFeign 使用 okhttp 发送 HTTP 请求与 HTTP/2 探索
-
tinymce 号称富文本编辑器世界第一,大家同意么?
-
- 最近发表
- 标签列表
-
- dialog.js (57)
- importnew (44)
- windows93网页版 (44)
- yii2框架的优缺点 (45)
- tinyeditor (45)
- qt5.5 (60)
- windowsserver2016镜像下载 (52)
- okhttputils (51)
- android-gif-drawable (53)
- 时间轴插件 (56)
- docker systemd (65)
- slider.js (47)
- android webview缓存 (46)
- pagination.js (59)
- loadjs (62)
- openssl1.0.2 (48)
- velocity模板引擎 (48)
- pcre library (47)
- zabbix微信报警脚本 (63)
- jnetpcap (49)
- pdfrenderer (43)
- fastutil (48)
- uinavigationcontroller (53)
- bitbucket.org (44)
- python websocket-client (47)