Dockerfile實踐

最近在玩OpenCV,順手build了一個OpenCV 3.2.0的Docker image。這個image是基於Ubuntu 16.04和OpenCV 3.2.0的source code build的,順帶也build進了Python3的綁定。這個image比較適合用來作為開發和測試基於OpenCV的服務端程序環境的base image。

由於包含了幾乎全部的OpenCV組件,build的過程還是比較費時的,image的尺寸也比較大,所以我將它push到了Docker Hub里。需要的話,可以用

docker pull chunliu/docker-opencv

把它拉下來使用。如果要精簡組件,或build別的版本的OpenCV,可以修改Dockerfile,重新build。

實際上我以前並沒有怎麼用過Docker,只在虛機中安裝過,順著Docker官方的tutorial做過,並簡單看過官方的幾篇doc,僅此而已。大概明白Dockerfile是怎麼回事,但沒有寫過很完整複雜的Dockerfile。事實證明,事非經過不知難,寫這個Dockerfile還是有一些坑的。

首先,要寫好這個Dockerfile,只靠記事本比較困難,使用輔助工具會容易一些。我用的是VS Code + Docker support,它能提供關鍵字著色和IntelliSense,也僅此而已。如果有工具能做語法檢查就更好了,比如檢查行尾是否少了一個續行符之類的。我開始幾次都是跑build失敗才發現,是某一行少了一個續行符。

另外,我沒發現有什麼好的方法,來debug和測試Dockfile。最開始,我是修改了Dockfile之後,就跑build,失敗再找原因。但是這個build比較費時,這樣不是很有效率。後來,我開始在一個container里,逐條跑Dockerfile里的命令,保證每條命令都沒問題,再跑build。這樣做的問題是,所有命令在一個bash session里跑成功了,並不能保證它們用RUN組織到Dockfile以後,build還能成功。

這就牽扯到Docker是怎麼執行這個RUN的問題了。Docker的文檔說,每一個RUN會是一個新的layer。我起初不太明白layer的含義,做過之後發現,所謂layer,就是一個中間狀態的container。RUN後面的代碼是在這個container里跑,跑完之後這個container被commit到image里,然後這個container被刪除。後面的RUN,會基於新commit的image,起一個新的container。

所以,如果兩段代碼需要在一個bash session里跑的話,就需要在一個RUN裡面才行。一個例子,比如build OpenCV的時候,會用下面的方式來make:

mkdir buildcd buildcmake ......make ......

如果將cd,cmake和make分開到不同的RUN中,那cmake和make就有問題了,因為工作路徑不對。實際上,RUN的工作目錄是由WORKDIR設定的,每個RUN開始時都會使用它上面最靠近它的WORKDIR作為工作目錄。所以如果非要將上面的代碼分開到不同的RUN,也可以在RUN之間插入WORKDIR來指定路徑,不過路徑跳來跳去的,比較混亂。

細讀Docker的兩篇官方文檔,對規避Dockerfile里的一些坑,是很有幫助的。

Reference

  • Dockerfile reference

  • Best practices for writing Dockerfiles

推薦閱讀:

Opencv學習筆記(1)
【小林的OpenCV基礎課 6】基本數學操作 初識掩膜
【opencv學習筆記六】圖像的ROI區域選擇與複製
在圖像處理中用Mat比IplImage 除了不用自己管理內存,Mat有其他的優勢沒?請熟悉OpenCV和圖像處理的大牛指點
OpenCV C++經典書籍和實戰項目

TAG:Docker | 集裝箱 | OpenCV |