以前的公司项目管理用Redmine,公司里的IT团队为了部署方便,将 Bitnami打包好的版本装在虚拟机里并且预先配置好各种预设值和数据库 什么的,需要新实例的时候直接在服务器上新建一个虚拟机就可以了。最近因 为工作需要,我要自己在本地搭一个Redmine实例,手上的破机器又跑不起虚 拟机,难道只能直接上了?那倒不至于,我们还有Docker.

Docker和虚拟机

Docker是用Go语言实现的“应用容器”(Application Container),用于 将具体应用和它的执行环境(包括依赖的库等等)打包到一起,以方便部 署,并且与其他应用隔离开来。Docker的大名我在年初就听说过了,但是因为 不想趟Go语言这滩浑水,所以一直没有动手……这次回头研究它的时候发现 Fedora的yum源里已经有docker-io包了,所以不试白不试……

它与虚拟机最大的不同在于,虚拟机一般工作在机器码级别,会模拟出整 个硬件环境,包括独立的CPU和IO设备等,所以虚拟机映像一般比较大而且运行 速度没有原生程序快;而Docker提供的容器只是在操作系统层面模拟出一 个独立的应用环境——像是提供特定的二进制程序和库文件——而其他基础设施, 像硬件和驱动程序之类的依然用的是宿主系统那一套,而且应用和宿主操作系 统之间没有任何抽象层,应用代码是直接在宿主CPU上跑的。Docker的实现有点 像chroot,但是更精细一些,还涉及到进程命名空间和许多其他细节——对 这些细节感兴趣的同学请移步到dotCloud的PaaS Under the Hood系列文 章。

由此可见,Docker要比虚拟机更轻量级,只需要一次性通过宿主操作系统 设定容器的环境就够了。但是宿主系统必须支持容器操作,而且通过Docker打 包的应用要满足宿主系统的执行要求,例如PowerPC程序就不能在x86宿主上执 行。也就是说,Docker为了轻量化,抛弃了虚拟机独立于硬件和操作系统的优 势。

上手搭建Redmine

我用的Redmine是这个版本,google的第一个结果XD. 这货的“Quick Start” 实际上是start不起来的,因为数据库其实要自己另外装……所以在这把我自己的 步骤记下来。

  1. 下载数据库容器映像:

    1
    $ docker pull sameersbn/mysql:latest
    
  2. 在宿主系统上建立数据库目录:

    1
    2
    3
    $ mkdir -p /where/ever/you/like/mysql
    $ # 如果宿主机上有跑SELinux的话,还要改一下目录的类型,否则会Permission denied:
    $ sudo chcon -Rt svirt_sandbox_file_t /where/ever/you/like/mysql
    
  3. 启动数据库容器:

    1
    2
    $ docker run --name mysql -it --rm \
        -v /where/ever/you/like/mysql:/var/lib/mysql sameersbn/mysql
    
  4. 进入MySQL的控制台给Redmine指定一个用户,并创建数据库:

    1
    $ docker run -it --rm --volumes-from=mysql sameersbn/mysql mysql -uroot
    
  5. 下载Redmine容器映像:

    1
    $ docker pull sameersbn/redmine:latest
    
  6. 在宿主系统上建立Redmine配置目录:

    1
    2
    $ mkdir -p /where/ever/you/like/redmine
    $ # 同样,如果宿主机上有跑SELinux的话,这里还要改一下目录的类型,参考第2步。
    
  7. 启动Redmine容器:

    1
    2
    3
    $ docker run --name=redmine -p 10080:80 -it --rm --link mysql:mysql \
        -e "DB_USER=redmine" -e "DB_PASS=password" -e "DB_NAME=redmine_production" \
        -v /where/ever/you/like/redmine:/home/redmine/data sameersbn/redmine
    

这时访问http://localhost:10080,就可以看到部署好的Redmine界面了。

上面的部署过程为数据库和Redmine分别建立了一个容器,而且每个容器的数 据保存路径都用-v参数映射到宿主的文件系统上,这是Docker容器常见的部 署模式。

为什么要进行目录映射呢?因为Docker的容器映像在运行时是只读的。例 如我们有一个映像A,然后使用这个映像运行了一个容器C,那么运行时对容器 内容的修改只存在于容器C中,映像A是不会发生改变的。假设我们想要保存对 容器C的修改,就要将修改内容commit到一个新的映像中。但是如果我们 进行了目录映射,修改内容就可以直接保存在宿主的文件系统上,不需要在每 次退出容器后都进行一次commit.

至于其他的参数,其实不难理解,请参考Docker文档