2017年2月13日 星期一

Docker 新手第二課: 前景/背景/收工休息 圖解狀態轉換

docker 基本指令 這篇觀念教學文是為略懂 docker 的讀者寫的。 你喜歡在你的 linux 電腦上試玩一些有的沒的; 但是不時會遇到一些軟體需要牽拖一大串三姑六婆相依套件, 擔心會把你的工作環境弄亂。 有時甚至還會有相依套件版本跟已安裝軟體不相容的問題。 你發現 docker 正好可以解決這個問題。 安裝好 docker、 對於 volume 跟 port 略有概念、 爬了一些文 [ 門外漢的 Docker 小試身手 三十分钟 Docker 新手入门]、 對 docker 已經有一些概念、 會用 docker ps -a 查看 (執行中或已收工的) docker instances、 用 docker images 查看已下載的映像檔。 但是對於 attach/interactive/terminal/... 又有點頭昏... 對於沒有立志要成為 docker 高手的人來說, 只需要再熟悉這張概念圖就夠了。 從此以後可以專心亂玩其他軟體, 不必再煩惱 docker 指令了! 同場加映不求專精工程師爬文後的一些小技巧及心得。

一、 前景/背景/收工休息

我自己最常使用 docker 的流程大致是這樣:

  1. 比方說想要玩引發 熱烈討論 (<= 好玩!) 的 「畫風轉移/混搭」 混圖魔法好了。 (另文討論) 得知它底層的類神經網路官網名稱是 neural-style; 但是懶得安裝一堆相依套件。
  2. 搜尋 「neural style docker」, 找到很多網友製作好的現成 docker 可用。 挑選一個有原始碼 (Dockerfile)、 文件清楚的版本, 例如 ffedoroff/neural-style
  3. 把 image 下載回自己的硬碟: docker pull ffedoroff/neural-style
  4. [B=>C] 啟動容器, 直接進入 bash (因為我是命令列控): docker run -ti --name nstyle -v /root/share:/out ffedoroff/neural-style bash 以下都假設我們這個 docker instance 叫做 nstyle; 當然你要打一長串的 16 進位數字 container ID 也可以。
  5. 在容器裡面啟動某個跑很久的指令, 等到不耐煩。
  6. [C=>D] (在容器裡面) 按 ^p ^q, 逃離容器, 但它還在背景裡繼續執行。
  7. 在 host 裡面做別的事, 隔一陣子忍不住又想看容器裡的指令的進度。
  8. [D=>C] 把容器帶到前景來: docker attach nstyle 可能需要多按一次 Enter, 才會出現提示符號。
  9. [C=>E]在容器裡面, 事情做完了, 收工: 按 ^d 容器結束執行, 回到 host。
  10. 下次 (甚至可能是重新開機過後) 又要執行同一個容器: [E=>C] 再次啟動 (既有的) 容器, 直接進入 bash: docker start -ai
  11. [C=>E] 事情做完了, 收工: 在容器裡面按 ^d
  12. 不滿意啟動容器時的參數 (例如想要重新調整 -v 所分享的目錄位置)。 [E=>X] 把容器燒毀! docker rm nstyle

以上狀態轉換的重點是標色的部分。 其中 ^p ^q^d 是在容器裡面按的; 其他 docker 指令都是在 host 裡面下的。

執行 run 時如果沒有給 -ti 的選項、 執行 start 時如果沒有給 -ai 的選項, 那麼容器就自動進入背景執行。 因為我看到 bash 才有安全感, 所以比較少這樣用。 不過其實也可以用 docker log nstyle 來查看背景執行的容器印了什麼東西出來。

二、 管理映像檔

如果對某個已下載的映像檔不滿意, 就用 docker rmi 映像名稱 把它刪掉。 相反地, 如果對某個映像檔很滿意, 可能會動手幫它加一些設定或套件。 不過你修改的是一個 (running) docker instance, 當它被 docker rm 時, 一切就隨風而去了。 如果想保留修改, 請先收工離開、 回到 host 底下, 執行 docker commit -m '註解加了什麼' -a '作者(自己)的聯絡資訊' nstyle ffedoroff/neural-style:m1 把修改過的 nstyle 寫入一個新的映像檔, 隨便取一個新的 tag (這裡取名為 m1), 這樣才會保留下來。 以後 run ... ffedoroff/neural-style:m1 就會執行你改過的 m1 版了。

如果硬碟空間快爆掉了, 可以參考 這個問答 把沒用的映像檔通通刪掉。

三、 撇步/常識/心得

以下是我一路上跌跌撞撞學到的雜七雜八知識跟技巧:

  1. 如果 run 的時候忘記取名字, 並不需要把它砍掉重練。 用 rename 就可改名。
  2. 想要讓 docker 內的時區與 host 一致, 可以用 -v /etc/localtime:/etc/localtime [ 來源]
  3. run 的時候, 可以有好幾組 -p (host 的哪些 ports 要借給容器的哪些 ports)、 好幾組 -v (host 的哪些目錄要讓容器看見)、 好幾組 -e (設定環境變數), 但是 所有的選項都必須放在 image 名稱之前, 不然會出現很奇怪看不懂的錯誤訊息。
  4. 如果嫌 ps 指令顯示的資訊太少, 可以用 docker inspect nstyle 查看一個 docker instance 詳細的資訊 => 不要問我, 從這裡再研究下去你已經超過我的程度了。

再來是 docker daemon 除錯與設定。 上網問問題之前, 最好先用 docker info 查看你的系統的 docker daemon 版本等等資訊, 並擇要貼上, 高手才幫得上忙。 有時還需要用 journalctl -u docker 查看 daemon 印的錯誤訊息。 有時高手會告訴你: 啟動 docker daemon 時要給某某選項。 根據 這個 issue, 在 ubuntu 16.04 底下, 你要修改的設定檔不是 /etc/default/docker 而是 /etc/docker/daemon.json 。 語法請見 Daemon configuration file 這一節。 (更精確但更囉嗦的做法請見 這裡。)

四、 安全考量及結論

  1. 不要在 docker 裡面安裝 ssh 服務!
  2. 用 「非 root 帳號」 執行 docker 比較安全嗎? 未必!
  3. 如果你的 commit 有一天有可能會 push 到 dockerhub 去分享, 請務必注意: 凡是遇到需要在 docker 裡面放密碼或金鑰等等私密資訊的情況, 要特別小心!

用了一陣子之後的心得: 基於安全性、 存活長短、 沒有 IP 位址等等因素, 如果沒有其他配套措施的話, 其實 docker 並不太適合直接讓網管拿來提供服務。 最適合用 docker 的, 真的就是我們這種愛亂玩軟體的家庭用戶無誤。 所以對於 docker, 我只學到夠用就好而已; 剩下的時間要拿去玩別的好玩東東啊!

1 則留言:

  1. 啊, 昨天才發現最近這幾篇的程式碼 <code>...</code> 部分都壞掉了 (哭) 因為我手殘, 存檔前多按了一個 (自訂的) 快速鍵, 把所有半型標點變成全形標點。 今天把它修好了。 可是先前都沒有讀者發現... 有點傷心啊~~

    回覆刪除