DockerFile讲解

Published on 2016 - 07 - 31

2016-07-31 by:小停雨(Rich)
转载请注明

这篇文章以简单的LNMP环境为例,记录与说明一下如何撰写DockerFile

1.撰写Nginx的Dockerfile

FROM centos:6.7
WORKDIR /root
RUN yum update -y
RUN yum groupinstall -y "Development Tools"
RUN yum install -y pcre pcre-devel zlib zlib-devel
RUN yum install -y wget tar
RUN wget http://nginx.org/download/nginx-1.10.1.tar.gz
RUN tar zxvf nginx-1.10.1.tar.gz
RUN cd nginx-* \
    && ./configure \
    && make \
    && make install
COPY ./conf /usr/local/nginx/conf
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx"]

2.撰写PHP的Dockerfile

FROM centos:6.7
WORKDIR /root
RUN rpm --import http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-6 \
    && rpm --import https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6 \
    && rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm \
    && rpm -Uvh https://mirror.webtatic.com/yum/el6/latest.rpm    
RUN yum update -y
RUN yum groupinstall -y "Development Tools"
RUN yum install -y php70w
RUN yum install -y php70w-devel php70w-pdo php70w-mysqlnd php70w-fpm php70w-opcache php70w-cli php70w-gd php70w-mcrypt php70w-mbstring php70w-xml
COPY ./etc /etc
EXPOSE 9000
CMD ["php-fpm"]

3.撰写Mysql的Dcokerfile

FROM mysql:5.7
(是不是奇怪怎么就一行?后面一起讲解docker仓库)

4.讲解Dockerfile的内容

如果细心观察上面的Dockerfile就会发现,原来dockerfile也不过就是一条一条的shell命令,但是shell命令前面都会有一段特殊的行为标识,这个行为标识来告诉docker要做一些什么,下面挨个说一下:

FROM:表示基于哪个镜像,看了上一篇docker基础文章的都知道docker pull命令,如果dockerfile里有了FROM命令,那么就代表运行docker pull,以本文的Nginx ‘DF’来举例, "FROM centos:6.7 = docker pull centos:6.7"

RUN:构建指令,RUN可以运行任何被基础image支持的命令。如基础image选择了centos    ,那么软件管理部分只能使用centos的命令。

WORKDIR:这一条很重要,是用来指定工作目录,如果'DF'中有了这一句,就代表在当前的Dockerfile中所有处于WORKDIR下面的命令都是在指定的工作目录中执行,比如wget, vi, sed等操作,都会在指定的工作目录中执行。

COPY:是拷贝命令,可以从真机拷贝一些文件到docker中,这个命令很常用,比如本文的Nginx,mysql与PHP都拷贝了一些配置文件到docker中。

EXPOSE:开放端口,该指令会将容器中的端口映射成宿主机器中的某个端口。当你需要访问容器的时候,可以不是用容器的IP地址而是使用宿主机器的IP地址和映射后的端口。要完成整个操作需要两个步骤,首先在Dockerfile使用EXPOSE设置需要映射的容器端口,然后在运行容器的时候指定-p选项加上EXPOSE设置的端口,这样EXPOSE设置的端口号会被随机映射成宿主机器中的一个端口号。也可以指定需要映射到宿主机器的那个端口,这时要确保宿主机器上的端口号没有被使用。EXPOSE指令可以一次设置多个端口号

CMD:执行命令,用于container启动时指定的操作。该操作可以是执行自定义脚本,也可以是执行系统命令。该指令只能在文件中存在一次,如果有多个,则只执行最后一条。
格式:CMD ["param1","param2"] (as default parameters to ENTRYPOINT)    

MAINTAINER:用来指定镜像创建者信息

ENTRYPOINT:设置container启动时执行的操作,指定容器启动时执行的命令,可以多次设置,但是只有最后一个有效。
格式:ENTRYPOINT ["executable", "param1", "param2"] (like an exec, the preferred form)  
     ENTRYPOINT command param1 param2 (as a shell)  
该指令的使用分为两种情况,一种是独自使用,另一种和CMD指令配合使用。
当独自使用时,如果你还使用了CMD命令且CMD是一个完整的可执行的命令,那么CMD指令和ENTRYPOINT会互相覆盖只有最后一个CMD或者ENTRYPOINT有效。

USER:设置启动容器的用户,默认是root用户。
USER daemon     

ENV:在image中设置一个环境变量。
格式:ENV <key> <value>
设置了后,后续的RUN命令都可以使用,container启动后,可以通过docker inspect查看这个环境变量,也可以通过在docker run --env key=value时设置或修改环境变量。假如你安装了JAVA程序,需要设置JAVA_HOME,那么可以在Dockerfile中这样写:
ENV JAVA_HOME /path/to/java/dirent        

ADD:从src复制文件到container的dest路径
所有拷贝到container中的文件和文件夹权限为0755,uid和gid为0;如果是一个目录,那么会将该目录下的所有文件添加到container中,不包括目录;如果文件是可识别的压缩格式,则docker会帮忙解压缩(注意压缩格式);如果<src>是文件且<dest>中不使用斜杠结束,则会将<dest>视为文件,<src>的内容会写入<dest>;如果<src>是文件且<dest>中使用斜杠结束,则会<src>文件拷贝到<dest>目录下。
格式:ADD <src> <dest>

VOLUME:指定挂载点,使容器中的一个目录具有持久化存储数据的功能,该目录可以被容器本身使用,也可以共享给其他容器使用。我们知道容器使用的是AUFS,这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令。
格式:VOLUME ["<mountpoint>"] 
FROM base  
VOLUME ["/tmp/data"]  
运行通过该Dockerfile生成image的容器,/tmp/data目录中的数据在容器关闭后,里面的数据还存在。例如另一个容器也有持久化数据的需求,且想使用上面容器共享的/tmp/data目录,那么可以运行下面的命令启动一个容器:
docker run -t -i -rm -volumes-from container1 image2 bash
#container1为第一个容器的ID,image2为第二个容器运行image的名字。

5.DockerFile缓存(重点)

DockerFile是带有缓存功能的,下面简单说一下如何操作缓存,已上面的Nginx为例,当执行一遍Dockerfile之后,再次执行,会发现只需要1秒或者2秒就可以再次制作一个镜像,这就是人性化的缓存功能,每执行的一条命令都会被缓存起来,但是如何来清除缓存呢?

例子:

FROM centos:6.7
WORKDIR /root
RUN yum update -y
RUN yum groupinstall -y "Development Tools"
RUN yum install -y pcre pcre-devel zlib zlib-devel
RUN yum install -y wget tar
RUN wget http://nginx.org/download/nginx-1.10.1.tar.gz
RUN tar zxvf nginx-1.10.1.tar.gz
RUN cd nginx-* \
    && ./configure \
    && make \
    && make install
COPY ./conf /usr/local/nginx/conf
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx"]

当运行一次之后有了缓存,只需要在想开始清除缓存的地方随便做一点点改动,就会清除从所改动行开始向下的所有缓存,比如我们在RUN yum install -y wget tar这一句上面添加一句 RUN echo hello, 那么从所添加这一句开始算起,向下所有行的缓存都会被清除,如果下面有下载软件的命令就会重新下载,不会再从缓存提取。所以合理的撰写与修改Dockerfile是很重要的,可以帮我们节省很多时间,相关的改动都尽量放在下边,下载等操作都尽量放在DF的上边。

6.构建镜像

docker build -t rich/nginx .  
docker run -d -p 8090:8080 rich/nginx

结束语

简单的Dockerfile就撰写完了,其中有几点要注意:

1.Dockerfile是严格的按照顺序执行。

2.合理的修改DF,合理的利用缓存,下载等耗时操作尽量放到上边几行,这样可以利用缓存节省时间

3.不要被cd命令误导,如果你的cd命令在 WORKDIR 下面,那么执行cd是没有效果的,因为在指定了WORKDIR后每一行DF命令都是在指定的工作目录中执行,cd虽然会成功进入你想进入的文件夹,但是cd下一条命令又会在WORKDIR中执行,所以如果你想在DF中使用cd命令请使用 &&, 比如 cd nginx && make && make install 与cd合并为同一条命令执行即可。

4.上文中所有的DF都是DockerFile的缩写

2016-07-31 by:小停雨(Rich)
转载请注明