apt和yum以及其他的包管理工具可以解决Linux下各种包的依赖关系,有了apt和yum基本不需要手动编译源代码解决依赖关系了。手动make源代码,可能会引出好多个make,make到最后发现对内核版本有要求,再去make内核,最后换操作系统。
使用apt和yum虽然方便了很多,但是还是有些时候会出问题,因为一个操作系统上的各种包大致都是同一时期的,比如我的gcc是2015年10月的4.8,glibc是2015年7月的2.8。如果我想把我系统上的gcc换成2010年的4.1版本,那么我可能glibc需要换成2011年之前的版本,然后又引出了一连串依赖关系,最终系统不能用了。
以上这些称之为“依赖地狱(dependency hell)”。我们部署一个应用的时候经常会出现这些烦人的问题,我在测试环境废了老大劲部署好了,到了发布生产的时候还得部署一遍,有可能生产与测试环境操作系统啥的还不一样。使用虚拟机(Virtual Machine)可以解决一部分问题,制作好一个VM镜像然后丢到HyperVisor上就行了,但是太重量级了。而使用容器(Container)可以很好的解决问题,尤其是docker使用了分层镜像使得容器镜像更容易发布和迁移。
docker目前已经不是一个简单的容器软件了,而是一个生态系统了。本文不会介绍那么多,仅仅分享一下如何在日常开发中像apt和yum一样来使用docker,反正我现在想安一个软件(当然不是图形化的),我都先用docker搜一下,比如nginx,tomcat,甚至DB2,IBM制作了官方的DB2-express镜像放到docker hub上了。
现在有这样一个场景,我们的应用是个C语言程序,要求必须用gcc 5.1.0编译,而且生产上在centos7上运行。但是我本地只有一个ubuntu server 14.04,上面除了docker和ssh几乎什么都没有安装,我想用它开发我们的应用。我如果用apt安装的话默认是4.8的。现在我用docker来解决这个问题。
使用docker安装开发环境
首先我需要一个编辑器,例如vim或者emacs,当然最好直接用apt安装,但是我可以用docker安一个编辑器。这样做其实还有一个好处,后面说。
vim都不是official的,official的就是公司或者社区提供的官方版。但是有不少人都把自己定制的vim打成镜像放到docker hub上了,可以拿过来用。星数最高的是golang-vim-dev,里面应该集成了golang的开发环境,下个简单的haron/vim。直接执行sudo docker pull haron/vim即可。
然后我们需要安装gcc 5.1.0,先搜一下。
这个有official的,official就是gcc官方提供的镜像。执行docker pull gcc:5.1.0
最后我们还需要一个centos 7的运行环境,也有官方的,直接sudo docker pull centos:7就能下载。
把所有需要的东西pull下来,看一下本地的镜像
本地已经有了gcc5.1.0,centos7以及vim。
开发测试与运行
如何用vim打开一个文件呢?
假如test.c的路径为/home/niuxinli/test.c,使用
docker run -it --rm -v /home/niuxinli/test.c:/test.c haron/vim vim /test.c
就能在容器中打开test.c,如果嫌长可以写一个alias或者脚本。
其中的各个选项的含义是:
-it : interactive+tty 交互式并且分配一个伪终端 --rm: 退出容器时删掉容器 -v /home/niuxinli/test.c:/test.c 把主机/home/niuxinli/test.c映射到容器的/test.c, v是volume的意思 vim /test.c 在容器里执行vim /test.c,这时vim命令看到的文件系统目录是容器里的,需要用里面的路径
我们使用另一种方式,直接把主机的工作目录映射到容器里。
新建一个工作目录/home/niuxinli/appworkspace,然后挂载到容器里,在容器里用vim编辑各种源代码。这样有个好处就是我们可以让开发人员只能看到这个目录里面的东西,不会互相影响。
docker run -it --rm -v /home/niuxinli/appworkspace:/appworkspace haron/vim /bin/bash
这次打开一个bash,在里面在用vim打开/appworkspace里的文件。
现在我们可以在appworkspace里编程了,镜像作者的配置还挺好的,自动缩进高亮都有。
保存后在/home/niuxinli/appworkspace里也产生了test.c。下面就是编译了,同样,我们把/home/niuxinli/appworkspace映射到gcc容器里,然后起一个bash进程,用gcc编译。
用gcc 5.1.0编译完了,需要放倒centos7里面运行。
总结
其实这样做有个问题,我们这个helloworld特别简单,仅用于演示。对于复杂的程序,还是会有依赖关系的,比如gcc镜像里的链接库与centos7里面的库有冲突,可能在centos7里面不能运行。正确的做法是制作一个centos7+gcc5.1的镜像,既用这个容器编译,也用它运行,开发测试生产用的编译运行环境都一致,这就是docker的build, ship and run any app anywhere。