O script de inicialização do apache2 faz uma pidof
verificação para detectar se o apache já está em execução.
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".
(Arquivo: /etc/init/apache2 no Ubuntu 16.04.3 LTS - truncado por questões de brevidade)
No entanto, em um host docker, os contêineres de VM já podem ter o apache neles. Nesse caso, pidof
retorna não vazio, mesmo que não haja nenhum apache em execução no host.
$ sudo service apache2 stop
$ pidof apache2
32742 32480 32379 32365 31295 31294 31293 31292 31291 31274 31270
Isso significa que o script init é bem-sucedido apenas quando todos os contêineres do docker com apache pararam (ou ainda não foram iniciados). Consequentemente, o apache no host não pode ser restart
editado.
Como corrigir essa situação para que o apache do host possa ser reiniciado independentemente das VMs? Existe uma versão pidof
que detecte apenas pids pertencentes diretamente ao init?
Pena que há um
# can't use pidofproc from LSB here
no script de inicialização, sem explicação real. Eu ainda consideraria este script apache2 como tendo um bug digno de um relatório.TL;DR: solução: substitua
pidof apache2
porpgrep --ns 1 ^apache2$
(ou se isso não funcionar,pgrep --ns 1 --nslist uts ^apache2$
)Uma longa explicação sobre namespaces com um exemplo que escrevi antes de encontrar
pgrep
poderia fazer o seguinte:Uma vez que você tenha os "candidatos" usando
pidof
, aqui está um método para separá-los: verifique seus namespaces e compare-os com os namespaces depid 1
(init/systemd). Exemplo de usolxc
einetd
processo, mas esta é a tecnologia do contêiner e o nome do processo:Aqui é claramente visível que os namespaces dos
pid 3372
compartilhamentos . está sendo executado no host. não compartilha nenhum namespace (ok user é o mesmo: container run como root), então está em um container. É possível que, às vezes, algum programa em execução no host tenha alguns deles alterados por algum motivo (geralmente relacionado à segurança), mas o que não deveria é o namespace uts (hostname). Então aqui está um script usando e que dado o nome do processo em arg "$1" (por exemplo: ou o argumento de um script) fornecerá apenas o processo no mesmo namespace uts, geralmente significando o (mesmo) host.pid 1
3372
10285
stat
set -- inetd
que no meu exemplo, retorna
3372
.Expliquei como fazer, mas por que reinventar a roda quando
pgrep
tem opções para lidar com isso:Ou para a maioria dos casos apenas:
se o seu serviço no host estiver ouvindo na porta 80, você poderá descobrir o ID do processo com netstats
os processos do container devem ser vinculados com outro número de porta no host e internamente no container com 80 portas. para que você possa facilmente descobrir o processo do host e eliminá-lo.