上篇文章 我们留了个坑, 最后提到了 init.d, systemd 这两个概念,在理解这两个概念前,我们先来了解另一个概念,那就是 Linux 上的 service。
如果硬要给 service 下个定义,还真有些不可描述。以笔者个人理解, Linux 上的 service 通常就是一个可以跑在后台的程序。具体来说,我们执行 ll /etc/init.d
,
这个目录下的可执行脚本都会对应一个程序。 然后这个程序我们可以通过 service xxxd start
或 service xxxd stop
去启动或是终止。
通常我们管理 service 有两种方式,而这两种方式就分别涉及到 init.d 和 systemd 了:
- 一是通过
/etc/init.d
内的可执行脚本,对应的技术是 System V init,涉及到的命令通常是service xxxc ...
和update-rc.d xxxc ...
等 - 二是通过
/lib/systemd/system
(debian) 或/usr/lib/systemd/system/
(redhat) 的配置文件,对应的技术是 systemd,涉及到的常用命令是systemctl
上述的方式一是老方式,而方式二是最近几年发展起来的新方式。笔者开发和生产环境一直是使用 Ubuntu,所以,这里以 Ubuntu 为例进行说明。
在 Ubuntu14.04 及以前,我们只能使用 System V init,因为这时还没有引入 systemd,而在 Ubuntu15.04 后,引入了 systemd,所以在这之后的系统,推荐使用 systemd
接下来,我们以 mongodb 为例,分别以两种方式走下创建 service 的流程
Ubuntu14.04 创建 mongod service
mongodb 官方提供了二进制文件下载,在这里。
下面我先说下我自己的部署标准
- 该软件整体安装在
/opt
目录下 - 相关的可执行文件如
mongo
、mongod
全局可用 - 配置到系统服务,可开机启动
了解了以上思路,我们正式开始部署流程,注意以下所有操作都是在 root 账户下,后面不再赘述。
1. 先解压从官网下载的二进制文件包,在 /opt
目录下解压后,解压后文件目录如下
# tree /opt
/opt
└── mongodb-linux-x86_64-3.6.4
├── bin
│ ├── bsondump
│ ├── install_compass
│ ├── mongo
│ ├── mongod
│ ├── mongodump
│ ├── mongoexport
│ ├── mongofiles
│ ├── mongoimport
│ ├── mongoperf
│ ├── mongoreplay
│ ├── mongorestore
│ ├── mongos
│ ├── mongostat
│ └── mongotop
├── GNU-AGPL-3.0
├── MPL-2
├── README
└── THIRD-PARTY-NOTICES
2. 创建相关文件及文件夹
# 进入到 mongodb 安装目录
cd /opt/mongodb-linux-x86_64-3.6.4
# 创建将来存放 mongo 数据的文件夹
mkdir data
# 创建日志文件夹
mkdir logs
# 创建并编写配置文件, 并给到 755 的权限
vim mongod.conf
# 创建并编写 init.mongod, 用于将来注册进 init.d
vim init.mongod
chmod 755 init.mongod
配置文件 mongod.conf 内容如下
# mongod.conf
# Where to store the data.
dbpath = /opt/mongodb/data
storageEngine = wiredTiger
directoryperdb = true
# where to log
logpath = /opt/mongodb/logs/mongodb.log
logappend=true
logRotate = reopen
port = 27017
# daemon
fork = true
# Enable journaling, http://www.mongodb.org/display/DOCS/Journaling
journal=true
# Turn on/off security. Off is currently the default
noauth = true
# auth = true
# keyFile = /srv/mongodb/conf/rs.key
# crawler repl
# replSet=rs_crawler
pidfilepath = /opt/mongodb/mongod.pid
init.mongod 内容如下
#! /bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/opt/mongodb/bin/mongod
DAEMON_ARGS="-f /opt/mongodb/mongod.conf"
NAME=mongod
DESC=mongodb
RUNDIR=/opt/mongodb
PIDFILE=$RUNDIR/mongod.pid
test -x $DAEMON || exit 0
if [ -r /etc/default/$NAME ]
then
. /etc/default/$NAME
fi
. /lib/lsb/init-functions
set -e
if [ "$(id -u)" != "0" ]
then
log_failure_msg "Must be run as root."
exit 1
fi
case "$1" in
start)
echo -n "Starting $DESC: "
mkdir -p $RUNDIR
touch $PIDFILE
chown mongodb:mongodb $RUNDIR $PIDFILE
chmod 755 $RUNDIR
if [ -n "$ULIMIT" ]
then
ulimit -n $ULIMIT || true
fi
if start-stop-daemon --start --quiet --oknodo --umask 007 --pidfile $PIDFILE --chuid mongodb:mongodb --exec $DAEMON -- $DAEMON_ARGS
then
echo "$NAME."
else
echo "failed"
fi
;;
stop)
echo -n "Stopping $DESC: "
if start-stop-daemon --stop --retry forever/TERM/1 --quiet --oknodo --pidfile $PIDFILE --exec $DAEMON
then
echo "$NAME."
else
echo "failed"
fi
rm -f $PIDFILE
sleep 1
;;
restart|force-reload)
${0} stop
${0} start
;;
status)
status_of_proc -p ${PIDFILE} ${DAEMON} ${NAME}
;;
*)
echo "Usage: /etc/init.d/$NAME {start|stop|restart|force-reload|status}" >&2
exit 1
;;
esac
exit 0
3. 接下来为了解耦或是方便,我们可以创建一些软链接
ln -s /opt/mongodb-linux-x86_64-3.6.4 /opt/mongodb
ln -s /opt/mongodb-linux-x86_64-3.6.4/bin/mongod /usr/local/bin/mongod
ln -s /opt/mongodb-linux-x86_64-3.6.4/bin/mongo /usr/local/bin/mongo
# /opt/mongodb-linux-x86_64-3.6.4/bin 下的其它命令是否创建软链,根据自己需求
我们注意到,mongodb 的所有相关文件都在自己的目录内,如果外部引用的话,都是通过软链接的方式,这类似于设计模式中的桥接或是代理。
4. 注册到系统服务
# 创建 mongodb 的用户,通常这种系统服务,出于安全考虑,我们不会直接以 root 用户运行
# 我们首先创建一个 mongodb 用户,将来用这个用户运行 mongodb
# 下面的命令创建了 mongodb user,同时创建了 mongodb group,指定该用户无法登录系统,同时创建了家目录,此处家目录其实可以不创建,因为我们的部署流程中没用到 mongodb 的家目录
useradd mongodb --home-dir /var/lib/mongodb --shell /usr/sbin/nologin --create-home --user-group
# 将 mongodb 的安装目录 全部交给 mongodb 用户
chown -R mongodb:mongodb /opt/mongodb /opt/mongodb-linux-x86_64-3.6.4
# 将 init.mongod 文件软链到 /etc/init.d/mongod, 注册成系统服务
ln -s /opt/mongodb/init.mongod /etc/init.d/mongod
# 下面的命令是为了将 mongod 软链到不同的 runlevel,以便于开机启动 mongod,其执行结果如下
# runlevel 不理解的话,可以简单参考 http://www.mikewootc.com/wiki/linux/usage/ubuntu_service_usage.html
# 这篇文章有个大概的介绍,能给您从一个点对这些概念初步了解,如果想要详细了解,再详查
update-rc.d -f mongod defaults
update-rc.d: warning: /etc/init.d/mongod missing LSB information
update-rc.d: see <http://wiki.debian.org/LSBInitScripts>
Adding system startup for /etc/init.d/mongod ...
/etc/rc0.d/K20mongod -> ../init.d/mongod
/etc/rc1.d/K20mongod -> ../init.d/mongod
/etc/rc6.d/K20mongod -> ../init.d/mongod
/etc/rc2.d/S20mongod -> ../init.d/mongod
/etc/rc3.d/S20mongod -> ../init.d/mongod
/etc/rc4.d/S20mongod -> ../init.d/mongod
/etc/rc5.d/S20mongod -> ../init.d/mongod
5. 启动关闭 mongod
# 以下命令启动 mongod, 会输出下面的结果
service mongod start
Starting mongodb: about to fork child process, waiting until server is ready for connections.
forked process: 1479
child process started successfully, parent exiting
mongod.
# 查看 mongod 状态
service mongod status
* mongod is running # 启动时的状态
* mongod is not running # 关闭时的状态
# 关闭 mongod
service mongod stop
Ubuntu18.04 创建 mongod service
在 Ubuntu18.04 上面,也可以通过与 Ubuntu14.04 流程一样,创建 service。但是,当我们创建完成后,通过 service mongod start
启动服务时,会报如下错误
Failed to start mongod.service: Unit mongod.service not found.
这是什么意思呢?
因为在 Ubuntu18.04 中,系统已经主要通过 systemd 来管理服务,所以,如果只是在 /etc/init.d
中注册了服务,还不够,需要根据我的 上篇文章,
在 /lib/systemd/system
中注册 mongod.sevice 配置文件。当这个也配置好后,就可以通过 service mongod start
启动服务了,此时输出如下:
● mongod.service - mongodb server
Loaded: loaded (/opt/mongodb/mongod.service; disabled; vendor preset: enabled)
Active: active (running) since Wed 2019-10-16 19:26:53 CST; 10s ago
Main PID: 25089 (mongod)
Tasks: 23 (limit: 478)
CGroup: /system.slice/mongod.service
└─25089 /opt/mongodb/bin/mongod -f /opt/mongodb/mongod.conf
Oct 16 19:26:53 iZ8vb9wvg14ypn9rjj3sdpZ systemd[1]: Started mongodb server.
此时的输出结果与执行 systemctl status mongod.service
结果一样,而并不是我们在 init.mongod 脚本中写的输出的内容,所以我怀疑,在 Ubuntu18.04 中,service 命令底层是不是还是调用了 systemctl
命令。另外,我们发现这个输出比 Ubuntu14.04 上面的好看一些。然后这也解答了我 上篇文章 的疑惑,即我们在 apt install ...
的时候,不仅把服务注册到了 systemd,还注册到了 init.d, 所以我们在管理服务时,既可以通过 service mongod ...
, 也可以通过 systemctl ... mongod
来控制。
但是为了方便起见,我们在较新版本的系统上,自行配置服务时,笔者建议采用 systemd 配置。
那么既然 systemd 可以实现以上需求,为什么新版本系统还不丢弃 init.d 呢?
笔者看来,首先 systemd 的功能并不能完全覆盖 init.d,比如 init.d 里面的服务,可以配置 runlevel,但是 systemd 中貌似并没有这种功能,虽然绝大多数场景用不到 runlevel 的特性。另外一点是,init.d 中的脚本,我们可以随意自定义命令,而 systemd 中只有些固定的 start/stop 等命令。
当然,软件行业一个新技术要代替老技术,真的阻力太大,我们有时候甚至不知道这个阻力到底是好是坏。我们经常看到,一个新技术,远远优于一个老技术,但是就是没法完全取代老技术,最后的结果往往是新技术不得不费了吃奶的劲儿以一个丑陋的方式去兼容老技术。
最后,如果您想要更多的了解 systemd,你可以参考 鸟哥的文档,本文只是给您展示了一个基本的东西,如果读者朋友希望有更全面的更深入的理解,还是建议读一些成体系的文档。
至此,Linux 上面服务的配置,就基本说完了。希望对于想要入门 Linux 系统服务的您来说有所帮助,也期待您留言讨论。