如您所知,Docker是“一个提供给开发者和系统管理员的,用来打包,迁移和运行应用程序的开放平台。”自从去年年初发布后,它一直处于快速演进的状态,围绕着该平台的开发者社区也十分活跃。
这篇文章用来记录本人尝试使用Docker构建应用nginx和hhvm的网络服务器基础映像的过程,以资参考。
1、开发环境的准备:
显然需要一套能运行Docker的系统。Docker的容器技术依赖于Linux内核,同时只能在64位系统上运行。在windows可以使用vitrual box虚拟合适的操作系统,这方面的文章比较多,不再赘述。我的话,因为校园网环境按照流量计费,所以选择Digitalocean的VPS作为开发环境,选择最低配置每天的开销约为¥1,至少比流量费便宜。
我将使用CoreOS作为开发环境。CoreOS是专用于Docker的定制化系统,没有包管理系统,比较轻量化,不过常用的Linux工具还是比较齐全的。DigitalOcean上可以方便地建立使用coreos系统的vps。值得注意的是,coreos的root用户的用户名为“core”。而且需要ssh登陆强制要求使用RSA密钥,在digitalocean上创建的时候会要求你选择密钥。
2、基本操作:
docker平台提供了很多构建完成的基础映像,可以简单地下载到本地并且在容器中运行。这些容器与宿主平台共用linux核心,但是拥有独立的“namespace”,与宿主和其他容器隔离。简单操作如下(如果使用非管理员账号可能需要‘sudo’,docker以root权限运行)
core@illya ~ $ docker pull debian:wheezy
core@illya ~ $ docker run -i -t --name foo debian
这将会下载官方打包的debian映像,然后新建容器并以交互方式在容器中运行bash shell。
root@1a022f23501a:/# echo hello
hello
在该容器中可以执行对应系统的特定操作,比如使用atp-get安装软件包。
root@1a022f23501a:/# apt-get update && apt-get install --qq procps
现在可以在容器内使用‘ps’指令列出当前运行的进程了:
root@1a022f23501a:/# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.6 17856 3076 ? Ss 07:33 0:00 /bin/bash root 145 0.0 0.3 15324 1900 ? R+ 07:58 0:00 ps aux
使用'exit'可以从当前容器中退出:
root@1a022f23501a:/#exit
docker可以将经过修改的容器('container')作为新的镜像('image')保存:
core@illya ~ $ docker commit foo bar 81663069ac71b8eec32ba4aa9d90b9f8a7f4ab58945988533f6d4a318d2b682c core@illya ~ $ docker run -i -t --rm bar ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.1 6908 528 ? Rs+ 08:12 0:00 ps aux
可以看到,被安装到容器中的,新的程序已经可用了。
容易想到,我们可以通过这样的方式,在基础镜像上进行修改,来实现我们所需要的功能。
3、构建nginx-hhvm所需要的知识:
安装nginx或者hhvm的方法漫天遍野,我也是现学的,所以也不多讲。
需要考虑的是,Docker通过监控应用程序进入时运行的第一个进程来判断容器是否退出。nginx默认以守护进程的方式运行,主进程在启动服务后会自动退出。Docker会误认为nginx已经退出而错误地终止容器的运行,显然不对。
我们可以使用 nginx -g 'daemon off' 指令使nginx的守护进程在前台运行。
容易想到,我们的容器中可能不只需要运行一个服务,尽管我们可以用启动脚本的方式来管理服务,但是这样十分不方便扩展。
采纳docker开发者的实践经验,我们可以使用‘supervisor’这个python程序来管理各个服务进程。相关文档可以前往这个链接查看。
4、Dockerfile与自动构建
使用上述的方法来构建docker镜像的话,过程不够透明,比较繁琐,不方便修改和分享。因此,我们可以选择使用Dockerfile来定义容器的构建过程,并且使用Docker.Inc的开放平台来自动构建镜像以及分享。
这里直接给出我用来构建nginx-hhvm服务的Dockerfile:
FROM debian:wheezy MAINTAINER Robin Liu <spdf@live.com> ADD build/* /tmp/ RUN \ apt-key add /tmp/hhvm.gpg.key && \ apt-key add /tmp/nginx_signing.key && \ echo "deb http://nginx.org/packages/debian/ wheezy nginx" >> /etc/apt/sources.list && \ echo "deb-src http://nginx.org/packages/debian/ wheezy nginx" >> /etc/apt/sources.list && \ echo deb http://dl.hhvm.com/debian wheezy main | tee /etc/apt/sources.list.d/hhvm.list RUN \ apt-get update && \ apt-get install -y apt-utils procps supervisor vim.tiny && \ apt-get install -y nginx hhvm RUN \ cp /tmp/nginx.conf /etc/nginx/nginx.conf && \ cp /tmp/hhvm.server.ini /etc/hhvm/server.ini && \ cp /tmp/supervisord.*.conf /etc/supervisor/conf.d/ && \ cp /tmp/enter.sh /etc/enter.sh && \ chmod 755 /etc/enter.sh EXPOSE 80 443 VOLUME ["/data"] CMD ["/etc/enter.sh"]
稍微解释一下各行的意思
FROM debian:wheezy
这一句定义了我们构建的镜像的基础镜像;
MAINTAINER Robin Liu <spdf@live.com>
这一句给出了该镜像的发布者的信息;
ADD build/* /tmp/
这一句将和Dockfile文件同一目录下的'build'文件夹内的全部文件复制到容器的'/tmp'目录下,备用;
RUN \ apt-key add /tmp/hhvm.gpg.key && \ apt-key add /tmp/nginx_signing.key && \ echo "deb http://nginx.org/packages/debian/ wheezy nginx" >> /etc/apt/sources.list && \ echo "deb-src http://nginx.org/packages/debian/ wheezy nginx" >> /etc/apt/sources.list && \ echo deb http://dl.hhvm.com/debian wheezy main | tee /etc/apt/sources.list.d/hhvm.list RUN \ apt-get update && \ apt-get install -y apt-utils procps supervisor vim.tiny && \ apt-get install -y nginx hhvm
这一段导入了nginx stable,HHVM和Supervisor的软件源,并且安装到系统中;
再接下来的一段将一些预定义的配置文件复制到对应位置,以及将docker容器启动时要运行的脚本变更权限为可执行;
这一句定义了容器需要导出的TCP端口;
这一句定义了容器可以由外部挂载的文件目录;
这一句定义了容器启动时默认执行的命令。
大概就是这样。
Docker.Inc提供了根据git仓库自动构建镜像的服务,可以根据Dockerfilet版本的变化以及基础镜像的更新自动重新构建镜像。
我的这个nginx-server服务也已提交到,名为‘kagami/nginx-hhvm’。好吧,我就是想强注自己喜欢的id罢了。