Docker镜像构建

1、如何构建Docker镜像

制作属于自己的Docker镜像,一般有两种方式:

  • 第一种为commit方式,利用已有的镜像,运行为容器后安装定制自己需要的环境,然后由容器生成镜像;
  • 另一种就是build方式,通过编写Dockerfile文件添加构建镜像指令生成镜像。

1、docker commit构建镜像

docker commit 命令主要作用是将已经配置好运行环境的容器重新提交为镜像;此时提交成功的镜像就可以使用,并且环境已经配置好,不需要配置环境。

格式:
    docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]

选项:
    --author		//指定修改的作者
    --message		//记录本次修改的内容

示例:
    docker commit --author "ZzHan <hzz@163.com>" --message "修改了默认网页" nginx01 nginx:v2

2、Dockerfile构建镜像

2.1 Dockerfile简介

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明;Docker 通过读取Dockerfile 中的指令自动生成镜像。

Dockerfile 是官方推荐的方式,这样可以让使用者更清晰地看到这个镜像的制作细节,逻辑清晰,便于管理。

FROM centos:7		//加载基础镜像,后续基于此镜像向里面继续添加内容
RUN yum -y install vim	//向基础镜像中安装一个vim编辑器
CMD ["/bin/bash"]	//镜像启动为容器后默认执行的指令

Dockerfile 文件编写完成后需要使用 docker build 命令将 Dockerfile 文件中的构建镜像指令加载运行,由此生成镜像。

2.2 docker build命令

docker build 命令用于从Dockerfile构建镜像。

格式:
    docker build  -t 镜像名:镜像标签 -f Dockerfile文件名 .

选项:
    -t		//指定通过Dockerfile文件构建的镜像名称和标签
    -f		//指定Dockerfile文件名

2.3 Dockerfile镜像构建指令

FROM : Dockerfile中第一条指令必须是FROM指令,表示从哪个基础镜像开始构建镜像

FROM centos:7	//基于centos7基础镜像构建新的镜像
FROM scratch	//表示不以任何镜像为基础

MAINTAINER : 镜像维护者个人信息,维护者的姓名和邮箱

MAINTAINER "ZzHan <***@163.com>"	//维护者姓名和邮箱

RUN : 构建镜像时需要执行的命令,有两种命令执行方式

shell形式执行
格式:
    RUN <command>	//RUN后边直接跟shell命令,linux操作系统上默认shell为/bin/sh -c
    
exec形式执行
格式:
    RUN ["executable", "param1", "param2"]	//执行可执行文件,executable为可执行文件,param为选项或参数;exec形式可以指定使用其他终端

两种形式对比:
    RUN echo "hzz"
    RUN ["/bin/bash", "-c", "echo hello"]

注:多行命令不要写多个RUN,Dockerfile中每一个RUN指令都会建立一层镜像,多少个RUN就构建了多少层镜像,会造成镜像的臃肿、多层,不仅仅增加了构件部署的时间,还容易出错。

ADD :将本地文件添加到构建的镜像中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget

    ADD <src>... <dest>
    ADD ["<src>",... "<dest>"]	//用于支持包含空格的路径
示例:
    ADD test /tmp/    		//添加"test"文件到镜像的"/tmp"目录
    ADD hom* /mydir/		//添加所有以"hom"开头的文件到镜像的"/mydir"目录

COPY :功能类似ADD,但是是不会自动解压文件,也不能访问网络资源


CMD : 指定镜像启动为容器后默认执行的命令,每个 Dockerfile 只能有一条 CMD 命令;如果指定了多条命令,只有最后一条会被执行,如果用户启动容器时候指定了运行的命令,则会覆盖掉 CMD 指定的命令

格式:
    CMD ["executable","param1","param2"]	//执行可执行文件,此方式优先
    CMD command param1 param2 			//执行shell内部命令
    CMD ["param1","param2"]			//设置了ENTRYPOINT,则为ENTRYPOINT添加参数

示例:
    CMD ["echo","This is a test"]
    CMD echo "This is a test"

ENTRYPOINT : 类似于 CMD 指令,但其不会被创建容器时指定的命令覆盖,如果创建容器时指定了命令那么这些命令会被当作参数送给 ENTRYPOINT 指令指定的程序;CMD 和ENTRYPOINT 同在时 CMD 的内容会被当作参数传递给 ENTRYPOINT 指定的命令。

格式:
    ENTRYPOINT ["executable", "param1", "param2"] 	//执行可执行文件, 此方式优先
    ENTRYPOINT command param1 param2 			//shell内部命令

ENV :设置环境变量。此环境变量为镜像启动为容器之后容器中的环境变量

格式:
    ENV <key> <value>		//<key>之后的所有内容均会被视为其<value>的组成部分,因此,一次只能设置一个变量
    ENV <key>=<value> ...	//可以设置多个变量,每个变量为一个"<key>=<value>"的键值对,如果<key>中包含空格,可以使用\来进行转义,也可以通过""来进行标示

示例:
    ENV myName zhuang han
    ENV myName="zhuang han" myAge="100"
    ENV HTTPD_MPM="event"

EXPOSE :指定镜像启动为容器后开放的端口

格式:
    EXPOSE <port> [<port>...]

示例:
    EXPOSE 80 443
    EXPOSE 8080
    EXPOSE 11211/tcp 11211/udp

注:EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口。

WORKDIR :工作目录,类似于cd命令

格式:
    WORKDIR /path/to/workdir

示例:
    WORKDIR /hzz  //这时工作目录为/hzz

注:通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都会在该目录下执行。

USER :指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户

 格式:
  USER user
  USER user:group
  USER uid
  USER uid:gid

 示例:
  USER www

 注:使用USER指定用户后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都将使用该用户。

ARG :在构建镜像时设置变量,此变量只在Dockerfile中有效

格式:
    ARG <name>[=<default value>]

示例:
    ARG Site="/var/www/html"
    RUN mkdir $Site

VOLUME :创建镜像时指定挂载点,一旦此镜像被启动为容器,则自动为该容器挂载匿名卷

格式:
    VOLUME ["/path/to/dir"]

示例:
    VOLUME ["/data"]
    VOLUME ["/var/www","/var/log/apache2","/etc/apache2"]

ONBUILD :用于设置镜像触发器,当有其他镜像以此镜像为基础镜像时自动调用 ONBUILD 指定的命令

格式:
  ONBUILD [INSTRUCTION]

示例:
    ADD test /tmp/
    ONBUILD ADD test /tmp/	//ONBUILD用于基础镜像中

HEALTHCHECK :镜像启动为容器后健康状况检查命令

格式:
    HEALTHCHECK [OPTIONS] CMD command	//在容器内部运行一个命令来检查容器的健康状况
    HEALTHCHECK NONE			//如果基础镜像有健康检查指令,使用此指令可以屏蔽掉其健康检查指令

选项
    --interval=<间隔>	//两次健康检查的间隔,默认为 30 秒
    --timeout=<时长>	//健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒
    --retries=<次数>	//当连续失败指定次数后,则将容器状态视为 unhealthy,默认 3 次

示例:
    HEALTHCHECK --interval=5m --timeout=3s CMD curl http://localhost || exit 1