Loading

想在Linux开机时候启动一个程序?看看这篇文章

回顾历史

按下电源开关的那一刻,BIOS苏醒,然后加载开机管理程序(Boot Loader),接着Kernel上场。Kernel完成硬件与驱动的载入,成功后开始执行用户态的第一个程序。
image
用户态第一个程序有个特点,其pid=1.pid=1的进程会开始执行一堆预先定义好的“开机脚本”或者“开机服务”
因此要想让程序在开机时候启动,只需要准备好脚本,告诉pid=1的进程即可。
image
一般来讲,需要开机启动的程序有很多,东西一多,就需要考虑管理问题。怎么管理呢?SysV initSystemd登场。

  • SysV init

System V是Unix的一个版本,简称SysV。在此版本中用户态的第一个程序调用的是init,然后init唤醒所有的其他服务。

  • Systemd

一款新的服务管理工具

还有种服务管理系统Upstart,存在感比较低,省略
这时候有人脑海里面就会闪现出一个问题:如何判断某个linux系统采用了那种服务管理系统?
可以从/proc/1/文件夹中获取到一些蛛丝马迹。在/proc目录中,有一个名称为exe的文件(和windows系统没有半毛钱关系)。
exe文件指向启动当前进程的可执行文件(完整路径)的符号链接。通过查看exe文件的指向,可以知道当前系统所使用的服务管理系统。
以下是在两种不同初始化系统上执行stat /proc/1/exe所得到的结果。从第二行结果可知,第一个系统采用的是Systemd,第二个系统采用的是SysV init初始化(init为其可执行文件)。
为什么例子中没有Upstart?因为找不到Upstart的系统

[root@ip-172-31-8-32 ~]# stat /proc/1/exe
  File: ‘/proc/1/exe’ -> ‘/usr/lib/systemd/systemd’
  Size: 0         	Blocks: 0          IO Block: 1024   symbolic link
Device: 3h/3d	Inode: 66971739    Links: 1
Access: (0777/lrwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)
root@ip-172-31-9-10:/proc/1# stat /proc/1/exe
  File: /proc/1/exe -> /init
  Size: 0               Blocks: 0          IO Block: 1024   symbolic link
Device: 33h/51d Inode: 81          Links: 1
Access: (0777/lrwxrwxrwx)  Uid: (    0/    root)   Gid: (    0/    root)

top命令也可达到同样效果:

Tasks: 124 total,   1 running, 123 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.3 us,  0.3 sy,  0.0 ni, 99.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.3 st
KiB Mem :  1880524 total,   109836 free,   350800 used,  1419888 buff/cache
KiB Swap:        0 total,        0 free,        0 used.  1226560 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
    1 root      20   0  126128   4136   2152 S  0.0  0.2   4:58.20 /usr/lib/systemd/systemd --switched-root --system --deserialize 21
    2 root      20   0       0      0      0 S  0.0  0.0   0:00.29 [kthreadd]
top - 18:05:00 up  1:52,  0 users,  load average: 0.19, 0.12, 0.13
Tasks:  10 total,   1 running,   9 sleeping,   0 stopped,   0 zombie
%Cpu(s):  2.1 us,  1.2 sy,  0.0 ni, 96.2 id,  0.2 wa,  0.0 hi,  0.3 si,  0.0 st
MiB Mem :  11921.9 total,   6530.6 free,   3152.8 used,   2238.5 buff/cache
MiB Swap:   3072.0 total,   3072.0 free,      0.0 used.   8108.7 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
    1 root      20   0    1744   1088   1016 S   0.0   0.0   0:00.02 /init
  122 root      20   0    1764     72      0 S   0.0   0.0   0:00.00 /init
  123 root      20   0    1764     88      0 S   0.0   0.0   0:00.01 /init

我是谁?我在哪里?应该到哪里去?

当明确了当前linux系统的初始化系统后,紧接着第二个问题接踵而至:怎么做才能让初始化系统知道,在系统启动后要运行kafka或者nginx?
答案和把一头大象装入冰箱一样:1. 打开冰箱门 2. 把大象装进去 3. 关闭冰箱门
但是细节呢?细节就是1、完成服务脚本 2、将服务脚本放在固定的位置,下面是不同初始化系统放置服务脚本的位置

SysV init Systemd
/etc/init.d /etc/systemd/system

下面一一更详细解释


SysV init

  1. /etc/init.d目录中,touch hello添加服务脚本service --status-all命令,会列举/etc/init.d目录中所有服务。以下结果说明,系统已经认识了服务hello
root@ip-172-31-9-10:/etc/init.d# service --status-all
 [ - ]  apparmor
 [ ? ]  apport
 [ - ]  dbus
 [ - ]  hello
 [ ? ]  hwclock.sh
...
  1. 编写服务脚本。服务脚本主体采用shell语法编写,一般应用程序都会提供自启动脚本。下面为一段例子脚本
点击查看代码
#!/bin/bash
#service hello
start() {
    echo 'start hello service...'
    echo 'start hello service over'
}
stop() {
    echo 'stop hello service...'
    echo 'stop hello service over'
}

case $1 in
    start)
        start ;;
    stop)
        stop
        ;;
    restart)
        stop
        start
        ;;
    *)
        echo "valid arg:[start|status|stop|restart]"
esac
exit 0
  1. 使用命令chkconfig --add hello将服务hello添加到开机启动中。 在/etc目录中,有6个子目录,每个子目录代表服务脚本的不同执行场景。以下为目录和场景的对应关系。
目录 level 执行场景
rc0.d 0 关机
rc1.d 1 单用户模式
rc2.d 2 无网络连接的多用户命令行模式
rc3.d 3 有网络连接的多用户命令行模式
rc4.d 4 系统保留
rc5.d 5 带图形界面的多用户模式
rc6.d 6 重新启动

每个目录中的文件都链接至init.d目录中的服务脚本。以下为rc0.d目录内容,其作用为在关机场景时,将rc0.d目录中所有的服务关闭(K-kill)
以nginx服务脚本为例,chkconfig在rc0.d目录中创建K01nginx软链接,指向/init.d/nginx,达到关机时关闭nginx服务的目的。

root@weidengbai:/etc/rc0.d# ls -l
total 0
lrwxrwxrwx 1 root root 13 Apr 23  2020 K01atd -> ../init.d/atd
lrwxrwxrwx 1 root root 20 Apr 23  2020 K01cryptdisks -> ../init.d/cryptdisks
lrwxrwxrwx 1 root root 25 Apr 23  2020 K01multipath-tools -> ../init.d/multipath-tools
lrwxrwxrwx 1 root root 15 Mar 25 09:48 K01nginx -> ../init.d/nginx
....

当运行chkconfig --add hello命令时,chkconfig 会自动创建对应目录的软连接。因此,如果系统未安装chkconfig 服务,参考对应目录中的命名规格,手工创建软链接,可以达到一样的效果。

systemd

systemd在SysV init 之后出现,向下兼容。但systemd的服务脚本也有自己独有的脚本语法和放置位置。下面以常见的kafka开机启动为例说明。
在此之前,系统中已经存在zookeeper.service.

  1. 在/etc/systemd/system目录中添加脚本touch kafka.service,然后systemctl list-unit-files |grep kafka查询此服务,确保添加成功:
[root@ip-172-31-8-32 system]# systemctl list-unit-files |grep kafka
kafka.service                                 masked
  1. 编辑服务脚本:
点击查看代码
[Unit]
# Kafka服务的描述
Description=Kafka Service
# 服务依赖—在什么服务之后启动,一般为在网络服务启动后启动
After=network.target zookeeper.service
 
 
[Service]
Type=forking
# 启动环境参数
# 此脚本指定了Zookeeper日志和Java的目录
#Environment=ZOO_LOG_DIR=/data/kafak/logs/
#Environment=JAVA_HOME=/usr/local/jdk1.8
 
# 启动命令
ExecStart=/usr/local/data/kafka_2.13/bin/kafka-server-start.sh -daemon /usr/local/data/kafka_2.13/config/server.properties
# 停止命令
ExecStop=/usr/local/data/kafka_2.13/bin/kafka-server-stop.sh

Restart=on-failure

[Install]
WantedBy=multi-user.target

  1. 加入开机启动
#系统重新加载服务
systemctl daemon-reload
#设置开机自启动
systemctl enable kafka.service
posted @ 2022-04-13 15:46  lecoder  阅读(530)  评论(0)    收藏  举报