注:早在學習《雲計算》這門課以前就已經知道docker,學習這門課時老師還鼓勵咱們本身嘗試一下;可是直到去年年末纔有機會嘗試,用過以後感受確實很好用。最近須要部署幾個shiny應用,又回顧了一下,並記錄與此。html
最開始據說docker,就知道可使用docker來部署應用,相對於以前在主機上直接安裝應用所需的運行環境,docker要方便的多。對於我這樣時不時被開發環境搞的懷疑人生的半個開發人員,天然會對這樣神奇的工具備所關注,只是一直沒有找到機會嘗試。直到去年年末,爲了部署一個Django應用,終於有機會嘗試了一下。有如下幾點認識:java
圖1:docker與虛擬機的區別,圖片來源:linkpython
因爲應用程序運行在container中,而容器又是基於image構建的,所以image就顯得很是重要了。image至關於一個刻錄好的光盤,裏面有預裝好的操做系統或應用程序等。docker官方維護了docker hub這個網站,相似於github,能夠直接從該網站上pull各類應用程序的官方鏡像。這些鏡像能夠直接使用,也能夠在此基礎上添加新的層,來構建本身的鏡像。linux
Docker的安裝nginx
windows下須要win10操做系統的特定版本(Windows 10 64bit: Pro, Enterprise or Education (1607 Anniversary Update, Build 14393 or later))才能夠安裝docker engine。下面是CentOS下安裝及啓動Docker Community Edition(CE)的官方文檔:git
在安裝好docker,並啓動docker以後,就能夠pull官方的image,並在這些image的基礎上按照本身的須要建立新的image。github
建立本身的image只須要一個Dockerfile文件就能夠,該文件中保存了構建image的每一步命令。image的每一層能夠僅包含一個命令也能夠是多個命令,且每一層執行完成後能夠緩存起來(下次不用從新執行已構建完成的層中的命令),這樣就讓可追溯的逐步搭建運行環境成爲可能。docker
Dockerfile中保存的是與基礎image對應的操做系統命令,例如以Ubuntu爲基礎image構建的新的image,該文件中就是Ubuntu系統的shell命令。如下是docker官網對該文件的介紹:shell
Docker can build images automatically by reading the instructions from a
Dockerfile
. ADockerfile
is a text document that contains all the commands a user could call on the command line to assemble an image. Usingdocker build
users can create an automated build that executes several command-line instructions in succession.ubuntu
下面是一個該文件的示例,使用了jupyter的官方鏡像datascience-notebook:
1 # 指定基礎image 2 FROM jupyter/datascience-notebook:03b897d05f16 3 MAINTAINER Xin Xiong <xiongxin20008@126.com> 4 5 # 替換CRAN鏡像爲國內的鏡像,能夠更快的安裝R packages 6 ARG CRAN_MIRROR=https://mirrors.tuna.tsinghua.edu.cn/CRAN/ 7 8 # 因爲要安裝程序,使用root身份 9 USER root 10 11 # install Java 12 RUN \ 13 apt-get update -qq && \ 14 apt-get install -y openjdk-8-jdk && \ 15 apt-get install -y mlocate && updatedb && \ 16 rm -rf /var/lib/apt/lists/* 17 18 # 爲安裝rJava作準備 19 # need using ln to avoid some errors, such as conftest.c:1:10: fatal error: jni.h: No such file or directory 20 RUN \ 21 ln -s /usr/lib/jvm/java-8-openjdk-amd64/include/jni.h /opt/conda/include/ && \ 22 ln -s /usr/lib/jvm/java-8-openjdk-amd64/include/linux/jni_md.h /opt/conda/include/ && \ 23 ln -s /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/amd64/server/libjvm.so /usr/lib/ && \ 24 R CMD javareconf 25 26 27 # 添加本地文件夾package到鏡像中的/src 28 ADD ./package/ /src/ 29 30 # link lib 31 RUN \ 32 ln -s /opt/conda/lib/libpcre.so /usr/lib/ && \ 33 ln -s /opt/conda/lib/liblzma.so /usr/lib/ && \ 34 ln -s /opt/conda/lib/libbz2.so /usr/lib/ && \ 35 ln -s /opt/conda/lib/libz.so /usr/lib/ && \ 36 ln -s /opt/conda/lib/libiconv.so /usr/lib/ && \ 37 ln -s /opt/conda/lib/libicuuc.so /usr/lib/ && \ 38 ln -s /opt/conda/lib/libicui18n.so /usr/lib/ 39 40 # 安裝前面添加到鏡像/src文件夾中rpacks.txt文件中的R package 41 # 且使用國內的鏡像地址CRAN_MIRROR 42 RUN \ 43 cd /src && \ 44 R -e 'install.packages(sub("(.+)\\\\n","\\1", scan("rpacks.txt", "character")), repos="'"${CRAN_MIRROR}"'")' 45 46 # 安裝前面添加到鏡像/src文件夾中requirements.txt文件中的Python package 47 RUN \ 48 cd /src && \ 49 pip --no-cache-dir install -r requirements.txt && \ 50 rm -rf /root/.cache 51 52 # 直接使用conda安裝Python package 53 RUN conda install -c rdkit rdkit 54 55 # 切換到默認普通用戶 56 USER jovyan
Jupyter的官方鏡像datascience-notebook,包含了Python, R和Julia以及一些數據分析中經常使用的包。我在該鏡像的基礎上,安裝了Java以及其餘一些本身須要的Python和R包。這些包的的名字保存在文件夾package的rpacks.txt和requirements.txt兩個文件中,每一個包名稱一行。在上面的操做中,第28行添加該文件夾中的內容到鏡像中的的/src目錄下,第42-44行安裝了rpacks.txt文件中的R包,第47-50行安裝了requirements.txt文件中的Python包。更多關於該鏡像的說明能夠在官方文檔的描述中看到,還有其餘的官方鏡像可供選擇。
如上面的例子所示,Dockfile中包含的最重要的內容是能夠在系統命令行中執行的命令,只是每一行命令前加了一些Dockfile特有的關鍵詞。下面是一些常見的關鍵詞:
FROM <鏡像>:<標籤> 指定基礎鏡像爲該鏡像的一個標籤版本,上面例子中的第2行
運行指定的命令。使用RUN能夠運行任何被基礎image支持的命令。若是基礎image是ubuntu系統,那麼軟件管理部分只能使用ubuntu的命令
添加本地文件或目錄到container
添加一些元數據,格式爲LABEL <key>=<value>,例如上面的第3行能夠寫成LABEL maintainer="Xin Xiong, xiongxin@20008@126.com". MAINTAINER關鍵詞已棄用。
定義一個變量,如第6行,能夠重複使用
更多關鍵詞,能夠參考官方文檔。此外,"&&"用來鏈接兩條不一樣的指令,"\" 表示同一條語句換行顯示
官方文檔給出了一些最佳實踐指南,好比說不要安裝不須要的package,應用解偶聯,最小化層數,如何最好的使用"apt-get",COPY和ADD關鍵詞的差異等。
有了上面的文件,就能夠在Dockerfile這個文件所在的文件夾,使用下面的命令build本身的鏡像了:
docker build -t onlybelter/ds-notebook .
這句命令會使用當前目錄下的Dockerfile文件,構建一個image,新image的名稱爲onlybelter/ds-notebook。
docker-compose能夠用來配置一些在image中沒有設置的參數,例如端口號,log日誌的目錄,容器啓動時運行的命令等。此外還能夠用來啓動、中止容器,打印log,查看容器狀態和限制資源使用等功能。
docker-compose的其餘介紹及安裝能夠參考官方文檔。
docker-compose的配置文件是一個放在與Dockerfile相同目錄下,以.yml結尾的文件,示例以下:
1 version: '2.2' 2 3 services: 4 jupyterlab: 5 image: onlybelter/ds-notebook 6 command: /bin/bash -c "jupyter lab --no-browser --ip=0.0.0.0 --notebook-dir=/mnt/notebook" 7 cpus: 16 8 mem_limit: 8g 9 volumes: 10 - /mnt/home/belter/github/jupyter-note:/mnt/notebook 11 - /etc/localtime:/etc/localtime:ro 12 environment: 13 - PYTHONUNBUFFERED=1 14 ports: 15 - 8888:8888
第1行,指定了配置文件的版本號,因爲v3不支持單機模式下配置資源,所以這裏使用了v2.2(若是不適用swarm或其餘集羣模式,官方推薦使用v2);
第4行是service的名稱;
第5行指定了image的名稱,就是上面build好的鏡像;
第6行設置了容器啓動時的命令;
第7-8行限制了資源的使用:16個CPU核,8G內存;
第10行,至關於掛載了一個本地目錄到容器,這樣容器和外部的host之間就能夠交換文件了(內外對應的文件夾裏的內容是同步的);
第11行用於同步容器與host的時間;
第13行設置了一個環境變量;
第15行設置了容器內外端口號的對應關係,左邊是host的端口號,右邊是容器內的端口號。
配置好上面的.yml文件(個人文件爲docker-compose.yml)後,就能夠啓動前面build好的鏡像來建立一個容器了。
$ sudo docker-compose up -d
$ sudo docker-compose logs
第1行命令使用當前目錄下的docker-compose.yml文件建立容器,並在後臺運行;第2行命令打印logs,能夠從logs中得到Jupyter Notebook生成的token來登陸。
Attaching to jupyterlab_jupyterlab_1 jupyterlab_1 | [I 20:07:06.567 LabApp] Writing notebook server cookie secret to /home/jovyan/.local/share/jupyter/runtime/notebook_cookie_secret jupyterlab_1 | [I 20:07:06.731 LabApp] JupyterLab beta preview extension loaded from /opt/conda/lib/python3.6/site-packages/jupyterlab jupyterlab_1 | [I 20:07:06.731 LabApp] JupyterLab application directory is /opt/conda/share/jupyter/lab jupyterlab_1 | [W 20:07:06.737 LabApp] JupyterLab server extension not enabled, manually loading... jupyterlab_1 | [I 20:07:06.737 LabApp] JupyterLab beta preview extension loaded from /opt/conda/lib/python3.6/site-packages/jupyterlab jupyterlab_1 | [I 20:07:06.737 LabApp] JupyterLab application directory is /opt/conda/share/jupyter/lab jupyterlab_1 | [I 20:07:06.744 LabApp] Serving notebooks from local directory: /mnt/notebook jupyterlab_1 | [I 20:07:06.744 LabApp] 0 active kernels jupyterlab_1 | [I 20:07:06.744 LabApp] The Jupyter Notebook is running at: jupyterlab_1 | [I 20:07:06.744 LabApp] http://1c7e68e582c4:8888/?token=3bda623azj07414dbcf58bf977e2c2855158bd052f77afa2 jupyterlab_1 | [I 20:07:06.744 LabApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
使用該host的ip加端口號8888,輸入日誌中的token就能夠打開Jupyter的界面。個人本地地址爲,http://192.168.1.33:8888/lab?
界面以下圖所示:
其餘docker-compose命令:
$ sudo docker-compose down # 關閉容器 $ sudo docker-compose ps # 查看容器運行狀態
此外使用docker stats <container name>能夠查看該容器資源使用狀況:
PS: 最近都是忙到每月最後一天更新博客,要改改啦!
https://stackoverflow.com/questions/16047306/how-is-docker-different-from-a-virtual-machine
https://www.docker.com/resources/what-container#/package_software
https://blog.csdn.net/weixin_37645838/article/details/83343029
https://docs.docker.com/engine/reference/builder/