目錄git
做者:楊冬 歡迎轉載,也請保留這段聲明。謝謝!
出處:https://andyyoung01.github.io/ 或 http://andyyoung01.16mb.com/github
如何正確地構建Docker鏡像,對於正確使用Docker是很是關鍵的。若是你想要定義容器須要運行的命令,而將命令行參數留給用戶提供,則使用Dockerfile中的ENTRYPOINT命令是十分方便的。docker
做爲演示,咱們假設一個簡單的場景:公司的服務器須要按期清理舊的日誌文件。這雖然是一個簡單的管理任務,可是很是容易出錯,管理員可能會不當心刪除了錯誤的文件。因此可使用一個Docker鏡像來包裝管理員運行的命令,下降這種問題出現的風險。
下面這段腳本刪除/log_dir目錄中久於某天的日誌,天數做爲命令行參數傳遞進來:shell
clean_logubuntu
1數組 2bash 3服務器 |
#!/bin/bashapp echo "Cleaning logs over $1 days old"ui find /log_dir -ctime "$1" -name '*log' -exec rm {} \; |
下面在與上面腳本相同的目錄下建立Dockerfile,以上面的腳本做爲entrypoint
:
1 2 3 4 5 |
FROM ubuntu:14.04 ADD clean_log /usr/bin/clean_log RUN chmod +x /usr/bin/clean_log ENTRYPOINT ["/usr/bin/clean_log"] CMD ["7"] |
上面代碼第2行將前面的腳本添加進鏡像;第4行定義了鏡像的默認執行的腳本命令;第5行定義了默認腳本命令的參數(7天)。
ENTRYPOINT
和CMD
的最佳實踐——老是使用數組形式的寫法:若是你常常在Docker Hub上查看別人的Dockerfile,會發現數組模式(例如 CMD [「/usr/bin/command」])會比shell模式用得更多(CMD /usr/bin/command)。這是由於shell模式會自動在你提供的命令前面添加一個/bin/bash -c命令,這可能會致使意外的結果。不過有時shell模式更加有用。
使用以下命令構建鏡像:
$ docker build -t log-cleaner .
ENTRYPOINT
和CMD
的區別常常令人迷惑。理解的關鍵點是知道當一個鏡像啓動時,entrypoint老是被執行,即便在docker run
命令後指定了鏡像要運行的命令。若是是這樣的話,這個命令會被認爲是entrypoint的參數,替換掉CMD中的默認參數。
例如上面構建的鏡像,若是這樣運行docker run -it log-cleaner /bin/bash
的話,並不會執行bash,而是將/bin/bash做爲參數傳遞給腳本(這裏替換掉了默認的7這個參數)。系統會提示錯誤的參數:
1 2 3 |
$ docker run -it log-cleaner /bin/bash Cleaning logs over /bin/bash days old find: invalid argument '-name' to '-ctime' |
正確的使用方法以下:
$ docker run -v /var/log/myapplogs:/log_dir log-cleaner 365
上述命令將/var/log/myapplogs目錄掛載到容器內部的腳本指定的目錄,而且以365做爲參數傳遞給腳本,使365天之前的日誌文件被刪除。