文 | Vik Paruchuri
譯 | EarlGrey
推薦 | 編程派公眾號(hào)(ID:codingpy)
數(shù)據(jù)科學(xué)開(kāi)發(fā)環(huán)境配置起來(lái)讓人頭疼,會(huì)碰到包版本不一致、錯(cuò)誤信息不熟悉和編譯時(shí)間漫長(zhǎng)等問(wèn)題。這很容易讓人垂頭喪氣,也使得邁入數(shù)據(jù)科學(xué)的這第一步十分艱難。而且這也是一個(gè)完全不常見(jiàn)的準(zhǔn)入門(mén)檻。
還好,過(guò)去幾年中出現(xiàn)了能夠通過(guò)搭建孤立的環(huán)境來(lái)解決這個(gè)問(wèn)題的技術(shù)。本文中我們就要介紹的這種技術(shù)名叫Docker。Docker能讓開(kāi)發(fā)者簡(jiǎn)單、快速地搭建數(shù)據(jù)科學(xué)開(kāi)發(fā)環(huán)境,并支持使用例如Jupyter notebooks等工具進(jìn)行數(shù)據(jù)探索。
要使用Docker,我們要先下載含有相關(guān)包(package)和數(shù)據(jù)科學(xué)工具的鏡像文件。之后,我們可以通過(guò)該鏡像,在數(shù)秒之內(nèi)就啟動(dòng)一個(gè)數(shù)據(jù)科學(xué)開(kāi)發(fā)環(huán)境,免去了手動(dòng)安裝包的麻煩。這個(gè)環(huán)境,也被成為Docker容器(container)。容器解除了配置的問(wèn)題——當(dāng)你啟動(dòng)一個(gè)Docker容器后,它就已經(jīng)處于了良好的狀態(tài),所有的包都是可以正常運(yùn)轉(zhuǎn)的。
除了降低進(jìn)入數(shù)據(jù)科學(xué)的門(mén)檻之外,Docker還可以讓我們快速搭建擁有不同Python版本和安裝了不同包的孤立環(huán)境,不像虛擬環(huán)境(virtualenv)那樣還要重新安裝包。
在本文中,我們將介紹Docker的基礎(chǔ)知識(shí),如何安裝Docker以及如何利用Docker容器快速地在本地機(jī)器上搭建數(shù)據(jù)科學(xué)環(huán)境。
虛擬機(jī)
能夠創(chuàng)建虛擬機(jī)的軟件已經(jīng)問(wèn)世數(shù)十年,可以讓你在本地電腦上模擬其他的系統(tǒng)環(huán)境。舉個(gè)例子,即使你的電腦運(yùn)行的是windows操作系統(tǒng),你仍可以通過(guò)虛擬機(jī)運(yùn)行l(wèi)inux系統(tǒng)。這可以讓你在不重裝系統(tǒng)的前提下,使用Linux——也就是說(shuō),Linux系統(tǒng)是虛擬化運(yùn)行的,所以你可以從Windows系統(tǒng)訪問(wèn)虛擬機(jī)。基本上,你可以在點(diǎn)擊該軟件的程序圖標(biāo)之后,看到彈出的窗口中乃是一個(gè)Linux系統(tǒng)桌面。而虛擬機(jī)需要鏡像來(lái)啟動(dòng),也就是你必須先擁有一個(gè)目標(biāo)系統(tǒng)的鏡像,才能啟動(dòng)相應(yīng)的虛擬機(jī)。如果你想使用Linux,你使用的鏡像就得包含創(chuàng)建Linux環(huán)境所必須的全部文件。
容器
盡管虛擬機(jī)有諸多好處,例如能夠使在Windows平臺(tái)進(jìn)行Linux開(kāi)發(fā)成為現(xiàn)實(shí),但是也有著自身的缺陷。首先,虛擬機(jī)的啟動(dòng)時(shí)間很長(zhǎng),要消耗大量的系統(tǒng)資源。另外,在利用鏡像創(chuàng)建完虛擬機(jī)中,很難在安裝完所需要的包后,再將這個(gè)鏡像保存,創(chuàng)建為新的鏡像。而Docker提供的Linux容器,則通過(guò)讓多個(gè)孤立環(huán)境在同一臺(tái)機(jī)器上運(yùn)行,解決了這個(gè)問(wèn)題。你可以把容器看作是一種更快、更簡(jiǎn)單地使用虛擬機(jī)的方法。
但是,容器的使用卻有一點(diǎn)麻煩,而且管理和發(fā)布容器鏡像也不容易。作為開(kāi)發(fā)人員,我們希望能夠快速下載并啟動(dòng)一個(gè)擁有指定包和工具配置的數(shù)據(jù)科學(xué)環(huán)境。例如,你肯定會(huì)希望能快速啟動(dòng)一個(gè)安裝了Jupyter notebook、spark和pandas的容器。
Docker
Docker容器的里層包裹的是Linux容器(a layer over Linux containers),可以支持更簡(jiǎn)單地對(duì)容器進(jìn)行管理和發(fā)布。使用Docker,可以很容易地下載具備相應(yīng)包的鏡像,并且快速啟動(dòng)。另外,Docker是跨平臺(tái)的,支持包括mac、Windows和Linux等系統(tǒng)。
作為創(chuàng)建孤立Python環(huán)境的另一種方式,虛擬環(huán)境(virtual environment)也有這些優(yōu)勢(shì)。但是Docker相較于虛擬環(huán)境的主要優(yōu)勢(shì)有:
-
能夠快速啟動(dòng)。如果你想馬上就開(kāi)始進(jìn)行數(shù)據(jù)分析,使用Docker就免去了你等待各種包進(jìn)行安裝的時(shí)間。
-
配置測(cè)試無(wú)誤。很多時(shí)候,要正常安裝Python包會(huì),需要以安裝某些系統(tǒng)包為前提,并只有在進(jìn)行相應(yīng)設(shè)置后才能正常使用。如果設(shè)置不當(dāng),會(huì)引起一些很奇怪的錯(cuò)誤。但是使用Docker后,這些包就已經(jīng)配置好了,可以立即使用。
-
跨平臺(tái)一致性。Python中的包是可以跨平臺(tái)使用的,但是在Windows和Linux平臺(tái)下有些不同,而且還有部分依賴(lài)包無(wú)法在Windows中安裝。但是由于Docker容器運(yùn)行的都是Linux環(huán)境,所以它們是高度一致的。
-
能夠設(shè)置checkpoint并且進(jìn)行恢復(fù)。你可以往Docker鏡像中安裝包,然后將那個(gè)checkpoint下的環(huán)境創(chuàng)建成一個(gè)新的鏡像。這讓你能夠快速撤銷(xiāo)或者回滾配置。
運(yùn)行一個(gè)Docker鏡像,就相當(dāng)于創(chuàng)建了一個(gè)Docker容器。在本文中,我們?cè)谌萜髦羞\(yùn)行一個(gè)Jupyter notebook,然后通過(guò)瀏覽器界面來(lái)處理數(shù)據(jù)。
安裝Docker
第一步就是安裝Docker。Docker官方為Windows和Mac用戶(hù)提供了一個(gè)簡(jiǎn)便安裝過(guò)程的圖形界面安裝器。官網(wǎng)上可以找到每個(gè)操作系統(tǒng)的安裝指南。
-
Mac OS
-
Linux
-
Windows
在安裝時(shí),你需要使用shell命令提示符(shell prompt)。shell命令提示符(shell prompt)也被稱(chēng)為終端或命令行,是在你的機(jī)器上通過(guò)文本界面而非圖形界面運(yùn)行命令的一種方式。例如,你可以在Windows系統(tǒng)中雙擊記事本就可以打開(kāi)一個(gè)文本編輯器,也可以在Linux終端中輸入nano達(dá)到這個(gè)目的。Docker提供了一個(gè)預(yù)先配置好的shell,可以用來(lái)運(yùn)行Docker命令。請(qǐng)按照下面的方法操作:
Mac OS —— 從Launchpad中打開(kāi)Docker Quickstart Terminal程序。詳情見(jiàn)本篇文章。
Linux —— 打開(kāi)任意bash終端,就可以使用docker命令。Windows —— 雙擊桌面上的Docker QuickstartTerminal程序的圖標(biāo)。詳情見(jiàn)本篇文章。
下文在提到需要運(yùn)行Docker命令或輸入某個(gè)命令時(shí),你都需要使用這個(gè)shell命令提示符。
下載鏡像
下一步是下載你需要的鏡像。下面是我們網(wǎng)站(dataquestio)目前提供的數(shù)據(jù)科學(xué)開(kāi)發(fā)專(zhuān)用鏡像:
dataquestio/python3-starter
—— 這個(gè)鏡像已經(jīng)安裝好了Python 3, Jupyter notebook和許多其他流行的數(shù)據(jù)科學(xué)庫(kù),包括numpy,pandas,scipy,scikit-learn和nltk。
dataquestio/python2-starter
—— 這個(gè)鏡像已經(jīng)安裝好了Python 2, Jupyter notebook和許多其他流行的數(shù)據(jù)科學(xué)庫(kù),包括numpy,pandas,scipy,scikit-learn和nltk。
你可以通過(guò)輸入 docker pull IMAGE_NAME
命令,下載相應(yīng)的鏡像。如果你想下載dataquestio/python3-starter
這個(gè)鏡像,那么你需要在終端輸入docker pull dataquestio/python3-starter
命令。輸入這段命令后,程序會(huì)自動(dòng)從Docker Hub下載鏡像。Docker Hub與Github類(lèi)似,不過(guò)卻是Docker鏡像的一個(gè)中樞。它會(huì)將相應(yīng)的鏡像文件下載至你的本地機(jī)器,這樣你才能利用該鏡像創(chuàng)建容器。
新建一個(gè)文件夾
在本地創(chuàng)建一個(gè)文件夾,用于存放notebooks。這個(gè)文件夾中將儲(chǔ)存你所有的工作文件,并會(huì)持續(xù)存在于你的機(jī)器中,即使是你銷(xiāo)毀了docker容器。在這里,我們將創(chuàng)建下面這個(gè)文件夾, /home/vik/notebooks
。
運(yùn)行鏡像
鏡像下載完成后,你可以通過(guò) docker run
運(yùn)行該鏡像。我們還需要傳入一些選項(xiàng),確保鏡像配置正確。
-p 選項(xiàng)用于設(shè)置虛擬機(jī)的端口,讓我們可以在本地訪問(wèn)Jupyter notebook服務(wù)器。
-d 選項(xiàng)用于以detached模式運(yùn)行容器,也就是作為背景進(jìn)程運(yùn)行。
-v 選項(xiàng)讓我們指定在本地機(jī)器中使用哪個(gè)文件夾存儲(chǔ)notebook。
完整的運(yùn)行命令是類(lèi)似這樣的:docker run-d-p8888:8888-v/home/vik/notebooks:/home/ds/notebooks dataquestio/python3-starter
。
你應(yīng)該將 /home/vik/notebooks
更改為你用于存儲(chǔ)文件的地址。另外,應(yīng)該把dataquestio/python3-starter
更改為自己喜歡的docker鏡像。
執(zhí)行 docker run
命令將會(huì)創(chuàng)建一個(gè)Docker容器。這是與你的本地機(jī)器相隔絕的,也可以把它看作是一臺(tái)單獨(dú)的電腦。在容器內(nèi)部,會(huì)運(yùn)行一個(gè)Jupyter notebook服務(wù)器,并可以讓我們使用許多數(shù)據(jù)科學(xué)工具包。
另外, docker run
命令也會(huì)在終端打印出容器的編碼(container id ),在通過(guò)其他docker容器對(duì)該容器進(jìn)行修改時(shí),就必須要使用這個(gè)編碼。在下文中我們稱(chēng)該編碼為容器編碼。
查看notebook服務(wù)器
如果你的系統(tǒng)是Linux,那么下一步非常簡(jiǎn)單——只需要在瀏覽器中打開(kāi)localhost:8888,之后應(yīng)該就能看到運(yùn)行中的notebook。如果你使用的是Windows或OSX,之前也按照Docker官方安裝指南進(jìn)行了操作,并且安裝過(guò)程中使用了docker-machine,那么本地機(jī)器的名稱(chēng)是default,運(yùn)行 docker-machine ipdefault
命令就可以得知docker容器的ip。如果使用了其他的名字,例如dev,那在命令中將default替換為dev即可。接下來(lái),在瀏覽器中訪問(wèn)CONTAINER_IP:8888
就可以看到notebook(將CONTAINER_IP替換為你的容器編碼)。
創(chuàng)建一個(gè)notebook
到了這一步,你可以創(chuàng)建一個(gè)新的Jupyter notebook測(cè)試下這個(gè)孤立的開(kāi)發(fā)環(huán)境。試試輸入下面這個(gè)scikit-learn的例子:
-
from sklearn import datasets
-
from sklearn.cross_validation import cross_val_predict
-
from sklearn import linear_model
-
import matplotlib.pyplot as plt
-
%matplotlib inline
-
lr = linear_model.LinearRegression
-
boston = datasets.load_boston
-
y = boston.target
-
predicted = cross_val_predict(lr, boston.data, y, cv=10)
-
fig, ax = plt.subplots
-
ax.scatter(y, predicted)
-
ax.plot([y.min(), y.max()], [y.min(), y.max()], 'k--', lw=4)
-
ax.set_xlabel('Measured')
-
ax.set_ylabel('Predicted')
-
plt.show
添加數(shù)據(jù)文件
如果你想往開(kāi)發(fā)環(huán)境中添加數(shù)據(jù)文件,你有三個(gè)選擇。第一個(gè)選擇,就是將文件放在你之前創(chuàng)建用來(lái)存放notebook的文件夾中。你放那里的任何文件將可以自動(dòng)通過(guò)Jupyter notebook中訪問(wèn)。
第二種選擇就是使用 docker cp
命令。docker cp
可以從本地機(jī)器復(fù)制文件至容器中,反之亦然。假設(shè)你想拷貝/hom/vik/data.csv
文件至一個(gè)id為4greg24134的容器中,你可以輸入下面的命令:docker cp/home/vik/data.csv4greg24134:/home/ds/notebooks
。這會(huì)將data.csv
文件拷貝到容器中用于存放notebook的文件夾中。當(dāng)然,你可以選擇將文件放到容器中的任何地方,但是把它們放在存放notebook的文件夾忠厚,你就可以輕松地通過(guò)Jupyter notebook訪問(wèn)這些文件了。
第三個(gè)選擇就是使用Jupyter notebook首頁(yè)右上方的 upload
按鈕。這可以讓你選擇一個(gè)文件,并上傳到容器中用于存放notebook的文件夾中。
不管你使用哪種方法,要想在Jupyter notebook中加載文件,需要按照類(lèi)似下面的方式進(jìn)行:
-
import pandas
-
data = pandas.read_csv("data.csv")
復(fù)制容器中的數(shù)據(jù)文件
你可能會(huì)需要從容器中拷貝文件至本地機(jī)器。最容易的辦法就是把文件放置在 /home/ds/notebooks
文件夾中,這樣的話這些文件就會(huì)自動(dòng)映像到本地機(jī)器。
另一種方法也就是利用 docker cp
命令。假設(shè)你想從id為4greg24314的容器中,把/home/ds/notebooks/data.csv
文件拷貝至本地機(jī)器的/home/vik/
文件夾中,你可以輸入下面的命令:cp4greg24134:/home/ds/notebooks/data.csv/home/vik/data.csv
。
最后一種方法就是使用Jupyter界面中的download選項(xiàng)。在網(wǎng)頁(yè)模式下點(diǎn)擊一個(gè)不是notebook的文件,將會(huì)將其下載至本地。如果你已經(jīng)打開(kāi)了一個(gè)notebook,那么可以先點(diǎn)擊 File
,然后選中downloadas
就可以下載至本地。
安裝更多的工具包
如果你想在容器中安裝更多的工具包,你可以通過(guò)正常的bash命令行命令就可以實(shí)現(xiàn)。要想在容器中執(zhí)行這些命令,你需要運(yùn)行 dockerexec
命令。這個(gè)命令接受容器的id作為參數(shù),以及一個(gè)期望運(yùn)行的命令。例如輸入dockerexec-it4greg24134/bin/bash
將會(huì)在編碼為4greg24134的容器中開(kāi)啟一個(gè)shell命令提示符(shell prompt)。-it
選項(xiàng)確保我們?cè)谌萜髦写蜷_(kāi)了一個(gè)輸入會(huì)話,并且可以輸入命令。
在運(yùn)行 dockerexec
命令之后,你就會(huì)看到容器中的shell命令提示符(shell prompt)出現(xiàn)。容器此時(shí)正通過(guò)一個(gè)名為ds
的虛擬環(huán)境運(yùn)行Python程序,這個(gè)虛擬環(huán)境已經(jīng)是處于激活狀態(tài)的。
接下來(lái),只需要輸入 pip install PACKAGE_NAME
就可以安裝其他的工具包。例如,你可以使用pip install requests
來(lái)安裝requests。
當(dāng)你希望退出容器的shell終端時(shí),只需要輸入 exit
即可。
關(guān)閉docker容器
在完成數(shù)據(jù)處理工作之后,你就可以通過(guò) docker rm-f CONTAINER_ID
來(lái)停止docker容器。你應(yīng)該輸入之前獲得的容器編碼。如果你忘了,你可以運(yùn)行docker ps
查看。容器停止運(yùn)行之后,notebooks會(huì)繼續(xù)存放在你本地用于存放的文件夾中。
更進(jìn)一步
Docker鏡像是通過(guò)Dockerfile創(chuàng)建的。Dockerfile指定了鏡像中應(yīng)該安裝的包和工具。通過(guò)修改Dockerfile,你就可以改變鏡像默認(rèn)按照的包和工具。
如果你想在本文中所使用的鏡像基礎(chǔ)上做一定修改,可以向我們的Github倉(cāng)庫(kù)提交PR,這個(gè)倉(cāng)庫(kù)中包含了鏡像的Dockerfile。我們歡迎大家參與改善當(dāng)前的鏡像,或是添加其他安裝了非Python包和工具的鏡像。