apache2 初始化脚本会pidof
检查 apache 是否已经在运行。
if pidof $DAEMON > /dev/null 2>&1 ; then
if [ -e $PIDFILE ] && pidof $DAEMON | tr ' ' '\n' | grep -w $(cat $PIDFILE) > /dev/null 2>&1 ; then
AP_RET=2
else
AP_RET=1
fi
...
elif [ $AP_RET = 1 ] ; then
APACHE2_INIT_MESSAGE="There are processes named 'apache2' running which do not match your pid file which are left untouched in the name of safety, Please review the situation by hand".
(文件:Ubuntu 16.04.3 LTS 上的 /etc/init/apache2 - 为简洁起见截断)
但是,在 docker 主机上,VM 容器中可能已经有 apache。在这种情况下pidof
,即使主机上没有运行 apache,也会返回非空。
$ sudo service apache2 stop
$ pidof apache2
32742 32480 32379 32365 31295 31294 31293 31292 31291 31274 31270
这意味着只有当所有带有 apache 的 docker 容器都停止(或尚未启动)时,init 脚本才会成功。因此,无法restart
编辑主机上的 apache。
如何解决这种情况,以便可以独立于 VM 重新启动主机的 apache?是否有一个版本pidof
只能检测 init 直接拥有的 pid?
太糟糕了
# can't use pidofproc from LSB here
,初始化脚本中有一个,没有真正的解释。我仍然认为这个 apache2 脚本有一个值得报告的错误。TL; DR:解决方案:替换
pidof apache2
为pgrep --ns 1 ^apache2$
(或者如果这不起作用,pgrep --ns 1 --nslist uts ^apache2$
)关于命名空间的详细解释,我在找到之前写的一个例子
pgrep
可以做到以下几点:一旦你有“候选人” using
pidof
,这里有一种方法可以将它们分开:检查它们的命名空间,并将它们与pid 1
(init/systemd) 的命名空间进行比较。lxc
使用和过程的示例inetd
,但这是容器的技术和过程的名称不可知论:在这里可以清楚地看到
pid 3372
sharepid 1
的命名空间。3372
正在主机上运行。10285
不共享任何命名空间(好的用户是相同的:容器以root身份运行),所以它在一个容器中。有时主机上运行的某些程序可能由于某种原因(通常与安全相关)而更改了其中的一些,但不应该是 uts(主机名)命名空间。所以这里有一个脚本 usingstat
并且在 arg "$1" 中给出进程的名称(例如:set -- inetd
或脚本的参数)将只给出相同 uts 命名空间中的进程,通常意味着(相同的)主机。在我的示例中,返回
3372
.我解释了如何做到这一点,但为什么要在
pgrep
有处理它的选项时重新发明轮子:或者对于大多数情况,只是:
如果您在主机上的服务在端口 80 上侦听,您可以使用 netstats 找出进程 ID
容器进程应与主机上的其他端口号绑定,并在具有 80 端口的容器内部绑定。这样您就可以轻松找出主机进程并将其杀死。