都2020年了,居然還有人沒有在數據科學項目中使用Docker?
新手程序員面臨的困難的問題之一是理解“環境”的概念。環境就是你編寫代碼的系統,聽起來很容易,但很快你就會明白維護系統有多困難。
很大原因是庫和 IDE,甚至 Python 代碼本身都會經歷更新和版本更改,有時候,我們對一個庫進行更新,就會導致另一段代碼報錯。正因如此,我們經常需要修復各種來源不明的 BUG。
此外,如果我們同時開發多個項目,可能會出現依賴性沖突。如果一段代碼因為另一段代碼而出現 BUG 時,情況會更糟糕。
另外,如果你想將一個項目共享給一個在不同操作系統上工作的團隊成員,或者將你在 Mac 上構建的項目發送到另一個操作系統上的服務器,你是否需要重新配置代碼?很明顯是一定需要的。
因此,為了減少這些問題的出現,人們提出使用容器來分離項目和它們所在的環境。容器基本上是一個環境可以運行的地方,與系統中的所有其他東西分開。一旦定義了容器中的內容,就可以輕松地重新創建環境,甚至與同事共享項目。
要求
首先,我們需要安裝一些設置:
Windows或macOS:安裝Docker Desktop(https://www.docker.com/get-started)
Linux:先安裝Docker,再安裝 Docker Compose(https://docs.docker.com/compose/install/)
對Python服務進行容器化
假設我們正在創建一個名為 server.py 的 Flask 服務,并假設文件內容如下:
- from flask import Flask
- server = Flask(__name__)
- @server.route("/")
- def hello():
- return "Hello World!"
- if __name__ == "__main__":
- server.run(host='0.0.0.0')
如上所述,我們需要記錄代碼的依賴關系,因此,我們可以創建一個 requirements.txt 文件,其中可以包含以下要求:
- Flask==1.1.1
因此,我們的軟件包需要具有以下結構:
- app
- ├─── requirements.txt
- └─── src
- └─── server.py
該結構非常合理(源代碼保存在單獨的目錄中)。要執行我們的 Python 程序,只需安裝一個Python 解釋器并運行即可。
我們可以在本地運行該程序,但是假設我們正在處理 15 個項目:在容器中運行是有意義的,這樣可以避免與其他項目發生沖突。
讓我們進入容器化。
Dockerfile
要運行 Python 代碼,我們將容器打包為 Docker 映像,然后基于它運行一個容器。如下所示:
- 創建一個 Dockerfile,其中包含構建圖像所需的說明;
- 然后由 Docker builder 創建映像;
- 簡單的 docker run image 命令然后創建一個運行應用程序的容器。
分析 Dockerfile
Dockerfile 是一個文件,其中包含有關組裝 Docker 映像(保存為 myimage )的說明:
- # 設置基本映像(主機操作系統)
- FROM python:3.8
- # 在容器中設置工作目錄
- WORKDIR /code
- # 將依賴項文件復制到工作目錄中
- COPY requirements.txt .
- # 安裝依賴項
- RUN pip install -r requirements.txt
- # 將本地src目錄的內容復制到工作目錄
- COPY src/ .
- # 在容器啟動時運行的命令
- CMD [ "python", "./server.py" ]
Dockerfile 是逐行編譯的,因此構建器會生成圖像層并將其堆疊在先前的圖像上。
我們還可以在 build 命令的輸出中觀察到作為步驟執行的 Dockerfile 指令。
- $ docker build -t myimage .
- Sending build context to Docker daemon 6.144kB
- Step 1/6 : FROM python:3.8
- 3.8.3-alpine: Pulling from library/python
- …
- Status: Downloaded newer image for python:3.8.3-alpine
- ---> 8ecf5a48c789
- Step 2/6 : WORKDIR /code
- ---> Running in 9313cd5d834d
- Removing intermediate container 9313cd5d834d
- ---> c852f099c2f9
- Step 3/6 : COPY requirements.txt .
- ---> 2c375052ccd6
- Step 4/6 : RUN pip install -r requirements.txt
- ---> Running in 3ee13f767d05
- …
- Removing intermediate container 3ee13f767d05
- ---> 8dd7f46dddf0
- Step 5/6 : COPY ./src .
- ---> 6ab2d97e4aa1
- Step 6/6 : CMD python server.py
- ---> Running in fbbbb21349be
- Removing intermediate container fbbbb21349be
- ---> 27084556702b
- Successfully built 70a92e92f3b5
- Successfully tagged myimage:latest
然后,我們可以看到映像位于本地映像存儲目錄中:
- $ docker images
- REPOSITORY TAG IMAGE ID CREATED SIZE
- myimage latest 70a92e92f3b5 8 seconds ago 991MB
在開發過程中,我們希望花費盡可能少的時間,為 Python 服務重建映像。
注意:Docker 和 virtualenv 非常相似但又有所不同。Virtualenv 只允許我們在 Python 的依賴關系之間切換,無法使用主機操作系統。但是,使用Docker,你可以在任何操作系統上交換整個操作系統:安裝并運行Python(例如 UBTUN,Debian,Alpine,甚至Windows Server Core)。因此,如果你的團隊工作需要驗證你的技術,請使用Docker。如果不需要,可以使用 venv。
總結
在上文中,我們展示了如何把 Python 服務容器化。 希望此過程將變得更容易,并且能夠為你的項目提供更長的保質期。同時,因為依賴關系的變化,也能降低你的代碼錯誤的可能性。