初嘗 Docker

lylandris發表於2017-01-21

前段時間整理 P4 到軟交換機( simple_switch )的編譯環境,由於一開始就覺得會有各種坑,就像用某些虛擬化技術來解決最基本的問題:可能要反覆重灌系統。

因為網易雲聽說了容器技術、也知道 docker 這個基於 lxc 的工具,就想著拿來用用看,但這個時候其實是把容器當作一個輕量級的虛擬機器去看待的。

看到 https://github.com/p4lang/switch 的 docker/Dockerfile 可以直接 build image,就開始嘗試:

首先遇到的問題是,網易雲的容器構建服務,無法 科學地 訪問 github,導致這個 Dockerfile 無法順利 build。於是就跑到阿里雲上面,使用海外構建功能進行嘗試,再一次失敗。原因是 bmv2 ( P4 的一個平臺模組)有個原始碼檔案有幾百K行。構建服務用的記憶體是 512M 使得 gcc 直接因為記憶體不足掛掉。接下來自己建立了一個 2G 記憶體的虛機,再“科學地”拉取程式碼後進行構建,完畢後第一個感受是映象好大、第二則是:這玩意兒怎麼用?

為了解決第一個問題,找了幾篇構建映象經驗方面的文章,同時閱讀了 docker 的文件,分清了 Dockerfile 和 shell 指令碼的區別。將自己建立的 Dockerfile 構建完畢後,著手解決第二個問題。p4lang/switch 的 docker/Dockerfile 構建完畢後,執行就自行退出,推送映象到網易雲後,啟動就報告執行失敗,參照了一下網易雲公共映象的 Dockerfile,原來是 要加一句話啟動 ssh -D 。至此,docker 被我用成了一個 虛擬機器。我可以 ssh 進去,在容器裡面起桌面、編譯自己的程式碼、跑 sample 等。同時,研究了特權模式對 host 裝置操作的許可權、 host kernel 的 capabilities 配置、卷的掛載等( https://github.com/lylandris/p4env )。但是,docker 究竟和 虛擬機器 有什麼區別呢?難道只是因為輕?同時,要加一句話啟動 ssh -D 也困惑著我,為什麼 p4lang/switch 專案倉庫中的 Dockerfile 沒有這句話?

再去閱讀 docker 文件,和一些 blog ,看到一句話,大意是:容器存在的生命週期就是主程式的生命週期。理解一下就是:任何映象中的打包的檔案都是為了這個主程式服務的,否則就不需要打包到映象中(也是精簡映象大小的原則);一個映象應該只幹主程式這一件事。回頭再研讀 ENTRYPOINT/CMD 兩個命令的使用方式,逐漸開始明朗了。網易雲在使用我之前構建的映象啟動容器的時候,因為 Dockerfile 中沒有指定 ENTRYPOINT/CMD,啟動的網頁上也沒去填寫 CMD 引數,所以其不知道起這個容器的目的是什麼,只好報告啟動失敗了。要加一句話啟動 ssh -D 是因為網易構建好的基礎映象認為大家需要遠端上去做一些基本的配置等,因此將 ENTRYPOINT 設定為 ssh -D。而我們在正常使用容器的時候,根本目的是期望其不會因為安裝 App 引入安裝一堆庫,使得多個 App 所依賴的庫出現打架、或者一個 App 解除安裝或升級的時候,不知道是否因為清理其原先依賴的庫版本導致其他 App 失效。也就是說,容器為每一個 App 打包了其執行環境,App 之間互不影響,App 升級也很簡便。同時,推匯出 App 的執行環境對於開發和運維變成了同一套,這也是為什麼容器和 DevOps 的發展相輔相成。

按照這個理解,p4lang/switch 的 Dockerfile 是將 switch 作為一個 App 交付給使用者。使用者看到的就是一個 switch。而對於我的需求,則是應該將 p4lang/p4c 這個編譯器打包成 App,用這個 App 編譯程式碼後,在呼叫 p4lang/bmv2 這個 App 執行試驗,而不是一股腦在一個映象中包含這兩個 App,然後把 ssh 打包成 App,遠端進去在容器內寫程式碼執行 sample。

想了一下以前曾經弄過的幾個需求,pandoc + latex 自動編譯文件的工具可以通過 docker 來解決當時配置環境的焦頭爛額。當然,先看看是不是已經有人把這個輪子在 hub.docker.com 公開了,要是有,就直接拿來主義了。

相關文章