原英文網址:http://ropenscilabs.github.io/r-docker-tutorial
這是專門爲具有 R 和 RStudio 知識的朋友設計的 Docker 教程。該介紹旨在幫助需要 Docker 進行項目的人們。我們首先解釋 Docker 是什麼以及爲什麼有用。然後,我們將詳細介紹如何將其用於可複製的分析項目。
準備
在開始之前,請根據自己的操作系統安裝下面的鏈接的介紹安裝 Docker
第一課:什麼是 Docker?爲什麼我應該使用它?
學習目標
- 理解 Docker 的基本思想
- 明白爲什麼 Docker 非常有用
爲什麼我想要使用 Docker?
想象一下,你正在 R 中進行分析,然後將代碼發送給朋友。 你的朋友在完全相同的數據集上運行此代碼,但結果略有不同。 這可能有多種原因,例如操作系統不同,R 軟件包的版本不同等。 Docker 可以解決這樣的問題。
可以將Docker容器視爲你計算機內部的一臺計算機。 這個虛擬計算機的妙處在於你可以將其發送給你的朋友。 當他們啓動計算機並運行你的代碼時,他們將獲得與你完全相同的結果。
簡單來說,你因爲下面的一些原因使用 Docker:
- 封裝所有依賴
- 分析可重複
還有一些 Docker 可以發揮用處的地方:
- 可移植性:由於 Docker 容器可以輕鬆地發送到另一臺機器,因此你可以在自己的計算機上設置好所有內容,然後在更強大的機器上運行分析。
- 可共享性:你可以將 Docker 容器發送給任何知道如何使用 Docker 的人。
基本詞彙
下面會經常出現鏡像和容器這兩個詞。映像的實例稱爲容器。映像是虛擬計算機的設置。如果運行此映像,將擁有它的一個實例,我們將其稱爲容器。可以有多個運行相同映像的容器。
第二課:在 Docker 中啓動 RStudio
學習目標
- 在 Docker 中啓動 RStudio
- 將磁盤與 Docker 鏡像鏈接
- 載入容器
安裝
首先參考 install Docker 進行安裝,沒有必要完成鏈接中所有的教程,有需要再回看它們。
在 Docker 中啓動 RStudio
要啓動 Docker,我們需要做的第一件事是打開一個 Unix Shell。如果你在 Mac 或 Windows 上,在最後一步,你安裝了一個叫做Docker快速啓動終端;現在打開它——它看起來應該像一個普通的 shell 提示符(~$
),但實際上它指向的是一個 Docker 默認運行的 linux 虛擬機,而在本教程的其餘部分,除非另有說明,你應該在這裏完成所有操作。如果您在 linux 機器上,那麼您可以使用普通的舊終端提示符。
在 Mac上,你也可以選擇終端並配置 Docker。特別是如果你得到錯誤不能連接到Docker守護進程。Docker 守護進程在此主機上運行嗎?。在教程的某個時候,運行下面的命令可能會解決你的問題:
eval "$(docker-machine env default)"
接下來,我們將要求Docker運行一個已經存在的映像,我們將使用來自 Rocker 的 verse Docker映像,它將允許我們在容器內運行RStudio,並且已經安裝了許多有用的R包。
docker run --rm -p 8787:8787 -e PASSWORD=yourpassword rocker/verse
--rm
、-p
和 -e
是允許你自定義如何運行容器的標誌。-p
告訴 Docker 你將使用一個端口在你的瀏覽器中看到 RStudio(在一個位置,我們隨後指定爲端口 8787:8787
)。—rm
確保當我們退出容器時,容器被刪除。如果我們不這樣做,每次我們運行一個容器,它的一個版本將被保存到我們的本地計算機。這最終會導致大量磁盤空間的浪費,直到我們手動刪除這些容器。稍後,我們將向你展示如何保存容器(如果你想這樣做的話)。最後,-e
將 PASSWORD
環境變量設置爲 yourpassword
。在堆棧中運行帶有RStudio的容器時,Rocker 需要你設置密碼。出於安全考慮,我們建議你將 yourpassword
更改爲您自己獨特的字符串。
如果你嘗試運行一個沒有在本地安裝的 Docker 容器,那麼Docker會自動在Docker Hub(一個在線的Docker 鏡像存儲庫)上搜索該容器,如果它存在,就下載它。
上面的命令將導致 RStudio-Server 不可見地啓動。要連接到它,打開一個瀏覽器,輸入http://
,然後加上你的 ip 地址,再加上:8787
。如果您運行的是 Mac 或 Windows 機器,您將在啓動 Docker Quickstart終端時出現在終端中的第一行文本中找到 ip 地址。例如,你應該會看到:
## .
## ## ## ==
## ## ## ## ## ===
/"""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\_______/
docker is configured to use the default machine with IP 192.168.99.100
For help getting started, check out the docs at https://docs.docker.com
你應該在瀏覽器中鍵入 URL http://192.168.99.100:8787
。
如果你在一臺 Linux 機器上運行,你可以使用 localhost
作爲 ip 地址,例如:http://localhost:8787
這將會將你導向 RStudio 登錄界面,使用下面的信息登錄:
username: rstudio
password: password
(上面你設置過這個東西)
現在你就可以在瀏覽器中使用 RStudio 工作了,就像你使用 Rstudio 桌面版一樣。
下面是一個截圖示例:
現在試試運行下面的代碼吧:
# make x the numbers from 1 to 5, and y the numbers from 6-10
x <- 1:5
y <- 6:10
# plot x against y
plot(x, y)
因爲我們剛纔啓動鏡像時使用了 --rm
標記,所以在這個機器上創建的任何東西在關閉後都會消失。你可以試試將上面的代碼保存爲一個文件,然後關閉瀏覽器,在終端上用 Control+C 關掉容器,然後重新啓動容器,看是否創建的文件是否依然存在。
將磁盤與 Docker 鏡像連接以便於訪問和保存數據文件
既然數據文件會消失,那麼我們退出容器後該如何保存我們的工作呢?一個解決的辦法是將一個磁盤(例如你的本地硬盤)與一個容器連接起來,這樣你就可以在本地磁盤上訪問和保存數據了。
這一次當我們啓動容器時使用 -v
標記指定我們項目的根目錄,如下所示(你的目錄可能有所不同),:
左邊是你本地計算機的路徑,右邊是容器裏的路徑,一般以 /home/rstudio/
開始(這個鏡像已經默認創建了用戶名 RStudio 和進行了相關配置)。
docker run --rm -p 8787:8787 -v /Users/tiffanytimbers/Documents/DC/r-docker-tutorial:/home/rstudio/r-docker-tutorial rocker/verse
再一次地,在你的瀏覽器進行 RStudio。
這一次你在 Docker 容器中啓動 RStudio 後,你可以查看到下面映射的文件目錄。然後就可以載入數據進行分析工作了:
# load gapminder data from a csv on your computer
gap5yr <- read.csv(file = 'data/gapminder-FiveYearData.csv')
畫一個分析圖:
# load ggplot library
library(ggplot2)
# plot GDP against life expectancy
qplot(gap5yr$lifeExp, gap5yr$gdpPercap)
# save the plot
ggsave(filename = 'data/GDP_LifeExp.pdf')
讓我們將腳本保存爲 plot_GDP_LifeExp.R
,然後關閉容器,看在本地目錄下是否能看到腳本和繪圖文件。
小結
這一課我們學習瞭如何通過容器在瀏覽器中運行 RStudio。學習了 --rm
標誌的作用和如何連接磁盤文件。
第三課:安裝 R 包
在 RStudio 內安裝 R 包
這跟我們使用 RStudio 桌面版沒什麼區別,試試運行:
# install package
install.packages('gapminder')
# load library
library(gapminder)
# peek at data
head(gapminder)
太好了!現在我們已經安裝好包並可以進行工作。但是等等,如果我們退出了容器會發生什麼?安裝的包會被刪除,因爲我們沒有保存這個版本的 Docker 鏡像。我們需要創建一個鏡像,這樣當利用它創建一個新的容器時,gapminder
包也已經安裝好了,可以直接使用。
爲了做到這一點,我們需要運行 docker commit
(類似 git commit
)保存修改。記住,這個操作需要在關閉容器前運行,一般我們另外打開一個終端進行這個操作。
我們可以使用下面的命令進行查看(類似 linux ps
命令):
docker ps
輸出應該類似下面展示,哈希值記錄了容器 ID:
4a6a528b35da rocker/verse "/init" 2 minutes ago Up 2 minutes 0.0.0.0:8787->8787/tcp silly_meninsky
現在我們在新的終端中運行下面命令,並記錄修改信息:
docker commit -m "verse + gapminder" 4a6a528b35da verse_gapminder
-m
指定修改信息,哈希值指定了我們要保存的容器,verse_gapminder
爲保存的鏡像設定了一個名字。
現在我們的電腦上就有 2 個鏡像了:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
verse_gapminder latest bb38976d03cf 57 seconds ago 1.955 GB
rocker/verse latest 0168d115f220 3 days ago 1.954 GB
現在你可以測試下新鏡像的工作情況。
安裝 R 系統外部依賴
許多 R 包有外部依賴,如 GSL, GDAL, JAGS,爲了安裝它們,你需要進行如下的操作:
docker ps # find the ID of the running container you want to add a package to
docker exec -it <container-id> bash # a docker command to start a bash shell in your container
apt-get install libgsl0-dev # install the package, in this case GSL
如果安裝報錯,先試試 apt-get update
爲了保存安裝的依賴,依舊需要進行修改的提交:
docker commit -m "verse + gapminder + GSL" <container id> verse_gapminder_gsl
第四課:對 Docker Hub 推送或拉取鏡像
學習目標
- 理解鏡像來自哪裏
- 從 Docker Hub 拉取鏡像
- 推送鏡像到 Docker Hub
從 Docker Hub 獲取鏡像
Docker Hub 是一個存儲 Docker 鏡像的地方,當我們運行下面的命令時,軟件首選檢查鏡像是否存在於你的計算機上。如果不存在,它會自動去 Docker Hub 搜索和下載。
docker run --rm -p 8787:8787 rocker/verse
如果你想要從 Docker Hub 上拉取鏡像而不運行它,可以使用命令:
docker pull rocker/verse
將鏡像放到 Docker Hub
想象一下如果你自己創建了一個鏡像,然後想要與其他人分享,你可以在 https://hub.docker.com/ 創建一個賬號。驗證完郵箱之後,你就可以將你的鏡像上傳了:
點擊創建倉庫
設置名字後點擊創建
-
使用命令行登錄 Docker Hub
docker login --username=yourhubusername [email protected]
如果沒問題應該會看到下面的信息
WARNING: login credentials saved in /home/username/.docker/config.json Login Succeeded
-
檢查鏡像的 ID
docker images
然後你會看到類似下面的輸出:
REPOSITORY TAG IMAGE ID CREATED SIZE verse_gapminder_gsl latest 023ab91c6291 3 minutes ago 1.975 GB verse_gapminder latest bb38976d03cf 13 minutes ago 1.955 GB rocker/verse latest 0168d115f220 3 days ago 1.954 GB
-
標記你的鏡像(打標籤)
docker tag bb38976d03cf yourhubusername/verse_gapminder:firsttry
這裏鏡像 ID 必須匹配,
fisttry
是標籤,一般選擇一些容易識別的標籤。 -
推送你的鏡像:
docker push yourhubusername/verse_gapminder
現在所有人都可以使用你的鏡像了!
保存和加載鏡像
將鏡像推送到 Docker Hub 非常使用,但它有些缺點:
- 受帶寬限制
- 推送意味着發佈(私密需要額外付費)
- 當在一些計算節點上工作時,如果每一次你都拉取 Docker Hub 的鏡像,速度會很慢
解決方案的在本地對你的鏡像進行存檔,這樣你可以在需要的時候輕鬆載入。
爲了這一目的,你可以使用 docker save
命令。讓我們試試吧:
docker save verse_gapminder > verse_gapminder.tar
如果我們想要從存檔中載入鏡像,使用下面的命令:
docker load --input verse_gapminder.tar
第五課:Dockerfile
前面我們學習了一個可以在 Docker 中運行 RStudio 的基礎鏡像,學習如何使用 docker commit
修改鏡像的內容。這是一個非常棒的技術,它讓我們可以進行重複,但如果我們想要更簡單地修改鏡像中的內容,並有一份清晰的記錄,該怎麼辦呢?這就是 Dockerfile 的用武之地了。
FROM rocker/verse:latest
這告訴 Docker 以 rocker/verse
基礎鏡像作爲開始。FROM
命令必須是第一條指令。
接下來,讓我們基於該基礎鏡像添加一層,讓 gapminder
提取安裝好可以直接使用:
RUN R -e "install.packages('gapminder', repos = 'http://cran.us.r-project.org')"
RUN
命令可以執行 Shell 命令,這個例子中,我們直接通過 Shell 調用包安裝命令。保存你的 Dockerfile,返回終端,現在我們可以利用下面的命令構建一個自定義鏡像:
docker build -t my-r-image .
-t my-r-image
指定鏡像名字(要小寫),.
指定構建鏡像所需要的資源來源,這裏指當前目錄。查看鏡像:
docker images
現在你可以運行你的鏡像:
docker run --rm -p 8787:8787 my-r-image
在 RStudio 控制檯中嘗試運行:
library('gapminder')
gapminder
現在該包已經是直接可以使用了!
有時候我們想要添加一些靜態文件到鏡像中,這可以使用 ADD
命令:
ADD data/gapminder-FiveYearData.csv /home/rstudio/
高級技巧:緩存層
在構建和重構建你的 Docker 鏡像時,你可能注意到了類似下面的輸出:
Step 2 : RUN R -e "install.packages('gapminder', repos = 'http://cran.us.r-project.org')"
---> Using cache
---> fa9be67b52d1
注意到使用的是命令的緩存版本。當你重新構建映像時,Docker 會檢查該映像的以前版本,以查看以前是否執行了相同的命令;每一個步驟都被保存爲一個單獨的層,Docker 非常聰明,可以重用那些層,如果它們沒有改變,並且和前面一樣的順序。因此,一旦你弄清楚了你的安裝過程的一部分(特別是如果它是一個緩慢的部分),把它放在你的Dockerfile的頂部,不要在這些行上面或中間放任何東西,特別是那些經常變化的東西;這可以大大加快你的構建過程。
簡單的說,重構建只修改有變動的步驟,如果很多命令沒有問題,儘量放到頂部。
小結
本節,我們學習瞭如何組合一個 Dockerfile 用於按我們自己的想法構建鏡像,包括 3 個命令:
-
FROM
指定基礎鏡像 -
RUN
運行命令 -
ADD
添加文件
使用 docker build -t my-r-image .
構建。
小抄:
第六課:分享你的分析
既然我們已經學會了如何利用 Dockerfile,我們就能夠將我們所有的分析發給合作者。我們將分享一個包含運行我們分析的所有依賴的鏡像。
我們通過 Dockerfile 構建該鏡像。讓我們還是以之前使用過的 rocker 鏡像開始。這一次我們使用指定的 R 版本,通過這裏查看所有可獲取的鏡像列表。版本標籤在可重複性分析中非常有用。
FROM rocker/verse:3.3.2
作爲分析的一部分,我們將使用 gapminder 數據集,添加下面的內容:
RUN R -e "install.packages('gapminder', repos = 'http://cran.us.r-project.org')"
接下來將我們的分析寫成腳本並將其添加到 Dockerfile 中。
library(ggplot2)
library(gapminder)
life_expentancy_plot <- ggplot(data = gapminder) +
geom_point(aes(x = lifeExp, y = gdpPercap, colour = continent))
將其添加到 Docker 鏡像中的指定目錄中:
ADD analysis.R /home/rstudio/
現在我們可以構建這個鏡像然後檢查是否我們已經具備分享的一些內容:
docker build -t my-analysis .
查看我們的分析鏡像:
docker images
啓動鏡像:
docker run -dp 8787:8787 my-analysis
太好了,我們的分析腳本在裏面,而且數據包也已經安裝好了。
現在將分析推送到 dockerhub。
創建倉庫後,使用下面的命令進行登錄。
docker login --username=yourhubusername [email protected]
檢查鏡像 ID:
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
my-analysis latest dc63d4790eaa 2 minutes ago 3.164 GB
給要提交的鏡像打標籤:
docker tag dc63d4790eaa yourhubusername/gapminder_my_analysis:firsttry
推送到你創建好的倉庫:
docker push yourhubusername/gapminder_my_analysis
現在你的鏡像任何人都可以使用了。
合作者通過下面的命令可以下載它:
docker pull yourhubusername/gapminder_my_analysis:firsttry
更多資料: