使用 docker 构建 AFEPack 镜像来减少安装 AFEPack 的痛苦

先前写了一篇如何在 Ubuntu 安装 AFEPack 的教程,但现在感觉有些陈旧了。在暑假到澳门大学学习期间,结识了 xywei , 他使用 docker 构建了 AFEPack,镜像地址在这里。先前也知道 docker 掀起的热潮,但一直没有学习它。

关于 docker 的学习,网上一搜一大堆。我自己买了本 杨保华、戴王剑、曹亚仑 编著的《Docker 技术入门与实践》,利用一个下午学会了基本操作,后面的有些功能自己用不到就没有再深究下去。闲话少说,下面进入正题。

安装 docker

首先,要构建 docker 镜像,你需要安装 docker,具体安装过程见官网或者 Google 、Baidu 一下。

编写 Dockerfile

要想实现自动构建 Docker 镜像,就需要编写 Dockerfile。只要知道 Dockerfile 编写时需要用的一些指令和编译安装的命令就可以了。

下面是我最后写好的 Dockerfile 。我在下面用中文添加注释,原文件参考我 GitHub 上的项目AFEPackDocker

FROM ubuntu:16.04                                   # 以 ubuntu 16.04 作为镜像的基础系统
MAINTAINER FSSlc, liuchang011235 AT gmail DOT com   # 维护者的相关信息
# install essential packages
RUN \                                               # RUN 后面跟上要运行的命令即可
  mkdir -p /root/Pkg && \
  # use aliyun's mirror for better download speed
  sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \
  apt-get update && \
  apt-get install -y make automake autoconf wget build-essential \
  libdeal.ii-dev mpi-default-dev nano # libhypre-dev trilinos-all-dev petsc-dev --no-install-recommends
## set some env varibles                            # 设置与 AFEPack 相关的环境变量
COPY env.txt /root/Pkg/env.txt 
## prepare AFEPack easymesh
RUN \
cd /root/Pkg && \
wget http://dsec.pku.edu.cn/~rli/AFEPack-snapshot.tar.gz && \
wget http://dsec.pku.edu.cn/~rli/source_code/easymesh.c.gz && \
tar -xzf ./AFEPack-snapshot.tar.gz -C /root/Pkg/  && \
gunzip easymesh.c.gz && \
## compile and install AFEPack
cat /root/Pkg/env.txt >> /root/.bashrc && . /root/.bashrc && \
cd /root/Pkg/AFEPack && \                           # 将 ubuntu 中安装的 deal.ii 库文件改名
ln -s /usr/lib/x86_64-linux-gnu/libdeal.ii.g.so.8.1.0 /usr/lib/x86_64-linux-gnu/libdeal_II.g.so && \
ln -s /usr/lib/x86_64-linux-gnu/libdeal.ii.so.8.1.0  /usr/lib/x86_64-linux-gnu/libdeal_II.so && \
aclocal && autoconf && automake --add-missing && \
env EXTRA_INCDIR="-I/usr/include/deal.II/" EXTRA_LIBDIR="-L/usr/lib/x86_64-linux-gnu/" ./configure && \
# make -j8 && make install                      # 下面分开编译 AFEPack,直接编译会报错,镜像就编译不下去了
cd ./template/ && make -j8 && cd ../library/ && make -j8 && make install && \
cd ../example/ && make -j8 && \
## compile and install easymesh
cd /root/Pkg/ && \
gcc -o easymesh easymesh.c -lm && \
mv ./easymesh /usr/local/bin/ && \
## do some clean work                           # 清理一些不需要的文件,减小镜像大小
rm easymesh.c AFEPack-snapshot.tar.gz env.txt && \
rm -rf /var/lib/apt/lists/*
CMD ["/bin/bash"]

UPDATE
为了能够本地编译安装 AFEPack 的镜像,我编写了两个 Dockerfile,一个是直接使用
Ubuntu 16.04 里面 8.1 版本的 deal.II,另一个是在 Ubuntu 14.04 里使用源码编译的 deal.II 6.3.1,请自行选择。

UPDATE 20181103
好久没有更新了,最近在做 docker 相关的事。了解到 docker 可以进行所谓的多阶段构建了。这个功能可以进一步地减小镜像的大小,所以我今天就尝试了一下,效果还是很明显的。从原来的 1.07GB 减少到现在的 573MB

另外 AFEPack 的包做了一些更新,居然默认 std=c++14 了!所以原来的 Dockerfile 可能不能使用了,所以我顺便做了更新。从构建的结果看,step-7 这个例子跑不通,这次更新后的 Dockerfile 都有这个问题,它们获取的
AFEPack 源码都是今天我从官网下载的。但是我放在 docker Hub 的镜像可以运行。。。

使用 docker build 命令构建镜像

编写完 Dockerfile 后,便可以构建镜像了。使用的命令是:

sudo docker build  -t afepack:v0 .

其中 -t 选项是指定编译后镜像的名称,即所谓的 tag

具体使用时,一般运行:

docker run -ti -v $HOME/Pkg:/opt afepack:v0 bash

上面的命令将启动一个容器,其中的 -v 选项将把主机中的 $HOME/Pkg 目录挂载到容器中的 /opt 目录,这样我们便可以在 $HOME/Pkg 中让主机和容器之间进行数据交互。