- 执行命令ps -ef查看redis服务,结果如下:
root@122c2df16bbb:/data# ps -ef
UID PID PPID C STIME TTY TIME CMD
redis 1 0 0 09:22 ? 00:00:01 redis-server *:6379
root 287 0 0 09:36 ? 0
《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》
【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享
0:00:00 /bin/bash
root 293 287 0 09:39 ? 00:00:00 ps -ef
上面的结果展示了两个关键信息:
第一,redis服务是redis账号启动的,并非root;
第二,redis服务的PID等于1,这很重要,宿主机执行docker stop命令时,该进程可以收到SIGTERM信号量,于是redis应用可以做一些退出前的准备工作,例如保存变量、退出循环等,也就是优雅停机(Gracefully Stopping);
现在我们已经证实了redis服务并非root账号启动,而且该服务进程在容器内还是一号进程,但是我们在Dockerfile和docker-entrypoint.sh脚本中都没有发现切换到redis账号的命令,也没有sudo和su,这是怎么回事呢?
答案是gosu
再看一次redis的docker-entrypoint.sh文件,如下图,地址是:https://github.com/docker-library/redis/blob/6845f6d4940f94c50a9f1bf16e07058d0fe4bc4f/5.0/docker-entrypoint.sh :
注意上图中的代码,我们来分析一下:
-
假设启动容器的命令是docker run --name myredis -idt redis redis-server /usr/local/etc/redis/redis.conf;
-
容器启动后会执行docker-entrypoint.sh脚本,此时的账号是root;
-
当前账号是root,因此会执行上图红框中的逻辑;
-
红框中的$0表示当前脚本的名称,即docker-entrypoint.sh;
-
红框中的$@表示外部传入的所有参数,即redis-server /usr/local/etc/redis/redis.conf;
-
gosu redis “$0” “@”,表示以redis账号的身份执行以下命令:
docker-entrypoint.sh redis-server /usr/local/etc/redis/redis.conf
-
gosu redis “$0” "@"前面加上个exec,表示以gosu redis “$0” "@"这个命令启动的进程替换正在执行的docker-entrypoint.sh进程,这样就保证了gosu redis “$0” "@"对应的进程ID为1;
-
gosu redis “ 0 ” " @ " 导 致 d o c k e r − e n t r y p o i n t . s h 再 执 行 一 次 , 但 是 当 前 的 账 号 已 经 不 是 r o o t 了 , 于 是 会 执 行