Docker中的Dockerfile命令详解FROM RUN COPY ADD ENTRYPOINT...
Dockerfile指令
这些建议旨在帮助您创建高效且可维护的Dockerfile。
FROM
尽可能使用当前的官方图像作为图像的基础。我们推荐Alpine图像,因为它是严格控制的并且尺寸小(目前小于5 MB),同时仍然是完整的Linux发行版。
标签
您可以为图像添加标签,以帮助按项目组织图像,记录许可信息,帮助实现自动化或出于其他原因。对于每个标签,添加LABEL以一个或多个键值对开头的行。以下示例显示了不同的可接受格式。内容包括解释性意见。
必须引用带空格的字符串或必须转义空格。内引号字符(")也必须进行转义。
# Set one or more individual labels
LABEL com.example.version="0.0.1-beta"
LABEL vendor1="ACME Incorporated"
LABEL vendor2=ZENITH\ Incorporated
LABEL com.example.release-date="2015-02-12"
LABEL com.example.version.is-production=""
图像可以有多个标签。在Docker 1.10之前,建议将所有标签组合到一条LABEL指令中,以防止创建额外的层。这不再是必需的,但仍然支持组合标签。
# Set multiple labels on one line
LABEL com.example.version="0.0.1-beta" com.example.release-date="2015-02-12"
以上也可以写成:
# Set multiple labels at once, using line-continuation characters to break long lines
LABEL vendor=ACME\ Incorporated \
com.example.is-beta= \
com.example.is-production="" \
com.example.version="0.0.1-beta" \
com.example.release-date="2015-02-12"
有关可接受的标签键和值的指导,请参阅了解对象标签。有关查询标签的信息,请参阅管理对象标签中与过滤相关的项目。另请参见 Dockerfile参考中的LABEL。
RUN
RUN在使用反斜杠分隔的多行上拆分长或复杂语句,以使您Dockerfile更具可读性,可理解性和可维护性。
APT-GET的
可能最常见的用例RUN是应用程序apt-get。因为它安装了包,所以该RUN apt-get命令有几个需要注意的问题。
避免RUN apt-get upgrade和dist-upgrade,因为父图像中的许多“基本”包无法在非特权容器内升级 。如果父图像中包含的包已过期,请与其维护人员联系。如果您知道有特定包,foo需要更新,请使用 apt-get install -y foo自动更新。
始终在同一 声明中结合RUN apt-get update使用。例如:apt-get installRUN
RUN apt-get update && apt-get install -y \
package-bar \
package-baz \
package-foo
apt-get update在RUN语句中单独使用会导致缓存问题,并且后续apt-get install指令会失败。例如,假设你有一个Dockerfile:
FROM ubuntu:18.04
RUN apt-get update
RUN apt-get install -y curl
构建映像后,所有层都在Docker缓存中。假设您稍后apt-get install通过添加额外包修改:
FROM ubuntu:18.04
RUN apt-get update
RUN apt-get install -y curl nginx
Docker将初始和修改的指令视为相同,并重用前面步骤中的缓存。其结果是,apt-get update在不执行,因为编译使用缓存的版本。因为apt-get update没有运行,您的构建有可能得到的一个过时的版本curl和 nginx包。
使用RUN apt-get update && apt-get install -y确保您的Dockerfile安装最新的软件包版本,无需进一步编码或手动干预。这种技术被称为“缓存破坏”。您还可以通过指定包版本来实现缓存清除。这称为版本固定,例如:
RUN apt-get update && apt-get install -y \
package-bar \
package-baz \
package-foo=1.3.*
版本固定强制构建以检索特定版本,而不管缓存中的内容是什么。此技术还可以减少由于所需包中意外更改而导致的故障。
下面是一个结构良好的RUN说明,演示了所有apt-get 建议。
RUN apt-get update && apt-get install -y \
aufs-tools \
automake \
build-essential \
curl \
dpkg-sig \
libcap-dev \
libsqlite3-dev \
mercurial \
reprepro \
ruby1.9.1 \
ruby1.9.1-dev \
s3cmd=1.1.* \
&& rm -rf /var/lib/apt/lists/*
该s3cmd参数指定一个版本1.1.*。如果映像以前使用的是旧版本,则指定新版本会导致缓存破坏,apt-get update并确保安装新版本。列出每行的包也可以防止包重复中的错误。
此外,当您通过删除/var/lib/apt/lists它来清理apt缓存时会减小图像大小,因为apt缓存不存储在图层中。由于RUN语句以#开头apt-get update,因此包缓存始终在刷新之前刷新apt-get install。
官方Debian和Ubuntu映像自动运行apt-get clean,因此不需要显式调用。
使用管道
某些RUN命令依赖于使用管道符(|)将一个命令的输出传递到另一个命令的能力,如下例所示:
RUN wget -O - https://some.site | wc -l > /number
Docker使用/bin/sh -c解释器执行这些命令,解释器仅评估管道中最后一个操作的退出代码以确定成功。在上面的示例中,只要wc -l命令成功,即使wget命令失败,此构建步骤也会成功并生成新映像。
如果您希望命令因管道中任何阶段的错误而失败,请预先set -o pipefail &&确定意外错误,以防止构建无意中成功。例如:
RUN set -o pipefail && wget -O - https://some.site | wc -l > /number
并非所有shell都支持该-o pipefail选项。
在诸如dash基于Debian的映像上的shell的情况下,考虑使用exec形式RUN明确选择支持该pipefail选项的shell 。例如:
RUN ["/bin/bash", "-c", "set -o pipefail && wget -O - https://some.site | wc -l > /number"]
CMD
该CMD指令应用于运行图像包含的软件以及任何参数。CMD应该几乎总是以形式使用CMD ["executable", "param1", "param2"…]。因此,如果图像是用于服务的,例如Apache和Rails,那么你可以运行类似的东西CMD ["apache2","-DFOREGROUND"]。实际上,建议将这种形式的指令用于任何基于服务的图像。
在大多数其他情况下,CMD应该给出一个交互式shell,例如bash,python和perl。例如,CMD ["perl", "-de0"],CMD ["python"],或CMD ["php", "-a"]。使用此表单意味着当您执行类似的操作时 docker run -it python,您将被放入可用的shell中,随时可以使用。 CMD应该很少的方式使用CMD ["param", "param"]会同ENTRYPOINT,除非你和你预期的用户已经非常熟悉如何ENTRYPOINT 工作的。
EXPOSE
该EXPOSE指令指示容器侦听连接的端口。因此,您应该为您的应用程序使用通用的传统端口。例如,包含Apache Web服务器EXPOSE 80的图像将使用,而包含MongoDB的图像将使用EXPOSE 27017,依此类推。
对于外部访问,您的用户可以docker run使用一个标志来执行,该标志指示如何将指定端口映射到他们选择的端口。对于容器链接,Docker为从接收容器返回源的路径提供环境变量(即MYSQL_PORT_3306_TCP)。
ENV
要使新软件更易于运行,您可以使用ENV更新PATH容器安装的软件的 环境变量。例如,ENV PATH /usr/local/nginx/bin:$PATH确保CMD ["nginx"] 正常工作。
该ENV指令对于提供特定于您希望容纳的服务的必需环境变量也很有用,例如Postgres PGDATA。
最后,ENV还可以用于设置常用的版本号,以便更容易维护版本颠簸,如以下示例所示:
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
与在程序中使用常量变量(与硬编码值相对)类似,此方法允许您更改单个ENV指令以自动神奇地破坏容器中的软件版本。
每ENV行创建一个新的中间层,就像RUN命令一样。这意味着即使您在将来的图层中取消设置环境变量,它仍然会在此图层中保留,并且可以转储其值。您可以通过创建如下所示的Dockerfile来测试它,然后构建它。
FROM alpine
ENV ADMIN_USER="mark"
RUN echo $ADMIN_USER > ./mark
RUN unset ADMIN_USER
$ docker run --rm test sh -c 'echo $ADMIN_USER'
mark
要防止这种情况,并且确实取消设置环境变量,请使用RUN带有shell命令的命令,在单个图层中设置,使用和取消设置变量all。您可以使用;或分隔命令&&。如果您使用第二种方法,并且其中一个命令失败,则docker build也会失败。这通常是一个好主意。使用\Linux Dockerfiles作为行继续符可以提高可读性。您还可以将所有命令放入shell脚本中,并让RUN命令运行该shell脚本。
FROM alpine
RUN export ADMIN_USER="mark" \
&& echo $ADMIN_USER > ./mark \
&& unset ADMIN_USER
CMD sh
$ docker run --rm test sh -c 'echo $ADMIN_USER'
ADD COPY
一般而言,虽然ADD并且COPY在功能上类似,但是COPY 是优选的。那是因为它更透明ADD。COPY仅支持将本地文件基本复制到容器中,同时ADD具有一些功能(如仅限本地的tar提取和远程URL支持),这些功能并不是很明显。因此,最好的用途ADD是将本地tar文件自动提取到图像中,如ADD rootfs.tar.xz /。
如果您有多个Dockerfile步骤使用上下文中的不同文件,则COPY它们是单独的,而不是一次性完成。这可确保每个步骤的构建缓存仅在特定所需文件更改时失效(强制重新执行该步骤)。
例如:
COPY requirements.txt /tmp/
RUN pip install --requirement /tmp/requirements.txt
COPY . /tmp/
导致RUN步骤的缓存失效次数少于放置 COPY . /tmp/之前的缓存失效次数。
由于图像大小很重要,ADD因此强烈建议不要使用从远程URL获取包。你应该使用curl或wget代替。这样,您可以删除提取后不再需要的文件,也不必在图像中添加其他图层。例如,你应该避免做以下事情:
ADD http://example.com/big.tar.xz /usr/src/things/
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
RUN make -C /usr/src/things all
而是做一些像:
RUN mkdir -p /usr/src/things \
&& curl -SL http://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all
对于不需要ADDtar自动提取功能的其他项目(文件,目录),您应该始终使用COPY。
ENTRYPOINT
最好的用法ENTRYPOINT是设置图像的主命令,允许该图像像该命令一样运行(然后CMD用作默认标志)。
让我们从命令行工具的图像示例开始s3cmd:
ENTRYPOINT ["s3cmd"]
CMD ["--help"]
现在可以像这样运行图像来显示命令的帮助:
$ docker run s3cmd
或使用正确的参数执行命令:
$ docker run s3cmd ls s3://mybucket
这很有用,因为图像名称可以兼作二进制文件的引用,如上面的命令所示。
该ENTRYPOINT指令还可以与辅助脚本结合使用,允许它以与上述命令类似的方式运行,即使启动该工具可能需要多个步骤。
例如,Postgres官方图像 使用以下脚本作为其ENTRYPOINT:
#!/bin/bash
set -e
if [ "$1" = 'postgres' ]; then
chown -R postgres "$PGDATA"
if [ -z "$(ls -A "$PGDATA")" ]; then
gosu postgres initdb
fi
exec gosu postgres "$@"
fi
exec "$@"
将app配置为PID 1
此脚本使用的execbash命令 ,以使最终运行的应用程序成为容器的PID 1.这允许应用程序接收发送到所述容器任何Unix信号。如需更多信息,请参阅ENTRYPOINT参考。
帮助程序脚本被复制到容器中并通过ENTRYPOINT容器启动运行:
COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["postgres"]
该脚本允许用户以多种方式与Postgres交互。
它可以简单地启动Postgres:
$ docker run postgres
或者,它可用于运行Postgres并将参数传递给服务器:
$ docker run postgres postgres --help
最后,它还可以用来启动一个完全不同的工具,比如Bash:
$ docker run --rm -it postgres bash
VOLUME
该 VOLUME指令应用于公开由docker容器创建的任何数据库存储区域,配置存储或文件/文件夹。强烈建议您使用图像VOLUME的任何可变和/或用户可维修部分。
USER
如果服务可以在没有权限的情况下运行,请使用USER更改为非root用户。首先在Dockerfile类似的东西中创建用户和组RUN groupadd -r postgres && useradd --no-log-init -r -g postgres postgres。
考虑一个显式的UID / GID
图像中的用户和组被分配了非确定性UID / GID,因为无论图像重建如何,都会分配“下一个”UID / GID。因此,如果它很重要,您应该分配一个显式的UID / GID。
由于Go存档/ tar包处理稀疏文件时未解决的错误,尝试在Docker容器内创建具有非常大的UID的用户可能导致磁盘耗尽,因为/var/log/faillog容器层中填充了NULL(\ 0)字符。解决方法是将--no-log-init标志传递给useradd。Debian / Ubuntu adduser包装器不支持此标志。
避免安装或使用,sudo因为它具有可能导致问题的不可预测的TTY和信号转发行为。如果您绝对需要类似的功能sudo,例如将守护程序初始化root为非运行它root,请考虑使用“gosu”。
最后,为了减少层次和复杂性,避免USER频繁地来回切换。
WORKDIR
为了清晰和可靠,您应该始终使用绝对路径 WORKDIR。此外,您应该使用难以阅读,排除故障和维护WORKDIR的扩散指令RUN cd … && do-something。
ONBUILD
一个ONBUILD命令将当前执行后Dockerfile构建完成。ONBUILD在任何导出FROM当前图像的子图像中执行。将该ONBUILD命令视为父母Dockerfile给孩子的指令Dockerfile。
Docker构建ONBUILD在子代中的任何命令之前执行命令Dockerfile。
ONBUILD对于将要构建FROM给定图像的图像非常有用。例如,您将使用ONBUILD一个语言堆栈映像来构建在该语言中编写的任意用户软件 Dockerfile,正如您在Ruby的ONBUILD变体中所看到的那样。
构建的图像ONBUILD应该获得单独的标记,例如:ruby:1.9-onbuild或ruby:2.0-onbuild。
把时要小心,ADD或COPY在ONBUILD。如果新构建的上下文缺少正在添加的资源,则“onbuild”映像将发生灾难性故障。如上所述,添加单独的标记有助于通过允许Dockerfile作者做出选择来缓解这种情况。
Docker中的Dockerfile命令详解FROM RUN COPY ADD ENTRYPOINT...的更多相关文章
- [转帖]Docker学习之Dockerfile命令详解
Docker学习之Dockerfile命令详解 https://it.baiked.com/system/docker/2436.html 图挺好的 前言 之前,制作镜像的伪姿势搭建已经见过了,今天介 ...
- [转]Docker(三):Dockerfile 命令详解
本文转自:https://blog.csdn.net/ityouknow/article/details/79600406 上一篇文章Docker(二):Dockerfile 使用介绍介绍了 Dock ...
- Docker(三):Dockerfile 命令详解
上一篇文章Docker(二):Dockerfile 使用介绍介绍了 Dockerfile 的使用,这篇文章我们来继续了解 Dockerfile ,学习 Dockerfile 各种命令的使用. Dock ...
- Docker(六):Dockerfile命令详解
Dockerfile 指令详解 1 FROM 指定基础镜像 FROM 指令用于指定其后构建新镜像所使用的基础镜像.FROM 指令必是 Dockerfile 文件中的首条命令,启动构建流程后,Docke ...
- Dockerfile 命令详解及最佳实践
Dockerfile 命令详解 FROM 指定基础镜像(必选) 所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制.就像我们之前运行了一个 nginx 镜像的容器,再进行修改一样,基础镜像是必须指 ...
- Dockerfile命令详解
使用docker就会避免不了的要做各种镜像,就会用到dockerfile,记录一下dockerfile的主要命令 1.主要组成部分 dockerfile执行build命令时,是从上倒下依次执行 ...
- Docker:Dockerfile命令详解
1.FROM 功能为指定基础镜像,并且必须是第一条指令. 如果不以任何镜像为基础,那么写法为:FROM scratch. 同时意味着接下来所写的指令将作为镜像的第一层开始 语法: FROM <i ...
- Docker dockerfile命令详解
docker-file 官网文档:https://docs.docker.com/v17.09/engine/reference/builder/ 制作Dockerfile为Docker入门学习的第一 ...
- Docker学习笔记-Dockerfile文件详解
什么是Dockerfile? Docker中有个非常重要的概念叫做--镜像(Image).Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序.库.资源.配置等文件外,还包含了一些为运 ...
随机推荐
- HDU-2444-The Accomodation of Students(二分图判定,最大匹配)
链接: https://vjudge.net/problem/HDU-2444#author=634579757 题意: There are a group of students. Some of ...
- Struts 2 配置Action详解_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 实现了Action处理类之后,就可以在struts.xml中配置该Action,从而让Struts 2框架知道哪个Act ...
- Codeforces Gym 101505C : Cable Connection (计算几何)
题目链接 题意:给出第一象限的N个点,存在一直线x/a+y/b=1(a>0,y>0)使得所有点都在这条直线下面,求 min{sqrt(a^2+b^2)} 显然,这样的直线必然经过这N个点中 ...
- 两个惊艳的python库:tqdm和retry
转载到请包括本文地址:http://spaces.ac.cn/archives/3902/ Python基本是我目前工作.计算.数据挖掘的唯一编程语言(除了符号计算用Mathematica外).当然, ...
- csp-s2019 AFO记
DAY 0 上午出发前大家都很颓废的样子. 我因为还没有实现刷完NOIP专题的所有题的目标而去憨比的学DDP. 最后还是不会,保卫王国是写不成了…… 该走了,学校领导来开了个欢送会,祝福我们从里WA到 ...
- cpp 面向对象初步探索
需求 尝试定义一个complex(复数类) 简略实现 headers/complex.h #ifndef __COMPLEX__ #define __COMPLEX__ class complex { ...
- psdash-为开发、测试人员提供简单的方法,在web界面查看服务器的运行情况(网络,带宽,磁盘,CPU), 同时可以在web界面查看日志
psdash是linux的系统信息web指示板主要由使用数据psutil——由此得名. github地址:https://github.com/Jahaja/psdash 特性 安装 开始 配置 截图 ...
- Linux基本命令使用(一)
1.head -n 文件 可以查看文件前n行 tail -n 文件 可以查看文件的后n行 tail -f 文件 可以实时查看文件,比如日志在更新,就可以实时显示最后几行 ...
- JMS学习五(ActiveMQ的本地事务)
1.ActiveMQ的本地事务 在一个JMS客户端,可以使用本地事务来组合消息的发送和接收.JMS Session接口提供了commit和rollback方法.事务提交意味着生产的所有消息被发送,消费 ...
- java实现微信小程序服务端(登录)
微信小程序如今被广泛使用,微信小程序按照微信官网的定义来说就是: 微信小程序是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验. 这就是微信小程序的魅力所在,有 ...