上一篇文章Docker(二):Dockerfile 使用介绍介绍了 Dockerfile 的使用,这篇文章我们来继续了解 Dockerfile ,学习 Dockerfile 各种命令的使用。

Dockerfile 指令详解

1 FROM 指定基础镜像

FROM 指令用于指定其后构建新镜像所使用的基础镜像。FROM 指令必是 Dockerfile 文件中的首条命令,启动构建流程后,Docker 将会基于该镜像构建新镜像,FROM 后的命令也会基于这个基础镜像。

FROM语法格式为:

FROM <image>
  • 1

FROM <image>:<tag>
  • 1

FROM <image>:<digest>
  • 1

通过 FROM 指定的镜像,可以是任何有效的基础镜像。FROM 有以下限制:

  • FROM 必须 是 Dockerfile 中第一条非注释命令
  • 在一个 Dockerfile 文件中创建多个镜像时,FROM 可以多次出现。只需在每个新命令 FROM 之前,记录提交上次的镜像 ID。
  • tag 或 digest 是可选的,如果不使用这两个值时,会使用 latest 版本的基础镜像

2 RUN 执行命令

在镜像的构建过程中执行特定的命令,并生成一个中间镜像。格式:

#shell格式
RUN <command>
#exec格式
RUN ["executable", "param1", "param2"]
  • 1
  • 2
  • 3
  • 4
  • RUN 命令将在当前 image 中执行任意合法命令并提交执行结果。命令执行提交后,就会自动执行 Dockerfile 中的下一个指令。
  • 层级 RUN 指令和生成提交是符合 Docker 核心理念的做法。它允许像版本控制那样,在任意一个点,对 image 镜像进行定制化构建。
  • RUN 指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定 --no-cache 参数,如:docker build --no-cache

3 COPY 复制文件

格式:

COPY <源路径>... <目标路径>
COPY ["<源路径1>",... "<目标路径>"]
  • 1
  • 2

和 RUN 指令一样,也有两种格式,一种类似于命令行,一种类似于函数调用。COPY 指令将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的<目标路径>位置。比如:

COPY package.json /usr/src/app/
  • 1

<源路径>可以是多个,甚至可以是通配符,其通配符规则要满足 Go 的 filepath.Match 规则,如:

COPY hom* /mydir/
COPY hom?.txt /mydir/
  • 1
  • 2

<目标路径>可以是容器内的绝对路径,也可以是相对于工作目录的相对路径(工作目录可以用 WORKDIR 指令来指定)。目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。

此外,还需要注意一点,使用 COPY 指令,源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关文件都在使用 Git 进行管理的时候。

4 ADD 更高级的复制文件

ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。比如<源路径>可以是一个 URL,这种情况下,Docker 引擎会试图去下载这个链接的文件放到<目标路径>去。

在构建镜像时,复制上下文中的文件到镜像内,格式:

ADD <源路径>... <目标路径>
ADD ["<源路径>",... "<目标路径>"]
  • 1
  • 2

注意 
如果 docker 发现文件内容被改变,则接下来的指令都不会再使用缓存。关于复制文件时需要处理的/,基本跟正常的 copy 一致

5 ENV 设置环境变量

格式有两种:

ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...
  • 1
  • 2

这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。

ENV VERSION=1.0 DEBUG=on \NAME="Happy Feet"
  • 1
  • 2

这个例子中演示了如何换行,以及对含有空格的值用双引号括起来的办法,这和 Shell 下的行为是一致的。

6 EXPOSE

为构建的镜像设置监听端口,使容器在运行时监听。格式:

EXPOSE <port> [<port>...]
  • 1

EXPOSE 指令并不会让容器监听 host 的端口,如果需要,需要在 docker run 时使用 -p-P 参数来发布容器端口到 host 的某个端口上。

7 VOLUME 定义匿名卷

VOLUME用于创建挂载点,即向基于所构建镜像创始的容器添加卷:

VOLUME ["/data"]
  • 1

一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:

  • 卷可以容器间共享和重用
  • 容器并不一定要和其它容器共享卷
  • 修改卷后会立即生效
  • 对卷的修改不会对镜像产生影响
  • 卷会一直存在,直到没有任何容器在使用它

VOLUME 让我们可以将源代码、数据或其它内容添加到镜像中,而又不并提交到镜像中,并使我们可以多个容器间共享这些内容。

8 WORKDIR 指定工作目录

WORKDIR用于在容器内设置一个工作目录:

WORKDIR /path/to/workdir
  • 1

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

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
  • 1
  • 2
  • 3
  • 4

在以上示例中,pwd 最终将会在 /a/b/c 目录中执行。在使用 docker run 运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。

9 USER 指定当前用户

USER 用于指定运行镜像所使用的用户:

USER daemon
  • 1

使用USER指定用户时,可以使用用户名、UID 或 GID,或是两者的组合。以下都是合法的指定试:

USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

使用USER指定用户后,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT 都将使用该用户。镜像构建完成后,通过 docker run 运行容器时,可以通过 -u 参数来覆盖所指定的用户。

10 CMD

CMD用于指定在容器启动时所要执行的命令。CMD 有以下三种格式:

CMD ["executable","param1","param2"]
CMD ["param1","param2"]
CMD command param1 param2
  • 1
  • 2
  • 3

省略可执行文件的 exec 格式,这种写法使 CMD 中的参数当做 ENTRYPOINT 的默认参数,此时 ENTRYPOINT 也应该是 exec 格式,具体与 ENTRYPOINT 的组合使用,参考 ENTRYPOINT。

注意 
与 RUN 指令的区别:RUN 在构建的时候执行,并生成一个新的镜像,CMD 在容器运行的时候执行,在构建时不进行任何操作。

11 ENTRYPOINT

ENTRYPOINT 用于给容器配置一个可执行程序。也就是说,每次使用镜像创建容器时,通过 ENTRYPOINT 指定的程序都会被设置为默认程序。ENTRYPOINT 有以下两种形式:

ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
  • 1
  • 2

ENTRYPOINT 与 CMD 非常类似,不同的是通过docker run执行的命令不会覆盖 ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给 ENTRYPOINT。Dockerfile 中只允许有一个 ENTRYPOINT 命令,多指定时会覆盖前面的设置,而只执行最后的 ENTRYPOINT 指令。

docker run运行容器时指定的参数都会被传递给 ENTRYPOINT ,且会覆盖 CMD 命令指定的参数。如,执行docker run <image> -d时,-d 参数将被传递给入口点。

也可以通过docker run --entrypoint重写 ENTRYPOINT 入口点。如:可以像下面这样指定一个容器执行程序:

ENTRYPOINT ["/usr/bin/nginx"]
  • 1

完整构建代码:

# Version: 0.0.3
FROM ubuntu:16.04
MAINTAINER 何民三 "cn.liuht@gmail.com"
RUN apt-get update
RUN apt-get install -y nginx
RUN echo 'Hello World, 我是个容器' \ > /var/www/html/index.html
ENTRYPOINT ["/usr/sbin/nginx"]
EXPOSE 80
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

使用docker build构建镜像,并将镜像指定为 itbilu/test:

docker build -t="itbilu/test" .
  • 1

构建完成后,使用itbilu/test启动一个容器:

docker run -i -t  itbilu/test -g "daemon off;"
  • 1

在运行容器时,我们使用了 -g "daemon off;",这个参数将会被传递给 ENTRYPOINT,最终在容器中执行的命令为 /usr/sbin/nginx -g "daemon off;"

12 LABEL

LABEL用于为镜像添加元数据,元数以键值对的形式指定:

LABEL <key>=<value> <key>=<value> <key>=<value> ...
  • 1

使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。 
如,通过LABEL指定一些元数据:

LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"
  • 1

指定后可以通过docker inspect查看:

docker inspect itbilu/test
"Labels": {"version": "1.0","description": "这是一个Web服务器","by": "IT笔录"
},
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

13 ARG

ARG用于指定传递给构建运行时的变量:

ARG <name>[=<default value>]
  • 1

如,通过ARG指定两个变量:

ARG site
ARG build_user=IT笔录
  • 1
  • 2

以上我们指定了 site 和 build_user 两个变量,其中 build_user 指定了默认值。在使用 docker build 构建镜像时,可以通过 --build-arg <varname>=<value> 参数来指定或重设置这些变量的值。

docker build --build-arg site=itiblu.com -t itbilu/test .
  • 1

这样我们构建了 itbilu/test 镜像,其中site会被设置为 itbilu.com,由于没有指定 build_user,其值将是默认值 IT 笔录。

14 ONBUILD

ONBUILD用于设置镜像触发器:

ONBUILD [INSTRUCTION]
  • 1

当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发。 
如,当镜像被使用时,可能需要做一些处理:

[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
  • 1
  • 2
  • 3
  • 4

15 STOPSIGNAL

STOPSIGNAL用于设置停止容器所要发送的系统调用信号:

STOPSIGNAL signal
  • 1

所使用的信号必须是内核系统调用表中的合法的值,如:SIGKILL。

16 SHELL

SHELL用于设置执行命令(shell式)所使用的的默认 shell 类型:

SHELL ["executable", "parameters"]
  • 1

SHELL在Windows环境下比较有用,Windows 下通常会有 cmd 和 powershell 两种 shell,可能还会有 sh。这时就可以通过 SHELL 来指定所使用的 shell 类型:

FROM microsoft/windowsservercore# Executed as cmd /S /C echo default
RUN echo default# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default# Executed as powershell -command Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello# Executed as cmd /S /C echo hello
SHELL ["cmd", "/S"", "/C"]
RUN echo hello
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

Dockerfile 使用经验

Dockerfile 示例

构建Nginx运行环境

# 指定基础镜像
FROM sameersbn/ubuntu:14.04.20161014# 维护者信息
MAINTAINER sameer@damagehead.com# 设置环境
ENV RTMP_VERSION=1.1.10 \NPS_VERSION=1.11.33.4 \LIBAV_VERSION=11.8 \NGINX_VERSION=1.10.1 \NGINX_USER=www-data \NGINX_SITECONF_DIR=/etc/nginx/sites-enabled \NGINX_LOG_DIR=/var/log/nginx \NGINX_TEMP_DIR=/var/lib/nginx \NGINX_SETUP_DIR=/var/cache/nginx# 设置构建时变量,镜像建立完成后就失效
ARG BUILD_LIBAV=false
ARG WITH_DEBUG=false
ARG WITH_PAGESPEED=true
ARG WITH_RTMP=true# 复制本地文件到容器目录中
COPY setup/ ${NGINX_SETUP_DIR}/
RUN bash ${NGINX_SETUP_DIR}/install.sh# 复制本地配置文件到容器目录中
COPY nginx.conf /etc/nginx/nginx.conf
COPY entrypoint.sh /sbin/entrypoint.sh# 运行指令
RUN chmod 755 /sbin/entrypoint.sh# 允许指定的端口
EXPOSE 80/tcp 443/tcp 1935/tcp# 指定网站目录挂载点
VOLUME ["${NGINX_SITECONF_DIR}"]ENTRYPOINT ["/sbin/entrypoint.sh"]
CMD ["/usr/sbin/nginx"]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

构建tomcat 环境

Dockerfile文件

# 指定基于的基础镜像
FROM ubuntu:13.10  # 维护者信息
MAINTAINER zhangjiayang "zhangjiayang@sczq.com.cn"  # 镜像的指令操作
# 获取APT更新的资源列表
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe"> /etc/apt/sources.list
# 更新软件
RUN apt-get update  # Install curl
RUN apt-get -y install curl  # Install JDK 7
RUN cd /tmp &&  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
RUN mkdir -p /usr/lib/jvm
RUN mv /tmp/jdk1.7.0_65/ /usr/lib/jvm/java-7-oracle/  # Set Oracle JDK 7 as default Java
RUN update-alternatives --install /usr/bin/java java /usr/lib/jvm/java-7-oracle/bin/java 300
RUN update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/java-7-oracle/bin/javac 300     # 设置系统环境
ENV JAVA_HOME /usr/lib/jvm/java-7-oracle/  # Install tomcat7
RUN cd /tmp && curl -L 'http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.8/bin/apache-tomcat-7.0.8.tar.gz' | tar -xz
RUN mv /tmp/apache-tomcat-7.0.8/ /opt/tomcat7/  ENV CATALINA_HOME /opt/tomcat7
ENV PATH $PATH:$CATALINA_HOME/bin  # 复件tomcat7.sh到容器中的目录
ADD tomcat7.sh /etc/init.d/tomcat7
RUN chmod 755 /etc/init.d/tomcat7  # Expose ports.  指定暴露的端口
EXPOSE 8080  # Define default command.
ENTRYPOINT service tomcat7 start && tail -f /opt/tomcat7/logs/catalina.out
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

tomcat7.sh命令文件

export JAVA_HOME=/usr/lib/jvm/java-7-oracle/
export TOMCAT_HOME=/opt/tomcat7  case $1 in
start)  sh $TOMCAT_HOME/bin/startup.sh
;;
stop)  sh $TOMCAT_HOME/bin/shutdown.sh
;;
restart)  sh $TOMCAT_HOME/bin/shutdown.sh  sh $TOMCAT_HOME/bin/startup.sh
;;
esac
exit 0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

原则与建议

  • 容器轻量化。从镜像中产生的容器应该尽量轻量化,能在足够短的时间内停止、销毁、重新生成并替换原来的容器。
  • 使用 .gitignore。在大部分情况下,Dockerfile 会和构建所需的文件放在同一个目录中,为了提高构建的性能,应该使用 .gitignore 来过滤掉不需要的文件和目录。
  • 为了减少镜像的大小,减少依赖,仅安装需要的软件包。
  • 一个容器只做一件事。解耦复杂的应用,分成多个容器,而不是所有东西都放在一个容器内运行。如一个 Python Web 应用,可能需要 Server、DB、Cache、MQ、Log 等几个容器。一个更加极端的说法:One process per container。
  • 减少镜像的图层。不要多个 Label、ENV 等标签。
  • 对续行的参数按照字母表排序,特别是使用apt-get install -y安装包的时候。
  • 使用构建缓存。如果不想使用缓存,可以在构建的时候使用参数--no-cache=true来强制重新生成中间镜像。

Docker(三):Dockerfile 命令详解相关推荐

  1. Dockerfile命令详解之 COPY

    许多同学不知道Dockerfile应该如何写,不清楚Dockerfile中的指令分别有什么意义,能达到什么样的目的,接下来我将在容器化专栏中详细的为大家解释每一个指令的含义以及用法. 专栏订阅传送门h ...

  2. Dockerfile命令详解

    使用docker就会避免不了的要做各种镜像,就会用到dockerfile,记录一下dockerfile的主要命令 1.主要组成部分     dockerfile执行build命令时,是从上倒下依次执行 ...

  3. Dockerfile 命令详解

    使用 Docker 就会避免不了的要做各种镜像,就会用到 Dockerfile,记录一下 Dockerfile 的主要命令 1.主要组成部分 Dockerfile 执行 build 命令时,是从上到下 ...

  4. shell编程之进阶篇三常见命令详解

    常见命令详解 接下来我们介绍一些shell脚本中经常使用的linux命令:grep.sed.awk.find grep命令详解 grep命令是我们常用的一个强大的文本搜索命令. 命令格式详解 grep ...

  5. Docker应用容器引擎——docker的常用命令详解

    文章目录 1.Docker常用命令 2.docker的启动.停止.重启 3.管理命令 4.镜像管理 5.命令的详细演示 docker create docker start docker run do ...

  6. Docker架构简介 命令详解

    1.1.Docker的介绍 Docker是一个开源的应用容器引擎,使用Go语言开发,基于Linux内核的cgroup,namespace,Union FS等技术,对应用进程进行封装隔离,并且 独立于宿 ...

  7. 【Docker】Dockerfile用法详解

    制作Docker image 有两种方式:一是使用 Docker container,直接构建容器,再导出成 image 使用:二是使用 Dockerfile,将所有动作写在文件中,再 build 成 ...

  8. Docker之Dockerfile 指令详解

    闲话不多说,dokerfile常用指令解析奉上 FROM 作用:指定基础镜像,必须放在DOckerfile的第一行,表示从哪个baseimage开始构建 格式: FROM <image>: ...

  9. Docker学习——Dockerfile 指令详解(五)

    2019独角兽企业重金招聘Python工程师标准>>> 我们已经介绍了 FROM (指定基础镜像) , RUN(执行命令) ,还提及了 COPY , ADD ,其实 Dockerfi ...

最新文章

  1. 怎样在表格中选出同一类_超超超超实用的年会策划执行表格模板合集!
  2. 让 QtWebkit 支持跨域CROS - nowboy的CSDN博客 - 博客频道 - CSDN.NET
  3. UA MATH563 概率论的数学基础I 概率空间1 基本概念
  4. ASP.NET Core 实战:使用 NLog 将日志信息记录到 MongoDB
  5. 树莓派 python_树莓派笔记08—Python流水灯
  6. 30 行 Javascript 代码搞定智能家居系统
  7. [转载]EmitMapper,AutoMapper,NLiteMapper和手工映射性能大比拼
  8. BXP_4.1安装配置及域应用随记一
  9. Facebook的体系结构分析---外文转载
  10. Luogu4198 楼房重建
  11. Fortran入门教程(十一)—— 模块
  12. python批量读取txt_python如何批量读取txt文件
  13. c语言贪吃蛇程序设计报告蚂蚁文库,贪吃蛇游戏C程序设计报告
  14. LABjs分析 http://labjs.com/documentation.php#queuescript
  15. 微信小程序数据拼接_微信小程序字符串和变量如何拼接
  16. 软件测试人员如何月薪过万、月薪过万的秘籍
  17. 通过HDMI获取显示器EDID数据
  18. 全景声基础-多声道制式简介2.0、5.1、全景声
  19. 云重磅 | 阿里巴巴平均每天纳税超1.4亿;谷歌、Face book与AWS将共建美欧新海底电缆;阿里发布谣言粉碎机:1秒辨真伪...
  20. win7共享xp打印机_快速有效的局域网共享方法,十年老技术现身说法亲测可用

热门文章

  1. 【最优化方法】穷举法 vs. 爬山法 vs. 模拟退火算法 vs. 遗传算法 vs. 蚁群算法
  2. Oracle编程入门经典 第8章 索引
  3. 干货︱机器学习中防止过拟合的处理方法
  4. 关于编译器的一个问题
  5. 聚类(1)——混合高斯模型 Gaussian Mixture Model
  6. Deep Learning论文笔记之(二)Sparse Filtering稀疏滤波
  7. Day 21:Docker 入门教程
  8. 数字图像处理:第五章 代数运算
  9. 个人博客(前端菜鸡)持续开发中,可前往 欢迎访问. www.amayaliu.cn
  10. 太白教你学python---博客分类目录