歡迎光臨
每天分享高質量文章

R用戶如何使用Docker?

什麼是Docker

 

Docker是“一種實現在操作系統層面的虛擬化軟體,也稱為容器”。這是Wikipedia的定義,對於不熟悉的人來說太晦澀難懂了。
簡單說,Docker是一類程式,使得在自己的機器上(稱為host)調度(啟動或者停止)多個操作系統(稱為容器)。假設有10台運行不同Linux系統的樹莓派,每台都運行不同服務,實際上可以在自己的機器上啟停這些樹莓派設備。
為什麼要在R中使用Docker

 

Docker可以實現在鏡像或者容器中內置環境,意味著可以在Macbook上運行Linux,或者在本機運行R 3.5而同時在虛機里運行R 3.3環境。同時,也意味著為某些特殊目的在虛擬環境中使用較老版本的環境包,而本機則保持最新狀態。
這樣可以解決“依賴性”問題,如果擔心環境改變會影響最新環境,可以建立一個虛擬容器運行需要的環境,可以是Linux、R或者任何其他需要的包。
Docker鏡像和Docker容器

 

在機器上,需要兩類東西,鏡像和容器。鏡像可以看做操作系統,而容器可以認為是鏡像的運行態。鏡像只需要運行一次,而容器則在需要時候隨時啟動,當然一個鏡像可以同時運行多個實體。
和R對比,安裝和裝載package類似於鏡像和容器,一個package只需要下載一次,但是可以運行多個實體。同樣在metaphore概念上也有類比:通過install.packages()來編譯鏡像,用library()來運行鏡像。
Dockerfile

 

Docker鏡像根據Dockerfile建立。Dockerfile是配置檔案,其中定義了:依賴的Docker鏡像,如何配置操作系統,運行容器時做什麼。有點類似於R包中的DESCRIPTION NAMESPACE檔案,其中也定義了依賴包,元信息,以及使用library呼叫後用戶可用的函式和資料。
因此,可以為R寫一個非常基礎的Dockerfile檔案,目的是可重覆性。也就是說:假如生成了一個分析環境(例如,在一個R檔案中定義),而且希望不管以後系統如何升級這個分析環境仍然可以工作。
首先,創建一個分析目錄和Dockerfile:
  1. mkdir ~/mydocker
  2. cd ~/mydocker
  3. touch Dockerfile
假如運行程式為位於~/mydocker目錄下的myscript.R:
  1. library(tidystringdist)
  2. df tidy_comb_all(iris, Species)
  3. p tidy_stringdist(df)
  4. write.csv(p, "p.csv")
FROM
每個Dockerfile都以FROM開頭,定義從哪個image開始創建。網上有很多官方發佈的鏡像,也可以從本地自己建一個開始。FROM定義了鏡像的依賴關係,就跟R中生成一個包需要依賴一個另外的包一樣(當然一般都是依賴base包)。
如果需要一個基於R的基礎包,Dirk Eddelebuettel和Carl Boettiger維護了rocker,這裡集中了R可以使用的所有容器鏡像。基礎包位於rocker/r-base下,我們期望鏡像可以重現,也就是任何時候運行都會產生同樣的結果,為了達到目的,在rocker/r-ver目錄下維護了3.1.0版本之前的R,這樣可以運行任何日期之前的程式(感謝Dirk Eddelebuettel)。接下來我們需要查找滿足R要求的鏡像,可以使用如下命令獲得R版本:
  1. R.Version()$version.string
因此,可以以如下標識開始一個Dockerfile:
  1. FROM rocker/r-ver:3.4.4
RUN
到這一步,可以加入一些運行時的短指令,例如創建接收分析資料的目錄:
  1. FROM rocker/r-ver:3.4.4
  2. RUN mkdir /home/analysis
Install our package
這條命令讓R執行一些命令列,R -e “my code”,用這個樣式在特定日期安裝依賴腳本,可以設置“repos”到特定日期,並且使用CRAN的鏡像。
  1. FROM rocker/r-ver:3.4.4
  2. RUN mkdir /home/analysis
  3. RUN R -e "options(repos = \
  4. list(CRAN = 'http://mran.revolutionanalytics.com/snapshot/2019-01-06/')); \
  5. install.packages('tidystringdist')"
Aside : making it more programmable with ARG
如果使用ARG引數可以修改生成時間,引數是:–build-arg WHEN=
  1. FROM rocker/r-ver:3.4.4
  2. ARG WHEN
  3. RUN mkdir /home/analysis
  4. RUN R -e "options(repos = \
  5. list(CRAN = 'http://mran.revolutionanalytics.com/snapshot/${WHEN}')); \
  6. install.packages('tidystringdist')"
{tidystringdist} 將會安裝我們要求日期的版本,即使我們在很久之後才執行這條命令。
COPY
現在,需要將主機上的分析腳本放到容器中,可以使用COPY localfile pathinthecontainer方式。註意這裡的myscript.R和Dockerfile要在同一個目錄下:
  1. FROM rocker/r-ver:3.4.4
  2. ARG WHEN
  3. RUN mkdir /home/analysis
  4. RUN R -e "options(repos = \
  5. list(CRAN = 'http://mran.revolutionanalytics.com/snapshot/${WHEN}')); \
  6. install.packages('tidystringdist')"
  7. COPY myscript.R /home/analysis/myscript.R
CMD
CMD是每次運行Docker都要運行的命令。
  1. FROM rocker/r-ver:3.4.4
  2. ARG WHEN
  3. RUN mkdir /home/analysis
  4. RUN R -e "options(repos = \
  5. list(CRAN = 'http://mran.revolutionanalytics.com/snapshot/${WHEN}')); \
  6. install.packages('tidystringdist')"
  7. COPY myscript.R /home/analysis/myscript.R
  8. CMD R -e "source('/home/analysis/myscript.R')"
Build 和 run

 

Build
我們的需求是:運行過去日期的分析工作,需要使用 –build-arg WHEN= 引數,只要在=後加入日期即可。在終端Dockerfile目錄下,運行:
  1. docker build --build-arg WHEN=2019-01-06 -t analysis .
-t name是鏡像的名字,. 意味著Dockerfile在同一個目錄下。
run
執行命令:
  1. docker run analysis
分析作業即可被執行。
匯出容器內容

 

現在我們迎來了下一項任務:訪問由容器之外分析源(這裡為p.csv)提供的相關內容;換言之,這些內容處於主機之上。相信大家都很明確,目前一切在容器之內發生的操作都只會影響到容器內部。 因此,我們需要的就是讓Docker容器與主機之間共用一個檔案夾。為了達成這專案標,我們將要使用所謂Volume,簡單來講,大家可以將其理解成一種告知Docker容器如何將主機上的檔案夾作為容器內檔案夾的方法。
這樣一來,當容器被關閉之後,容器在該檔案夾當中創建的所有內容都將得以保留。為此,我們將在運行容器時使用-v標誌,同時配合path/from/host:/path/in/container。此外,我們還需要創建一個檔案夾以接收來自容器與主機的結果:
  1. FROM rocker/r-ver:3.4.4
  2. ARG WHEN
  3. RUN mkdir /home/analysis
  4. RUN R -e "options(repos = \
  5. list(CRAN = 'http://mran.revolutionanalytics.com/snapshot/${WHEN}')); \
  6. install.packages('tidystringdist')"
  7. COPY myscript.R /home/analysis/myscript.R
  8. CMD cd /home/analysis \
  9. && R -e "source('myscript.R')" \
  10. && mv /home/analysis/p.csv /home/results/p.csv
  11. mkdir ~/mydocker/results
  12. docker run -v ~/mydocker/results:/home/results analysis
等待計算完成,然後……
  1. ls ~/mydocker/results
  2. p.csv
OK
下麵我們該做什麼?

 

到這裡,每一次啟動這個Docker鏡像時,分析都將得到執行並給出結果。另外,其中不存在依賴性問題:軟體包將始終根據你的需要開始安裝。雖然過程可能有點耗時,這是因為每次運行容器時軟體包都會從頭安裝;但正如我在開頭的宣告中所提到,這是為了對Docker、R以及再現性做出基本介紹,旨在幫助更多初學者順利上手Docker方案:)
下麵我們再進行一點拓展討論:
如果大家希望自己的分析以軟體包版本為基礎,而非以安裝時間為基礎,則可使用remotes::install_version()。
  1. FROM rocker/r-ver:3.4.4
  2. RUN R -e "install.packages('remotes'); \
  3. remotes::install_version('tidystringdist', '0.1.2')"
  4. ...
另外,你可以使用Volume以追蹤傳入容器內的資料,這樣任何處於同一環境中的資料都將接受分析處理。
原文鏈接:https://colinfay.me/docker-r-reproducibility/

赞(0)

分享創造快樂