Linux

Bash 腳本入口點 (PID=1) 僅在存在虛假陷阱(不執行任何操作)時才會殺死“tail”子程序

  • August 30, 2017

我在我的Bash腳本中遇到了一個奇怪的行為,我有這個Bash正在執行的腳本PID 1(它是一個entrypointforDocker容器,如果你不熟悉 Docker,我假設你可以忽略這個資訊)。

當我執行以下腳本時,SIGTERM一切都很快終止,一切似乎都很好(請記住,sshd服務不存在!我的整個系統只啟動了這個腳本,它不再執行tail,但直到現在它不是問題) .

#!/bin/bash

trap "pkill sshd" SIGTERM

export PATH=/usr/local/samba/bin/:/usr/local/samba/sbin/:$PATH

if [ -f /usr/local/samba/etc/smb.conf ]; then
       exec /usr/local/samba/sbin/samba -i
else
       tail -f /dev/null & wait ${!}
fi

當我刪除它時,問題就來了trap。現在我的系統掛了,似乎是因為tail還在執行,並且由於某種原因沒有結束(如果你熟悉Docker,Docker會等待10秒,然後殺死容器,因為它沒有響應SIGTERM,再次如果您不熟悉 Docker,請忽略此資訊)。

#!/bin/bash

export PATH=/usr/local/samba/bin/:/usr/local/samba/sbin/:$PATH

if [ -f /usr/local/samba/etc/smb.conf ]; then
       exec /usr/local/samba/sbin/samba -i
else
       tail -f /dev/null & wait ${!}
fi

有人可以向我解釋到底是什麼問題嗎?為什麼那個假貨trap能讓一切正常工作(雖然它實際上什麼也沒做,但它確實有效,因為它就在那裡)。

我仍然想提一下,使用空的trap:trap "" SIGTERM沒有幫助,陷阱中應該有一些東西可以工作(即使它什麼都不做)。

希望有人能幫助我,謝謝!

實際上t在執行容器時添加參數(分配tty)可以解決問題。我用-d參數執行它,現在用-td.

我不知道為什麼,但它做到了。如果有人能解釋為什麼會發生這種情況,那就太好了。

您沒有提供您的Dockerfile,也不清楚您如何將SIGTERM信號發送到容器。

但是,這是我試圖重現您的問題的方法:

我的Dockerfile

FROM ubuntu
ADD ./entrypoint.sh /opt/entrypoint.sh
# Using the exec form here, so that the process is assigned PID 1.
ENTRYPOINT ["/opt/entrypoint.sh"]

建構容器:

$ docker build -f Dockerfile -t test_image .

每次更改入口點腳本時不要忘記重建容器。

使用以下命令執行容器:

$ docker run --rm -it --name test_trap test_image

現在,讓我們看看每次執行時發生了什麼。

1)使用腳本trap中的行:Bash

# The main process will receive SIGTERM, trap it and exit.
$ docker stop test_trap

# The main process will receive SIGTERM, trap it and exit.
$ docker kill -s=TERM test_trap

# The main process will receive SIGKILL and will be stopped immediately.
$ docker kill -s=KILL test_trap

2)沒有trap線:

# The main process will receive SIGTERM which will be ignored.
# After a grace period (10s by default) it will receive SIGKILL and will be stopped.
$ docker stop test_trap

# The main process will receive SIGTERM which will be ignored.
# Container will continue running.
$ docker kill -s=TERM test_trap

# The main process will receive SIGKILL and will be stopped immediately.
$ docker kill -s=KILL test_trap

原因是核心PID 1特別對待一個程序並且不會殺死接收SIGTERM信號的程序(以及SIGINT)。

有關此問題的更多資訊:

任何程序都可以為 TERM 註冊自己的處理程序,並在退出之前使用它們執行清理。如果程序沒有註冊自定義信號處理程序,核心通常會退回到 TERM 信號的預設行為:終止程序。

但是,對於 PID 1,核心在轉發 TERM 時不會回退到任何預設行為。如果您的程序沒有註冊自己的處理程序(大多數程序沒有),則 TERM 不會對程序產生影響。

來源 - https://engineeringblog.yelp.com/2016/01/dumb-init-an-init-for-docker.html

更新

我還不能發表評論,所以我會在這裡發表評論。這是同樣的PID 1問題。兩者都-d-td信號處理按預期工作:TERM被忽略,因為入口點程序被分配PID 1,而KILL終止程序。如果添加該trap行,則TERM信號將在兩種情況下都被擷取。如果由於任何原因它對您不起作用,那麼您應該發布您Dockerfile執行的確切命令並相應地更新您的問題。

引用自:https://serverfault.com/questions/869543