注:早在学习《云计算》这门课以前就已经知道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/