Docker修炼第一招: 从Dockerfile开始

ty672769 8年前
   <p>东坡有诗:日建镜像三百个,不辞长用Dockerfile。</p>    <p>觉得镜像构建枯燥乏味?困货,快来根Dockerfile吧!</p>    <p>作为一枚构建镜像的老司机,下面跟大家展示一篇Dockerfile实战。</p>    <h2>Docker、Dockerfile、Docker镜像、容器这些都是什么鸟?</h2>    <p>老生常谈,再再再……普及一下:</p>    <ul>     <li><strong>Docker:</strong> 最早是dotCloud公司出品的一套容器管理工具,但后来Docker慢慢火起来了,连公司名字都从dotCloud改成Docker。</li>     <li><strong>Dockerfile:</strong> 它是Docker镜像的描述文件,可以理解成火箭发射的A、B、C、D……的步骤。</li>     <li><strong>Docker镜像:</strong> 通过Dockerfile做出来的,包含操作系统基础文件和软件运行环境,它使用分层的存储方式。</li>     <li><strong>容器:</strong> 是运行起来的镜像,简单理解,Docker镜像相当于程序,容器相当于进程。</li>    </ul>    <p>讲了这么多,大家可能已经意识到了,想玩转Docker必须先要搞定Docker镜像,镜像又来自于 <strong>Dockerfile</strong> ,因此本文从Dockerfile编写开始,与您分享Docker镜像的制作过程,里面有 <strong>经验</strong> ,有 <strong>技巧</strong> ,还有 <strong>彩蛋</strong> ~!</p>    <h2>如何通过Dockerfile快速构建镜像</h2>    <p>接下来,我们通过构建一个Tomcat镜像,来演示Dockerfile的使用方法,当然前提是你的电脑安装了Docker环境,如何安装Docker环境就不在此赘述了。</p>    <h3>1、创建一个Dockerfile</h3>    <p>Dockerfile命名必须为“Dockerfile”,Docker镜像构建时,会查找指定目录中的Dockerfile。</p>    <h3>2、编写Dockerfile</h3>    <p>(1)环境配置</p>    <p>首先,我们需要指定一个基础镜像,为了方便,我们从Ubuntu镜像开始。</p>    <pre>  bash    FROM ubuntu:14.04</pre>    <p>通过FROM指令,Docker编译程序能够知道通过哪个基础镜像执行来进行编译。所有的Dockerfile都必须以FROM指令开始。通过该指令,我们相当于有了一个最基本的Ubuntu系统。</p>    <p>(2)其他环境配置</p>    <p>我们可以像这样指定Dockerfile的作者。</p>    <pre>  bash    MAINTAINER example <example@goodrain.com></pre>    <p>另外我们需要指定时区,否则我们做出的镜像可能会跟当前时间不符。</p>    <pre>  bash    RUN echo "Asia/Shanghai" > /etc/timezone;dpkg-reconfigure -f noninteractive tzdata</pre>    <p>我们可以像在电脑上安装Tomcat一样,把Tomcat安装在Docker容器中。</p>    <p>(3)Tomcat必要软件安装。</p>    <p>我们此时使用的Ubuntu系统其实是很简陋的系统,上面很多系统都没有。所以我先安装一些必要的软件。</p>    <pre>  bash    RUN apt-get update && apt-get install -y curl vim net-tools && \        rm -rf /var/lib/apt/lists/* && mkdir -p /app</pre>    <p>RUN指令用来在Docker的编译环境中运行指定命令。这里我安装了 curl 、 vim 、 net-tools ,其中 curl 用来获取 java 和 tomcat 的安装包, vim 和 net-tools 用来调试,并创建了 /app 目录。</p>    <p>(4)指定工作目录</p>    <p>使用 WORKDIR /app 可以将工作目录定位到/app 目录下</p>    <p>(5)获取安装软件</p>    <p>我们使用 <strong>第 (3)步</strong> 安装的 curl 工具来获取安装包。</p>    <pre>  bash    RUN  curl -L 'http://download.oracle.com/otn-pub/java/jdk/7u65-b17/jdk-7u65-linux-x64.tar.gz' -H 'Cookie: oraclelicense=accept-securebackup-cookie; gpw_e24=Dockerfile' | tar -xz \        && curl -L 'http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.8/bin/apache-tomcat-7.0.8.tar.gz' | tar -xz</pre>    <p>以上命令将会从指定地址下载安装包,并解压到当前目录(上一步我们指定了工作空间为/app,所以会解压到此目录下)</p>    <p>(6)指定运行脚本</p>    <p>截止到上一步,我们已经将需要的准备工作都做好了,剩下的还有Java环境变量的设置,Tomcat环境变量设置(非必须)和Tomcat的启动。</p>    <pre>  bash    COPY tomcat7.sh /app/tomcat7.sh    RUN chmod +x /app/tomcat7.sh</pre>    <p>上面的两行命令会将与Dockerfile同级目录的tomcat7.sh文件上传到docker容器中的/app目录下,并且给该文件赋予可执行的权限。</p>    <p>看一眼该脚本的内容便一目了然了。</p>    <p>```bash</p>    <h2>Java环境变量配置</h2>    <p>export JAVA_HOME=/app/jdk1.7.0_65</p>    <p>export PATH=$JAVA_HOME/bin:$PATH</p>    <p>export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar</p>    <h2>Tomcat环境变量配置</h2>    <p>export TOMCAT_HOME=/app/apache-tomcat-7.0.8</p>    <p>export PATH=$TOMCAT_HOME/bin:$PATH</p>    <h2>启动 Tomcat</h2>    <p>exec $TOMCAT_HOME/bin/catalina.sh run</p>    <p>(7)指定端口</p>    <p>bash</p>    <p>EXPOSE 8080</p>    <p>```</p>    <p>通常情况下,Tomcat启动后会监听8080端口,在容器中也一样。</p>    <p>EXPOSE指令用于标明,这个镜像中的应用将会侦听某个端口,并且希望能将这个端口映射到主机的网络界面上</p>    <p>(8)指定脚本的运行</p>    <p>至此,我们要做的准备工作就做完了。使用下面这条命令,运行我们在第6步创建的脚本,一个简单的Tomcat的Dockerfile就编写完成了。</p>    <pre>  bash    ENTRYPOINT [“/app/tomcat7.sh"]</pre>    <p>ENTRYPOINT 用于标明一个镜像作为容器运行时,最后要执行的程序或命令。</p>    <h3>3.构建镜像</h3>    <p>进入Dockerfile所在目录,运行命令 docker build -t mytomcat . (注意最后有个点用来表示当前目录,初次构建速度会比较慢,需要多等一会。)</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/f52f4a96028e7a7720a2b1cb32b8880a.png"></p>    <p>出现如下信息就构建成功了</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/77015673a23a0cb5b77883aa632d9815.png"></p>    <h3>4.运行Docker容器</h3>    <pre>  bash    docker run -i -t -p 5000:8080 mytom</pre>    <p>其中,docker run 用于运行一个容器</p>    <ul>     <li>-t 在容器指定一个伪终端或者终端;</li>     <li>-i 进行命令交互;</li>     <li>-p 匹配镜像内的网络端口号,即我们可以通过宿主机中访问5000端口来达到访问容器8080端口的目的。</li>    </ul>    <h3>5.查看构建好的镜像和运行的容器</h3>    <pre>  bash    docker images  #查看镜像</pre>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/e910272f06a9c2b9cdc3312904bc9e54.png"></p>    <pre>  bash    docker ps -a #查看所有的容器</pre>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/86b2496ee803513b23b9d85e0130d9e7.png"></p>    <h3>6.查看服务是否运行</h3>    <p>在宿主机中我们输入localhost:5000访问,出现如下界面,表示Tomcat成功运行。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/d765035437394150de4cd609e48a815d.png"></p>    <p>至此,我们就成功的创建了一个Tomcat镜像了,当然这里只是为了简单演示,所以镜像做的比较简单,官方的Tomcat镜像比这复杂的多,在熟悉了Dockerfile后可以去看看官方的做法。</p>    <h3>6.其他</h3>    <p>在做镜像的时候有那么多步骤,根本不可能一次将所有的步骤完成,所以,这里教给大家一个 <strong>小技巧</strong> 。</p>    <p>在编写完Dockerfile到第二步的时候,其实可以先使用一个脚本先运行着,然后进入容器内部进行操作。笔者在编写Dockerfile时先使用如下命令</p>    <pre>  bash    COPY run.sh /app/run.sh    RUN chmod +x /app/run.sh    ENTRYPOINT [“/app/run.sh"]</pre>    <p>run.sh脚本的内容如下</p>    <pre>  bash    </pre>    <h2>!/bin/bash</h2>    <p>sleep 15</p>    <p>while true</p>    <p>do</p>    <p>echo &quot;true&quot;</p>    <p>sleep 180</p>    <p>done</p>    <p>其实就是一段死循环代码代替原有的tomcat7.sh,接着就可以build和run我们的容器了。容器运行起来后使用docker exec -it container_id bash 进入docker容器。此时就和我们平时装软件的方式一样了,做完一个步骤,在Dockerfile中记录一条,这样Dockerfile也就做出来了。(ps:exit退出容器。)</p>    <p>特别注意的一点,如果做好镜像以后,在镜像中有需要保存的数据(持久化目录)需要我们在Dockerfile中指定持久化目录。为了能够保存(持久化)数据以及共享容器间的数据,Docker提出了Volume的概念。简单来说,Volume就是目录或者文件,它可以绕过默认的联合文件系统,而以正常的文件或者目录的形式存在于宿主机上。并且我们运行容器的时候需要使用使用 -v 来声明Volume,如:</p>    <pre>  bash    docker run -it -v /home/dock/logs:/usr/logs tomcat /bin/bash</pre>    <p>冒号前为宿主机目录,必须为绝对路径,冒号后为镜像内挂载的路径,这样容器内更改的数据就被写到宿主机上了。</p>    <p>拥有了Tomcat服务器后,就可以跑写好的java-web程序了,如何运行java-web程序就不在此详述了,跟普通运行java-web程序一样。</p>    <p>同样的,如果你有一个web应用,将其放入Docker容器中,写好Dockerfile,构建好应用运行需要的环境后,就可以很快的使用应用了。</p>    <h2>彩蛋环节</h2>    <p>目前支持Java,PHP,Python等多种语言的应用,不用自己构建具体环境,可以直接从源码进行构建,十分方便。以上说的Dockerfile也是支持的。如果有写好的程序想要跑起来可以参照好雨进行部署。----------作者:,平台研发部</p>    <p> </p>    <p>来自:http://dockone.io/article/1866</p>    <p> </p>