docker entrypoint入口檔案詳解
參考ofollow,noindex">https://www.cnblogs.com/breezey/p/8812197.html
在編寫Dockerfile的時候,包含一個entrypoint配置,該配置的作用是在容器啟動之前做一些初始化配置,或者一些自定義的配置等。通常是一個指令碼,然後在腳本里配置相關預定義項。這篇文件就詳細說一說entrypoint入口檔案的編寫技巧。
下面以mysql官方映象中的entrypoint檔案docker-entrypoint.sh為例,檔案地址為:
docker-entrypoint.shset -e
你寫的每個指令碼都應該在檔案開頭加上set -e
, 這句語句告訴bash如果任何語句的執行結果不是true則應該退出. 這樣的好處是防止錯誤像滾雪球般變大導致一個致命的錯誤, 而這些錯誤本應該在之前就被處理掉. 如果要增加可讀性, 可以使用set -o errexit
, 它的作用與set -e
相同
set -o pipefail
設計用途同上, 就是希望在執行錯誤之後立即退出, 不要再向下執行了. 而 -o pipefail 的作用域是管道, 也就是說在 Linux 指令碼中的管道, 如果前面的命令執行出了問題, 應該立即退出
shopt -s nullglob
在使用 Linux 中的萬用字元時* ?
等 如果沒有匹配到任何檔案, 不會報 No such file or directory 而是將命令後面的引數去掉執行
if [ "${1:0:1}" = '-' ]; then...
這是一個判斷語句, 在官方檔案中, 上一行已經給出了註釋:if command starts with an option, prepend mysqld
這個判斷語句是${1:0:1}
意思是判斷$1
(呼叫該指令碼的第一個引數), 偏移量0(不偏移), 取一個字元(取字串的長度)
如果判斷出來呼叫這個指令碼後面所跟的引數第一個字元是-中橫線的話, 就認為後面的所有字串都是 mysqld 的啟動引數
上面的這個操作類似於 Python 的字串切片
set -- mysqld "$@"
在上面判斷完第一個引數是-開頭之後, 緊接著就執行了 set -- mysqld "$@" 這個命令,使用了 set -- 的用法。
set -- 會將他後面所有以空格區分的字串, 按順序分別儲存到$1
,$2
,$3
變數中, 其中新的$@為set --後面的全部內容
舉例來說:bash docker-entrypoint.sh -f xxx.conf
在這種情況下,set -- mysqld "$@"
中的 $@ 的值為-f xxx.conf
當執行完set -- mysqld "$@"
這條命令後:
$1=mysqld $2=-f $3=xxx.conf $@=mysqld -f xxx.conf
可以看到, 當執行 docker-entrypoint.sh指令碼的時候後面加了 -x形式的引數之後,
@值的基礎之上, 在前面又預添加了 mysqld 命令
exec "$@"
幾乎在每個docker-entrypoint.sh
指令碼的最後一行, 執行的都是exec "$@"
命令
這個命令的意義在於你已經為你的映象預想到了應該有的呼叫情況, 當實際使用映象的人執行了你沒有預料到的可執行命令時, 將會走到指令碼的這最後一行, 去執行使用者新的可執行命令
情況判斷
上面直接說了指令碼的最後一行, 在之前的指令碼中, 需要充分的去考慮你自己的指令碼可能會被呼叫的情況. 還是拿 SQL/">MySQL 官方的 dockerfile 來說, 他判斷以下情況:
- exec "$@"
${mysql[@]}
Shell 中的陣列, 直接執行${mysql[@]}
會把這個陣列當做可執行程式來執行
mysql=( mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" ) echo ${mysql[1]} -- output: mysql echo ${mysql[2]} --output: --protocol=socket echo ${mysql[3]} --output: -uroot echo ${mysql[4]} --output: -hlocalhost echo ${mysql[@]} --output: mysql --protocol=socket -uroot -hlocalhost --socket=
exec gosu mysql"$BASH_SOURCE" "$@"
這裡的 gosu 命令, 是 Linux 中 sudo 命令的輕量級”替代品”
gosu 是一個 golang 語言開發的工具, 用來取代 shell 中的 sudo 命令. su 和 sudo 命令有一些缺陷, 主要是會引起不確定的 TTY, 對訊號量的轉發也存在問題. 如果僅僅為了使用特定的使用者執行程式, 使用 su 或 sudo 顯得太重了, 為此 gosu 應運而生.
gosu 直接借用了 libcontainer 在容器中啟動應用程式的原理, 使用 /etc/passwd 處理應用程式. gosu 首先找出指定的使用者或使用者組, 然後切換到該使用者或使用者組. 接下來, 使用 exec 啟動應用程式. 到此為止, gosu 完成了它的工作, 不會參與到應用程式後面的宣告週期中. 使用這種方式避免了 gosu 處理 TTY 和轉發訊號量的問題, 把這兩個工作直接交給了應用程式去完成