Dockerfile(Dockerfile的详细使用、通过Dockerfile构建apache镜像)

1 Dockerfile介绍

前面的docker镜像管理章节有说到,构建镜像的方式有两种:

  • 一种是基于容器制作
  • 另一种就是通过Dockerfile。Dockerfile其实就是我们用来构建Docker镜像的源码,当然这不是所谓的编程源码,而是一些命令的组合,只要理解它的逻辑和语法格式,就可以编写Dockerfile了。

简要概括Dockerfile的作用:它可以让用户个性化定制Docker镜像。因为工作环境中的需求各式各样,网络上的镜像很难满足实际的需求。

2 基本结构

  • Dockerfile 是一个文本格式的配置文件,用户可以使用 Dockerfile 快速创建自定义镜像。

  • Dockerfile 由一行行命令语句组成,并且支持以 # 开头的注释行。

  • Dockerfile整体就两类语句组成

    • Comment 注释信息
    • Instruction arguments 指令 参数,一行一个指令
    • Dockerfile文件名首字母必须大写。
    • Dockerfile指令不区分大小写,但是为方便和参数做区分,通常指令使用大写字母。
  • Dockerfile中指令按顺序从上至下依次执行。

  • Dockerfile中第一个非注释行必须是FROM指令,用来指定制作当前镜像依据的是哪个基础镜像。

  • Dockerfile中需要调用的文件必须跟Dockerfile文件在同一目录下,或者在其子目录下,父目录或者其它路径无效。

2.1 Dockerfile分为四部分

  • 基础镜像信息
  • 维护者信息
  • 镜像操作指令
  • 容器启动时默认要执行的指令

3 Dockerfile 基础知识

指令的一般格式为INSTRUCTION arguments,指令包括:

FROM		#基础镜像,一切从这里开始构建
MAINTAINER	#镜像是谁写的,姓名+邮箱
RUN			#镜像构建的时候需要运行的命令
ADD			#步骤,tomcat镜像,这个tomcat的压缩包!添加内容
WORKDIR		#镜像的工作目录	
VOLUME		#挂载的目录
EXPOSE		#暴露端口配置
CMD			#指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT	#指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD		#当构建一个被继承 Dockerfile 这个时候就会运行ONBUILD 的指令
COPY 		#类似ADD,将我们文件拷贝到镜像中
ENV			#构建的时候设置环境遍量
//示例
#第一行必须指定基于的基础镜像
FROM centos

#维护人的信息
LABEL MAINTAINER="CWT <[email protected]>"

#安装httpd软件包
RUN yum -y update  && 
    yum -y install httpd

#开启80端口
EXPOSE 80

#复制网站首页文件至镜像中web站点下
ADD index.html /var/www/html/index.html

#复制该脚本至镜像中,并修改其权限
ADD httpd.sh /httpd.sh
RUN chmod 775 /httpd.sh

#当启动容器时默认要执行的动作
CMD ["/httpd.sh"]

其中,一开始必须指明所基于的镜像名称,接下来一般会说明维护者信息。
后面则是镜像操作指令,例如RUN指令,RUN指令将对镜像执行跟随的命令。每运行一条RUN指令,镜像添加新的一层,并提交。
最后是CMD指令来指定运行容器时的操作指令。

4 Dockerfile常用指令

4.1 FROM

第一条指令必须为FROM指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令(每个镜像一次)

//语法格式:FROM <image>或FROM <imagge>:<tag>

//构建新镜像是基于那个镜像
FROM centos:7

4.2 LABEL MAINTAINER

指定维护者信息

//语法格式: MAINTAINER <name email_address>
LABEL MAINTAINER='[email protected]'

4.3 RUN

RUN指令将对镜像执行跟随的命令

//RUN指令的语法格式有两种:

shell格式:(默认用/bin/sh -c来执行)
RUN <command>  RUN <命令行命令>
# <命令行命令> 等同于,在终端操作的 shell 命令。

exec格式:
RUN ["executable","param1","param2"]  RUN ["可执行文件", "参数1", "参数2"]
# 例如:
# RUN ["./test.php", "dev", "offline"] 等价于 RUN ./test.php dev offline

注意: 每运行一条RUN指令,镜像添加新的一层,并提交,所以过多无意义的层,会造成镜像膨胀过大。所以当命令较长时可以使用 来换行

RUN echo "hello worldnhello tom" > /tmp/abc && 
    cat /tmp/abc

4.4 CMD

  • 指定启动容器时默认执行的命令,即:如果docker run没有指定任何的执行命令或者dockerfile里面也没有ENTRYPOINT,那么就会使用执行CMD指定的默认的命令
  • 每个 Dockerfile 只能有一条 CMD 命令。如指定了多条,只有最后一条被执行
  • 如果用户启动容器时指定了运行的命令,如:docker run xxx /bin/bash,则/bin/bash 会覆盖 CMD 指定的命令
//语法格式:
CMD ["executable","param1","param2"]使用exec执行,推荐方式
CMD command param1 param2在/bin/sh中执行,提供给需要交互的应用
CMD ["param1","param2"]提供给ENTRYPOINT的默认参数

例如:CMD ["nginx", "-g", "daemon off;"]

4.5 EXPOSE

EXPOSE用于告诉Docker服务器容器暴露的端口号,供互联系统使用。
在启动容器时通过-P,Docker主机会自动分配一个端口转发到指定的端口,使用-p则可以具体指定哪个本地端口映射过来

//语法格式:EXPOSE <port> [<port>...]

例如:EXPOSE 80 443 22

4.6 ENV

指定一个环境变量,会被后续 RUN 指令使用,并在容器运行时保持

//语法格式:
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...


例如:
ENV NODE_VERSION 7.2.0

RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" 
    && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"

4.7 COPY

  • 复制本地主机的(为Dockerfile所在目录的相对路径,文件或目录)为容器中的。目标路径不存在时会自动创建
  • 使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等
  • 如果是目录,只复制目录内容,而非目录本身
//语法格式:
COPY [--chown=<user>:<group>] <src>...  <dest>
COPY [--chown=<user>:<group>] ["<src>",...  "<dest>"]

[--chown=<user>:<group>]:可选参数,用户改变复制到容器内文件的拥有者和属组。

<源路径>:源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:
COPY hom* /mydir/
COPY hom?.txt /mydir/

4.8 ADD

  • 该命令将复制指定的到容器中的。其中可以是Dockerfile所在目录的一个相对路径(文件或目录);也可以是一个URL;还可以是一个tar文件(会自动解压为目录)

  • ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下

    • ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
    • ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
  • 如果src是目录,只复制目录中的内容,而非目录本身

  • 如果src是一个 URL ,下载后的文件权限自动设置为 600

//语法格式: 
ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"] 


例如:
ADD test /absoluteDir/         
ADD --chown=55:mygroup files* /somedir/
ADD --chown=bin files* /somedir/
ADD --chown=1 files* /somedir/
ADD --chown=10:11 files* /somedir/
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz 

4.9 ENTRYPOINT

  • 类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,如果在docker run的后面提供了参数会被当作参数传递给 ENTRYPOINT 指令指定的程序。
  • 每个Dockerfile中只能有一个ENTRYPOINT,当指定多个ENTRYPOINT时,只有最后一个生效。
  • 但是, 如果运行 docker run 时使用了 --entrypoint 选项,此选项的参数可当作要运行的程序覆盖 ENTRYPOINT 指令指定的程序。
//语法格式:
ENTRYPOINT ["executable","param1","param2"]
ENTRYPOINT command param1 param2(在shell中执行)


例如:
FROM nginx

ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参 

运行容器:docker run  nginx:test				#没有传参

容器内会默认运行以下命令,启动主进程。
nginx -c /etc/nginx/nginx.conf


docker run  nginx:test -c /etc/nginx/new.conf			#传参

容器内会默认运行以下命令
nginx -c /etc/nginx/new.conf

4.10 VOLUME

创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等

//语法格式:
VOLUME ["<容器内路径1>", "<容器内路径2>"...]
VOLUME <路径>

//例如
VOLUME /data

4.11 USER

  • 指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户
  • 这个用户必须是事先建立好的,否则无法切换
  • 要临时获取管理员权限可以使用 gosu,而不推荐 sudo
  • 当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户
//语法格式:
USER <user>[:<group>] 
USER <UID>[:<GID>]


例如:
RUN groupadd -r mysql && useradd -r -g mysql mysql
USER mysql

4.12 WORKDIR

  • 指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。

  • docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。

  • 可以使用多个WORKDIR指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。

//语法格式:
WORKDIR <工作目录路径>


例如:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
最终路径为/a/b/c

4.13 ONBUILD

用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这是执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。

//语法格式:ONBUILD [INSTRUCTION]


例如,Dockerfile使用如下的内容创建了镜像test-build
[...]
ONBUILD ADD nginx.conf /usr/local/nignx/nginx.conf
ONBUILD RUN mkdir /data
[...]


此时,如果基于test-build创建新的镜像时,新的Dockerfile中使用FROM test-build指定基础镜像时,会自动执行ONBUILD指令的内容,等价于在后面添加了两条指令。

FROM test-build

# Automatically run the following
ADD nginx.conf /usr/local/nignx/nginx.conf
RUN mkdir /data

5 构建镜像注意事项

  • 编写完成Dockerfile后,可以通过docker build命令来创建镜像。

  • 基本的格式为docker build [选项] 路径,该命令将读取指定路径下(包括子目录)的Dockerfile,并将该路径下所有内容发送给Docker服务端,由服务端来创建镜像。因此一般建议放置Dockerfile的目录为空目录。

  • 另外,可以通过 .dockerignore 文件(每一行添加一条匹配模式)来让Docker忽略路径下的目录和文件。

  • 要指定镜像的标签信息,可以通过-t选项。

  • 例如,指定Dockerfile所在路径为/tmp/docker_builder/,并且希望生成镜像标签为build_repo/first_image,可以使用下面的命令

docker build -t build_repo/first_image /tmp/docker_builder/

6 使用Dockerfile构建apache镜像

//创建目录
[root@docker ~]# ls
anaconda-ks.cfg
[root@docker ~]# mkdir /apache
[root@Docker ~]# cd /apache/
[root@Docker apache]# touch Dockerfile
[root@Docker apache]# ls
Dockerfile

[root@Docker apache]# mkdir packages
[root@Docker apache]# cd packages/
[root@Docker packages]# mv /usr/src/apr-1.7.0.tar.gz .
[root@Docker packages]# mv /usr/src/apr-util-1.6.1.tar.gz .
[root@Docker packages]# mv /usr/src/httpd-2.4.48.tar.gz .

[root@Docker ~]# tree
.
├── anaconda-ks.cfg
└── apache
    ├── Dockerfile
    └── packages
        ├── apr-1.7.0.tar.gz
        ├── apr-util-1.6.1.tar.gz
        └── httpd-2.4.48.tar.gz


/编写dockerfile
[root@Docker ~]# cat apache/Dockerfile
# 第一行必须指定基于的基础镜像
FROM centos

# 维护者信息
LABEL MAINIAINER='[email protected]'

ENV PATH /usr/local/apache/bin:$PATH
ENV apr_version=1.7.0 apr_util_version=1.6.1 httpd_version=2.4.48

# 将源码包传到指定文件,并会自动解压
ADD packages/* /usr/src/

# 切换到当前所在目录
WORKDIR /usr/src/

# 镜像操作指令
# 下载所需的安装包
RUN yum -y install openssl-devel pcre-devel pcre  expat-devel libtool gcc gcc-c++ make  &&  
 
# 编译安装apr
    cd apr-1.7.0 && sed -i '/$RM "$cfgfile"/d' configure &&  
    ./configure --prefix=/usr/local/apr  &&     make && make install  &&  
# 编译安装apr-util
    cd ../apr-util-1.6.1  && 
    ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr  && 
    make && make install  &&  
# 编译安装httpd
    cd ../httpd-2.4.48    &&  
    ./configure --prefix=/usr/local/apache 
    --enable-so 
    --enable-ssl 
    --enable-cgi 
    --enable-rewrite 
    --with-zlib 
    --with-pcre 
    --with-apr=/usr/local/apr 
    --with-apr-util=/usr/local/apr-util/ 
    --enable-modules=most 
    --enable-mpms-shared=all 
    --with-mpm=prefork   && 
    make && make install  &&  
    sed -i '/#ServerName/s/#//g' /usr/local/apache/conf/httpd.conf 

#暴露端口号
EXPOSE 80 443

#设置存储卷 
VOLUME ["/usr/local/apache/htdocs/"]          

#启动命令
CMD  ["-D","FOREGROUND"]                 
ENTRYPOINT ["/usr/local/apache/bin/apachectl"]

//创建镜像
[root@Docker ~]# docker build -t caiaoc/apache:latest /apache/

[root@docker ~]# docker images
REPOSITORY      TAG       IMAGE ID       CREATED        SIZE
caiaoc/apache   latest    3b1fe562c6f6   12 hours ago   701MB
nginx           latest    f652ca386ed1   6 days ago     141MB
busybox         latest    d23834f29b38   9 days ago     1.24MB
httpd           latest    ad17c88403e2   2 weeks ago    143MB
centos          latest    5d0da3dc9764   2 months ago   231MB



//使用刚刚创建的镜像启动容器,开放端口,创建容器
[root@docker apache]# docker run --name apache1 -itd -p 80:80 caiaoc/apache:latest
7e6e7a2bc6b460eba55d55a61acdf89ac8d9e316ffa73ca0e541fddf378d9791
[root@docker apache]# docker exec -it apache1 /bin/bash
[root@7e6e7a2bc6b4 src]# ss -antl
State     Recv-Q    Send-Q         Local Address:Port         Peer Address:Port    Process    
LISTEN    0         128                  0.0.0.0:80                0.0.0.0:*                  

通过网页访问测试
在这里插入图片描述

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>