因为工作需要, 需要制作一个Docker来打包一个python程序。该python程序是开源的, 但是要下载对比数据库及其他辅助文件,配置好环境变量,并且要安装很多python的依赖包才能运行。虽然不是很麻烦,但是为了让其他人方便使用,最好还是可以直接下载就用。稍微花了两天学了一下Docker来打包这个程序,这样只要下载镜像直接运行就可以使用了。
本项目python程序介绍
该python开源软件是MetaPhlAn,用于分析从基因序列数据中提取的微生物群落的组成。该程序要运行必须在本机安装biobakery和bowtie2。并且将这两个包所在的路径加入到环境变量中。同时还需要安装numpy,pandas等安装包。如果follow本博客来生成镜像的话。可以先把上面连接中的文件下载下来。
什么是docker
国际惯例,简单介绍一下什么是docker。简单来说,Docker是对Linux一些容器的打包。Docker 将应用程序与该程序的所有依赖及一些配置,打包在一个文件里面,运行这个文件,就会生成一个容器,可以直接在容器上运行任务。例如我有一个apache服务网站,现在想要再另一台服务器上复现,那么就必须先安装apache服务,配置运行环境,将网站文件复制过去,再运行。这样就很麻烦,而且打不准会出现环境变量或者配置问题。但如果使用docker将这个服务打包的话就不用这么麻烦了。直接在另一台服务器上运行复现就可以了。
安装docker
docker的安装按照官网的来就行了,不同系统的安装方法都有。由于我使用的是ubuntu系统,这里就只讲Ubuntu系统下docker的安装。Ubuntu下的安装非常简单(不是最新版的话)。一般来说只要apt直接安装就可以了。最新版的安装比较复杂,大家还是去看官网的安装方法吧。
sudo apt-get install docker
安装完之后可以测试一下
sudo docker run hello-world
如果出现下面的输出则说明安装成功了
Hello from Docker!
This message shows that your installation appears to be working correctly.
... ...
修改image仓库的镜像地址
在上面的命令中
sudo docker run hello-world
会根据hello-world这个镜像,生成一个容器运行。 当然第一次运行的时候我们本地并没有这个镜像, 这时候docker会从官网寻找镜像, 并pull到本地。也就是先执行了下面的语句
sudo docker pull hello-world
但是如果使用默认的官方仓库下载速度将会非常慢,没办法官网在国外。我们可以把默认docker下载仓库改成国内仓库,这样下载速度会快很多。
sudo vim /etc/default/docker
在文件的最后面加上一句
DOCKER_OPTS="--registry-mirror=https://registry.docker-cn.com"
然后重启docker服务
sudo service docker restart
这样就会从国内仓库下载镜像了。
创建docker用户组(可选)
大家如果注意我上面的命令,会发现再docker命令之前都有sudo,也就是只有root用户才有权限运行docker的命令。这是由于在默认情况下,docker只允许root用户和docker用户组的用户访问Docker引擎。一般情况下我们不会直接使用root用户,因此最好的方法是将当前使用的用户加入到docker用户组。
# 建立docker用户组
sudo groupadd docker
# 将当前用户添加到docker用户组中
sudo usermod -aG docker $USER
这样当前用户就添加到了docker用户中,可以直接运行docker命令了。测试一下
docker run hello-world
如果执行成功,那就说明配置生效了。如果出现下面类似的情况, 就说明当前用户的docker配置文件权限方面存在问题。
WARNING: Error loading config file:/home/user/.docker/config.json - stat /home/user/.docker/config.json: permission denied
可以用下面的命令修改一下权限
sudo chown "$USER":"$USER" /home/"$USER"/.docker -R
sudo chmod g+rwx "/home/$USER/.docker" -R
这样应该就可以了。
使用Dockerfile定制镜像
上面的准备工作做完之后,就可以开始创建镜像了。一般我们很少从头创建一个镜像,我们会根据现有的镜像来进行定制。镜像的创建有多种方法,这里采用官网推荐的方法。使用Dockerfile创建,Dockerfile是包含一串指令的文本文件。Dockerfile首先要指定一个基础镜像,然后在这个镜像上执行指令,例如安装软件,修改配置等。这样就生成了一个定制的镜像了。
创建一个文件夹并进入该文件夹创建一个Dockerfile。
mkdir MetaPhlAn
cd MetaPhlAn
touch Dockerfile
再创建一个content文件夹,用来存放本项目中需要用到的依赖包。也就是前面所说的biobakery和bowtie2。然后将下载下来的biobakery和bowtie2存放到该目录下。
mkdir content
# 将biobakery和bowtie2拷贝到该目录下
接下来开始编写Dockerfile文件。在Dockerfile文件中写入下面的内容。
FROM ubuntu:16.04
WORKDIR /bowtie2
COPY content /root/
ENV MDIR="/root/metaphlan2" PATH="/root/metaphlan2:/root/metaphlan2/utils:$PATH" \
PATH="$PATH:/root/bowtie2-2.3.4.1-linux-x86_64"
RUN apt-get update \
&& apt-get install -y python \
python-dev \
python-pip \
&& apt-get clean \
&& apt-get autoclean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
&& pip install numpy pandas biopython scipy matplotlib h5py \
&& pip install biom-format
下面开始逐条解释每一句的含义。
FROM ubuntu:16.04
这条语句意思是把ubuntu16:04指定为基础镜像。也就是说我们接下来的指令都是在ubuntu镜像下执行的。这条语句是必须的。这里有一个特殊的镜像值得一提。那就是 scratch镜像,它表示一个空白的镜像,有什么用呢?有时候仅仅只是把二进制的可执行文件进行打包。这时候并不依赖任何环境,这时候scratch镜像就可以用到了。
WORKDIR /bowtie2
COPY content /root/
WORKDIR指令用来指定镜像中的工作目录,如果镜像中没有这个目录,则会自动帮你创建。
COPY指令是将文件传入到镜像中。源文件的各种元数据都会保留。比如读、写、执
行权限、文件变更时间等。这条指令的意思就是把该content文件夹下的所有文件拷贝到镜像中的/root/目录下。注意是content文件夹下的内容,而不是文件夹。
ENV MDIR="/root/metaphlan2" PATH="/root/metaphlan2:/root/metaphlan2/utils:$PATH" \
PATH="$PATH:/root/bowtie2-2.3.4.1-linux-x86_64"
这条指令的意思是给镜像中Ubuntu添加环境变量,这是为了让我的python程序可以运行,因为该python程序必须用到biobakery和bowtie2。因此将它们添加到环境变量,以便程序运行时可以找到。
RUN apt-get update \
&& apt-get install -y python \
python-dev \
python-pip \
&& apt-get clean \
&& apt-get autoclean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
&& pip install numpy pandas biopython scipy matplotlib h5py \
&& pip install biom-format
上面的指令很好理解,首先是再ubuntu下安装python及其安装包。然后清除安装包,这是为了减少镜像的大小。最后在安装python包的依赖。
值得注意的是当你安装的python包之间有依赖时,一定要把依赖其他包的包放在后面安装。像我这里就是这样。
&& pip install numpy pandas biopython scipy matplotlib h5py \
&& pip install biom-format
由于biom-format依赖与numpy包,所以不能把biom-format包放在上面一行一起安装。这样会报错。
生成镜像
编写完Dockerfile之后, 就可以生成镜像了。
docker image build -t metaphlan-docker .
-t 是用来指定镜像名称的,注意镜像名称不能包含大写字母
最后的 . 是指Dockerfile的地址,这里当然就是本目录了。
如无意外的话, 就会生成一个metaphlan-docker镜像(有点久,需要耐心等一等)。
运行镜像
安装完之后自然是需要试试的。
docker run -i -t --rm -v ~/data:/bowtie2 metaphlan-docker bash
-i 是交互的意思。
-t 是打开一个terminal的意思
-v 是挂载目录,后面的参数是 本地的目录:镜像目录, 像我这里的意思就是把镜像中的 /bowtie2挂载到本地的 ~/data目录下。也就是我在本地~/data目录下的任何操作,都会映射到容器中的 /bowtie2目录,这样就实现了本地和容器的文件传输。