Сценарий инициализации 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".
(Файл: / etc / init / apache2 в Ubuntu 16.04.3 LTS - для краткости усечен)
Однако на хосте докеров в контейнерах виртуальных машин уже может быть apache. В таком случае pidof
возвращает непустое значение, даже если на хосте не запущен apache.
$ sudo service apache2 stop
$ pidof apache2
32742 32480 32379 32365 31295 31294 31293 31292 31291 31274 31270
Это означает, что сценарий инициализации завершается успешно только тогда, когда все Docker-контейнеры с apache остановлены (или еще не запущены). Следовательно, apache на хосте не может быть restart
изд.
Как исправить эту ситуацию, чтобы apache хоста можно было перезапустить независимо от виртуальных машин? Есть ли версия pidof
который будет обнаруживать только pid, принадлежащие непосредственно init?
Жаль, что есть # can't use pidofproc from LSB here
в сценарии инициализации без реального объяснения. Я бы по-прежнему считал этот скрипт apache2 ошибкой, о которой следует сообщить.
TL; DR: решение: заменить pidof apache2
с участием pgrep --ns 1 ^apache2$
(или, если это не сработает, pgrep --ns 1 --nslist uts ^apache2$
)
Длинное объяснение пространств имен с примером, который я написал перед тем, как найти pgrep
мог сделать это следующим образом:
Когда у вас есть «кандидаты», использующие pidof
, вот способ их разделения: проверьте их пространства имен и сравните их с pid 1
(init / systemd) пространства имен. Пример использования lxc
и inetd
процесс, но это не зависит от технологии контейнера и названия процесса:
# lxc-start stretch-amd64
# pidof inetd
10285 3372
# ls -l /proc/1/ns/
total 0
lrwxrwxrwx. 1 root root 0 nov. 9 19:49 cgroup -> cgroup:[4026531835]
lrwxrwxrwx. 1 root root 0 nov. 9 19:49 ipc -> ipc:[4026531839]
lrwxrwxrwx. 1 root root 0 nov. 9 19:49 mnt -> mnt:[4026531840]
lrwxrwxrwx. 1 root root 0 nov. 9 19:49 net -> net:[4026531993]
lrwxrwxrwx. 1 root root 0 nov. 9 19:49 pid -> pid:[4026531836]
lrwxrwxrwx. 1 root root 0 nov. 9 19:49 pid_for_children -> pid:[4026531836]
lrwxrwxrwx. 1 root root 0 nov. 9 19:49 user -> user:[4026531837]
lrwxrwxrwx. 1 root root 0 nov. 9 19:49 uts -> uts:[4026531838]
# ls -l /proc/3372/ns/
total 0
lrwxrwxrwx. 1 root root 0 nov. 9 19:51 cgroup -> cgroup:[4026531835]
lrwxrwxrwx. 1 root root 0 nov. 9 19:51 ipc -> ipc:[4026531839]
lrwxrwxrwx. 1 root root 0 nov. 9 19:51 mnt -> mnt:[4026531840]
lrwxrwxrwx. 1 root root 0 nov. 9 19:51 net -> net:[4026531993]
lrwxrwxrwx. 1 root root 0 nov. 9 19:51 pid -> pid:[4026531836]
lrwxrwxrwx. 1 root root 0 nov. 9 19:51 pid_for_children -> pid:[4026531836]
lrwxrwxrwx. 1 root root 0 nov. 9 19:51 user -> user:[4026531837]
lrwxrwxrwx. 1 root root 0 nov. 9 19:51 uts -> uts:[4026531838]
# ls -l /proc/10285/ns/
total 0
lrwxrwxrwx. 1 root root 0 nov. 9 19:50 cgroup -> cgroup:[4026532516]
lrwxrwxrwx. 1 root root 0 nov. 9 19:50 ipc -> ipc:[4026532415]
lrwxrwxrwx. 1 root root 0 nov. 9 19:50 mnt -> mnt:[4026532410]
lrwxrwxrwx. 1 root root 0 nov. 9 19:50 net -> net:[4026532418]
lrwxrwxrwx. 1 root root 0 nov. 9 19:50 pid -> pid:[4026532416]
lrwxrwxrwx. 1 root root 0 nov. 9 19:50 pid_for_children -> pid:[4026532416]
lrwxrwxrwx. 1 root root 0 nov. 9 19:50 user -> user:[4026531837]
lrwxrwxrwx. 1 root root 0 nov. 9 19:50 uts -> uts:[4026532414]
Здесь хорошо видно, что pid 3372
акции pid 1
пространства имен. 3372
работает на хосте. 10285
не разделяет какое-либо пространство имен (нормально, пользователь тот же: контейнер запущен как root), поэтому он находится в контейнере. Возможно, что иногда какая-то программа, запущенная на хосте, по какой-то причине меняет некоторые из них (обычно связанные с безопасностью), но чего не должно быть, так это пространство имен uts (hostname). Итак, вот сценарий, использующий stat
и это с учетом имени процесса в аргументе "$ 1" (например: set -- inetd
или аргумент сценария) предоставит только процесс в том же пространстве имен uts, обычно означающий (тот же) хост.
pid1uts="$(stat -c %N /proc/1/ns/uts|cut -d' ' -f3)"
for i in $(pidof "$1"); do
if [ "$pid1uts" = "$(stat -c %N /proc/$i/ns/uts|cut -d' ' -f3)" ]; then
echo $i
fi
done | xargs -r
который в моем примере возвращает 3372
.
Я объяснил, как это сделать, но зачем изобретать велосипед, когда pgrep
есть варианты, чтобы справиться с этим:
# pgrep ^inetd$
3372
10285
# pgrep --ns 1 --nslist uts ^inetd$
3372
Или в большинстве случаев просто:
# pgrep --ns 1 ^inetd$
3372
если ваша служба на хосте прослушивает порт 80, вы можете определить идентификатор процесса с помощью netstats
#netstat -plan | grep :80
Процессы контейнера должны быть связаны с другим номером порта на хосте и внутри контейнера с портом 80. так что вы можете легко определить хост-процесс и убить его.