Docker学习笔记(二) —— 使用Dockerfile 定制镜像

Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,所以每一条指令的内容,就是描述该层应当如何构建。mysql

Dockerfile 指令

FROM 指定基础镜像

ROM 就是指定 基础镜像,Dockerfile 中 FROM 是必备的指令,而且必须是第一条指令。nginx

FROM scratch 表示一个空白镜像。因此 scratch 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将做为镜像第一层开始存在。sql

RUN 执行命令

RUN 指令是用来执行命令行命令的。因为命令行的强大能力,RUN 指令在定制镜像时是最经常使用的指令之一。其格式有两种:docker

  • shell 格式:RUN <命令> ,就像直接在命令行中输入的命令同样。刚才写的 Dockerfile 中的 RUN 指令就是这种格式
  • exec 格式:RUN ["可执行文件", "参数1", "参数2"],这更像是函数调用中的格式。

须要注意的是,Dockerfile 中每个指令都会创建一层,因此每一个Run都会建立一层镜像,若是有多个命令能够尽可能写在一个RUN里面。可使用&& 串联起来shell

COPY 复制文件

  • COPY [--chown= : ] <源路径> ... <目标路径>
  • COPY [--chown= : ] [" <源路径1> ",... " <目标路径> "]

<目标路径> 能够是容器内的绝对路径,也能够是相对于工做目录的相对路径(工做目录能够用 WORKDIR 指令来指定)。目标路径不须要事先建立,若是目录不存在会在复制文件前先行建立缺失目录。 数据库

使用 COPY 指令,源文件的各类元数据都会保留。好比读、写、执行权限、文件变动时间等。
在使用该指令的时候能够加上 --chown= : 选项来改变文件的所属用户及所属组。 缓存

COPY --chown=55:mygroup files* /mydir/
COPY --chown=bin files* /mydir/
COPY --chown=1 files* /mydir/
COPY --chown=10:11 files* /mydir/

ADD 更高级的复制

ADD 和 COPY 的格式和性质都是基本一致的。区别在于:服务器

  • 好比 <源路径> 能够是一个 URLDocker 引擎会试图去下载这个连接的文件放到 <目标路径> 去。下载后的文件权限自动设置为 600。
  • <源路径> 为一个 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的状况下,ADD 指令将会自动解压缩这个压缩文件到 <目标路径> 去

若是权限须要调整的话就须要另外的一层RUN,因此并不推荐使用。
对于复制文件,应该尽量的使用COPY。网络

CMD 容器启动命令

与RUN类似,有两种格式:架构

  • shell 格式:CMD <命令>
  • exec 格式:CMD ["可执行文件", "参数1", "参数2"...]

容器就是进程,因此在启动容器的时候须要指定所运行的程序及参数。CMD 指令就是用于指定默认容器主进程的启动命令的。

在运行时能够指定新的命令来替代镜像设置中的这个默认命令。

须要注意的是 Docker 不是虚拟机,容器中的命令都应该之前台执行而不是像虚拟机、物理机里面那样,用 systemd 去启动后台服务,容器内没有后台服务的概念

对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它须要关心的东西。

栗子:
  • 错误的写法
CMD service nginx start
  • 正确的写法
CMD ["nginx", "-g", "daemon off;"]

ENTRYPOINT 入口点

ENTRYPOINT 的目的和 CMD 同样,都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也能够替代,不过比 CMD 要略显繁琐,须要经过 docker run 的参数 --entrypoint 来指定。

当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,再也不是直接的运行其命令,而是将 CMD 的内容做为参数传给 ENTRYPOINT 指令,换句话说实际执行时,将变为:

<ENTRYPOINT> "<CMD>"

ENTRYPOINT的做用:

  • 应用运行前的准备工做,好比mysql镜像在启动时执行相关的sql,能够写一个脚本,而后放入 ENTRYPOINT 中去执行,这个脚本会将接到的参数(也就是 )做为命令,在脚本最后执行。

ENV 设置环境变量

格式:

  • ENV
  • ENV = = ...

支持环境变量的指令:ADD、COPY、ENV、EXPOSE、LABEL、USER、WORKDIR、VOLUME、STOPSIGNAL、ONBUILD。

ARG 构建参数

格式:ARG <参数名> [= <默认值> ]

构建参数和 ENV 的效果同样,都是设置环境变量。所不一样的是,ARG 所设置的构建环境的环境变量,在未来容器运行时是不会存在这些环境变量的。可是不要所以就使用 ARG 保存密码之类的信息,由于 docker history 仍是能够看到全部值的。

Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值能够在构建命令 docker build 中用 --build-arg <参数名> = <值> 来覆盖。

VOLUME 定义匿名卷

格式:

  • VOLUME [" <路径1> ", " <路径2> "...]
  • VOLUME <路径>

容器运行时,应该尽可能保持容器存储层不发生写操做,对于数据库类须要保存动态数据的应用,其数据库文件应该保存于卷(VOLUME)中。在Dockerfile中,能够事先指定某些目录为挂载为你命卷,这样在运行时若是用户不指定挂载,其应用也能够正常运行,不会向容器存储层写入大量数据。

VOLUME /data

这里的 /data 目录就会在运行时自动挂载为匿名卷,任何想 /data 中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。固然,运行时能够覆盖这个挂载设置。好比:

docker run -d -v mydata:/data xxxx

在这行命令中,就使用了 mydata 这个命名卷挂载到了 /data 这个位置,替代了 Dockerfile 中定义的匿名卷的挂载配置。

EXPOSE 声明端口

格式:

  • EXPOSE <端口1> [ <端口2> ...]。

EXPOSE 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会由于这个声明应用就会开启这个端口的服务。

WORKDIR 指定工做目录

格式:WORKDIR <工做目录路径>

使用 WORKDIR 指令能够来指定工做目录(或者称为当前目录),之后各层的当前目录就被改成指定的目录,如该目录不存在,WORKDIR 会帮你创建目录

若是须要改变之后各层的工做目录的位置,应该使用 WORKDIR 指令。

USER 指定当前用户

格式:

  • USER 指定当前用户

USER 指令和 WORKDIR 类似,都是改变环境状态并影响之后的层。WORKDIR 是改变工做目录,USER 则是改变以后层的执行 RUN, CMD 以及 ENTRYPOINT 这类命令的身份。

和 WORKDIR 同样,USER 只是切换到指定的用户而已,这个用户必须是事先创建好的,不然没法切换。

HEALTHCHECK 健康检查

格式:

  • HEALTHCHECK [选项] CMD <命令> :设置检查容器健康情况的命令
  • HEALTHCHECK NONE:若是基础镜像有健康检查指令,使用这行能够屏蔽掉其健康检查指令

当在一个镜像指定了 HEALTHCHECK 指令后,用其启动容器,初始状态会为 starting,在 HEALTHCHECK 指令检查成功后变为 healthy,若是连续必定次数失败,则会变为 unhealthy。

HEALTHCHECK 支持下列选项:

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

和 CMD, ENTRYPOINT 同样,HEALTHCHECK 只能够出现一次,若是写了多个,只有最后一个生效。

ONBUILD 为他人作嫁衣裳

格式:

  • ONBUILD <其它指令> 。

ONBUILD 是一个特殊的指令,它后面跟的是其它指令,好比 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。

docker build 构建命令

格式:

docker build [OPTIONS] PATH | URL | -

参数:

  • -build-arg=[] :设置镜像建立时的变量;

  • --cpu-shares :设置 cpu 使用权重;

  • --cpu-period :限制 CPU CFS周期;

  • --cpu-quota :限制 CPU CFS配额;

  • --cpuset-cpus :指定使用的CPU id;

  • --cpuset-mems :指定使用的内存 id;

  • --disable-content-trust :忽略校验,默认开启;

  • -f :指定要使用的Dockerfile路径;

  • --force-rm :设置镜像过程当中删除中间容器;

  • --isolation :使用容器隔离技术;

  • --label=[] :设置镜像使用的元数据;

  • -m :设置内存最大值;

  • --memory-swap :设置Swap的最大值为内存+swap,"-1"表示不限swap;

  • --no-cache :建立镜像的过程不使用缓存;

  • --pull :尝试去更新镜像的新版本;

  • --quiet, -q :安静模式,成功后只输出镜像 ID;

  • --rm :设置镜像成功后删除中间容器;

  • --shm-size :设置/dev/shm的大小,默认值是64M;

  • --ulimit :Ulimit配置。

  • --tag, -t: 镜像的名字及标签,一般 name:tag 或者 name 格式;能够在一次构建中为一个镜像设置多个标签。

  • --network: 默认 default。在构建期间设置RUN指令的网络模式

镜像构建上下文(Context)

docker build 命令最后有一个 .。. 表示当前目录,而 Dockerfile 就在当前目录,所以很多初学者觉得这个路径是在指定 Dockerfile 所在路径,这么理解实际上是不许确的。若是对应上面的命令格式,你可能会发现,这是在指定 上下文路径。那么什么是上下文呢?

首先咱们要理解 docker build 的工做原理。Docker 在运行时分为 Docker 引擎(也就是服务端守护进程)和客户端工具。Docker 的引擎提供了一组 REST API,被称为 Docker Remote API,而如 docker 命令这样的客户端工具,则是经过这组 API 与 Docker 引擎交互,从而完成各类功能。所以,虽然表面上咱们好像是在本机执行各类 docker 功能,但实际上,一切都是使用的远程调用形式在服务端(Docker 引擎)完成。也由于这种 C/S 设计,让咱们操做远程服务器的 Docker 引擎变得垂手可得。

当咱们进行镜像构建的时候,并不是全部定制都会经过 RUN 指令完成,常常会须要将一些本地文件复制进镜像,好比经过 COPY 指令、ADD 指令等。而 docker build 命令构建镜像,其实并不是在本地构建,而是在服务端,也就是 Docker 引擎中构建的。那么在这种客户端/服务端的架构中,如何才能让服务端得到本地文件呢?

这就引入了上下文的概念。当构建的时候,用户会指定构建镜像上下文的路径,docker build 命令得知这个路径后,会将路径下的全部内容打包,而后上传给 Docker 引擎。这样 Docker 引擎收到这个上下文包后,展开就会得到构建镜像所需的一切文件。

相关文章
相关标签/搜索