在筆記本上主要還是想以輕量、方便為主,所以采用的是在WSL2中使用docker的這么一個方案。
WSL2
我筆記本原來是預裝的是WIN10家庭版,需要先升級為專業版,并加入windows預覽體驗計劃。更新完之后,安裝WSL,我選擇的是Ubuntu16.04,并且升級到WSL2[1],就可以支持docker了。
在WSL2中安裝docker-ce[2]。因為WSL2中沒法正常的使用systemctl,我參考了韋易笑的文章[3]對docker做了自啟動。
Why docker?
- 環境隔離,相當于輕量級的虛擬機
- 可更新、可擴展,一次配置,到處享用
- 一鍵部署
鏡像與容器
鏡像與容器是我們接觸得最多的東西和基本的概念。鏡像是一個只讀的模板,它可以包含一個完整的linux系統、軟件和其它運行環境。docker利用容器來運行應用,容器是鏡像的運行實例,每個容器都是相互隔離的。
Hello world
我們從hello-world,來看看docker運行容器的流程。
安裝完docker后,為了不用每次運行docker命令都需要加上sudo,需要先將用戶加入docker用戶組:sudo adduser $USER docker
。然后登出賬戶,再登陸即可。
完了我們運行docker官方的hello-world,看看能否正常運行:docker run -rm hello-world

這條命令的意思是,從hello-world
鏡像創建一個容器并運行容器。
容器被創建后,可以啟動(start)和停止(stop),不需要之后可以刪除。一個容器在程序運行完成后會自動停止,但是容器不會被自動刪除。--rm
參數是讓容器運行完成、停止后自動刪除該容器。 我們可以通過docker ps -a
命令查看已存在的容器。
從圖中第二、三行可以看到,docker在從鏡像創建容器時,首先會查找本地鏡像。當本地查找不到時,會從倉庫查找。這里的倉庫概念和github、maven的倉庫概念類似,默認是從官方的dockerhub查找,可以自行添加其它鏡像源。
此外,我們運行nginx測試一下在容器中運行web服務,執行命令docker run nginx
。我們可以通過localhost來訪問WSL2中的服務:


創建開發環境
一般情況下,我們不需要自己從頭制作一個鏡像,可以在別人做好的鏡像上進行二次制作。以python的flask程序為例,可以把python3.6的鏡像作為基礎鏡像:docker pull python:3.6

其中冒號后面的3.6是tag,如果不加tag的話默認是latest。
然后從該鏡像中運行一個容器實例:docker run -it --name="flask" python:3.6 /bin/bash

可以看到,其實容器內是有一個完整的文件系統的,并且容器內安裝好了python 3.6.10。 關于命令,-i是以交互的形式運行容器,-t是為其分配一個偽輸入終端,--name="flask"則是為該容器創建一個別名。之后我們可以用docker start/stop flask
之類的命令來啟動或停止該容器。
接著我們在容器容器內的根目錄創建一個名為app
的文件夾(后來發現不用手動創建),為的是之后將宿主機(WSL2)的目錄直接映射到docker容器中,就省去了將宿主機的代碼傳到docker容器這個步驟。并且這種方式對安全、以及數據持久化來說都有幫助。
然后根據需要,在容器內安裝flask:pip install flask
,并用docker commit 4f6 eagle/flask
命令保存新的鏡像。4f6是容器的id,和git的版本號有些類似,后面是新鏡像的名字。可以看到,由于安裝flask,鏡像的尺寸也比原來大了一些。


這樣我們開發環境的鏡像就創建完成了,接下來要測試一下是否可行。先刪除之前的容器或者運行容器時指定其它的別名,然后使用命令創建新的容器:
docker run -it --name="flask" -p 5555:2333 -v /home/eagle:/app eagle/flask /bin/bash
其中-p 5555:3333
是將宿主機的5555
端口映射到容器的2333
端口,-v /home/eagle:/app
則是將宿主機的目錄映射到容器的app
目錄。
接著寫一個簡單的flask測試程序,來看看這個容器是否能否充當開發環境。在宿主機創建app.py
文件并寫入以下代碼:
from flask import Flaskapp = Flask(__name__)@app.route('/')
def hello():return 'flask in docker'if __name__ == '__main__':app.run(host='0.0.0.0', port=2333)
在docker容器中運行python app.py
啟動flask服務,并在瀏覽器中查看結果:


環境移植
接下來我們要考慮如何把自己制作好的鏡像移植到別的機子上,做到“一次配置,到處享用”。很簡單,導出鏡像和導入鏡像只需要:
docker save eagle/flask > flask-docker-image.tar.gz
docker load < flask-docker-image.tar.gz
但是,我們的問題不在于此。從前面可以看到,我們制作好的鏡像足足有900+MB那么大,能不能有什么辦法可以使鏡像小一些呢?
答案是肯定的!那就是使用alpine版本的python鏡像。alpine[4]是一個超輕量級的linux系統,只有5MB的大小,而dockerhub[5]上也提供了python的alpine版本鏡像。
運行命令docker pull python:3.6-alpine
下載鏡像,然后對比一下幾個鏡像的大小,可以看到這個鏡像也只有95MB,僅占原來的十分之一:

即使安裝了flask,也才105MB,并且程序可以正常運行,測試過程和結果和之前差不多,就不贅述了。
另外我這里采用的是在容器中安裝依賴和用目錄映射,做開發環境的搭建。至于制作鏡像和鏡像瘦身,還有別的方法[6],等我實際用到的時候再把這部分的坑填了吧。
結語
docker提供的容器化方案為我們日常的開發和部署提供了很大的便捷,所以受到許多人的青睞。但是做機器學習的話,還需要考慮到調用顯卡這回事,目前Nvidia官方也提供了nvidia-docker這么個東西。因筆記本沒有顯卡,無法測試,日后也會把這部分的坑填上,判斷其是否能作為日常開發的環境。
參考
- ^如何在 Windows 10 中安裝 WSL2 的 Linux 子系統?https://blog.csdn.net/WPwalter/article/details/101508601
- ^Docker Ce | 鏡像站使用幫助 | 清華大學開源軟件鏡像站 | Tsinghua Open Source Mirror?https://mirrors.tuna.tsinghua.edu.cn/help/docker-ce/
- ^WSL服務自啟動的正確方法?https://zhuanlan.zhihu.com/p/47733615
- ^Docker之操作系統Alpine_菲宇運維-CSDN博客?https://blog.csdn.net/bbwangj/article/details/81088231
- ^python - Docker Hub?https://hub.docker.com/_/python/
- ^Docker Layers Explained - DZone Cloud?https://dzone.com/articles/docker-layers-explained