Docker学习笔记---Dockerfile

EarthChen · · 2831 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

Docker可以通过从Dockerfile包含所有命令的文本文件中读取指令,自动构建镜像。

每个需要使用Docker的项目都应该有一个Dockerfile,这个文件描述了我们需要的镜像环境。

Dockerfile指令

FROM

有效的Dockerfile必须从FROM开始,镜像可以是任何有效的镜像。
官方建议,如果只需要一个linux基础镜像,建议使用Debian镜像,控制的很小。

FROM <image> [AS <name>]

或
FROM <image>[:<tag>] [AS <name>]

或
FROM <image>[@<digest>] [AS <name>]

LABEL

LABEL <key>=<value> <key>=<value> <key>=<value> ...

该LABEL指令将元数据添加到图像。A LABEL是一个键值对。要在LABEL值中包含空格,请使用引号和反斜杠,就像在命令行解析中一样。几个用法示例

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."

图像可以有多个标签。要指定多个标签,Docker建议LABEL在可能的情况下将标签组合到单个指令中。每个LABEL指令产生一个新的层

LABEL multi.label1="value1" multi.label2="value2" other="value3"

或
LABEL multi.label1="value1" \
      multi.label2="value2" \
      other="value3"

要查看图像的标签,请使用docker inspect命令。

$ docker inspect Ubuntu

RUN

如果你需要RUN多个命令,建议使用多行写出来,使用( \ )分隔多行

RUN有两种形式

  • RUN <command> shell形式,命令在shell中运行,默认为/bin/sh
  • RUN ["executable", "param1", "param2"]
    RUN指令在当前镜像的顶部的新层中执行任何命令,病提交结果,结果提交的图像当被用户下一步Dockerfile

可以使用命令更改shell中的默认的SHELL.

在shell窗体中,可以使用 \ 讲一条指令继续下一行
例如:

RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'

相当于:

RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'

注:如果你想使用其他shell比如bash,请使用在所需的shell传递参数,RUN ["/bin/bash", "-c", "echo hello"]

apt-get

如果你的基础镜像使用的是Debian,那你一定会经常使用apt-get命令安装软件

一般来说,我们最好不要使用apt-get upgrade或者apt-get dist-upgrade,使用上述命令会造成许多非必须包被安装,这是不必要的。如果知道要更新当前基础镜像中中的某一个软件,比如nginx,请使用apt-get install -y nginx来进行安装更新

通常我们会如下使用他:

RUN apt-get update && apt-get install -y \
        package-bar \
        package-baz \
        package-foo

先执行apt-get update是为了确保不被缓存所干扰,保证安装的软件是比较新的版本。

以下是一个使用RUNapt-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/*

最后删除/var/lib/apt/lists/是为了清理缓存从而减少镜像大小,Debian和Ubuntu都会在最后自动调用apt-get clean*来清理,不需要显示调用

CMD

该指令有三种形式:

  • CMD ["executable","param1","param2"],这是首先方式
  • CMD ["param1","param2"],作为ENTRYPOINT的默认参数
  • CMD command param1 param2 外壳形式

当以shell或者exec格式使用是,该CMD指令设置运行镜像时要执行的命令
如果你使用shell的形式CMD,那么<command>将执行 /bin/sh -c:

FROM ubuntu
CMD echo "This is a test." | wc -

如果您想在 <command> 没有shell 的情况下运行,那么您必须将该命令表达为JSON数组,并提供可执行文件的完整路径。 此数组形式是首选格式CMD。任何其他参数必须单独表示为数组中的字符串:

FROM ubuntu
CMD ["/usr/bin/wc","--help"]

CMD指令应用与运行镜像中所包含的软件,及其参数。CMD应该以CMD [“executable”, “param1”, “param2”…]表示。

在很多时候,CMD给出的是一个交互式shell,比如bash,Python等,比如CMD ["perl", "-de0"]CMD ["python"],或 CMD [“php”, “-a”]

EXPOSE

该指令指示容器讲监听链接的端口,类似于,将容器中的某一个端口暴露出去,从而在外部访问绑定该端口。在容器内部,应该使用应用的传统通用端口。

EXPOSE <port> [<port>...]

该EXPOSE指令通知Docker容器在运行时监听指定的网络端口。EXPOSE不使主机的端口可以访问。为此,您必须使用该-p标志来发布一系列端口,或者使用该-P标志来发布所有暴露的端口。您可以公开一个端口号,并在外部发布另一个端口号

ENV

ENV <key> <value>
ENV <key>=<value> ...

注:

  • 该ENV指令将环境变量<key>设置为该值 <value>。该值将处于所有“后代” Dockerfile命令的环境中
  • 该ENV指令有两种形式。第一个表单ENV <key> <value>将会将一个变量设置为一个值。第一个空格后的整个字符串将被视为<value>- 包括空格和引号等字符。
  • 第二种形式ENV <key>=<value> ...允许一次设置多个变量。请注意,第二种形式在语法中使用等号(=),而第一种形式则不使用等号。像命令行解析一样,引号和反斜杠可用于在值中包含空格。

例如:

ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy


和
ENV myName="John Doe" myDog=Rex\ The\ Dog \
    myCat=fluffy

上述两种方法所产生的结果是一样的,推荐使用第一种方式。

使用ENV来更新容器中的环境变量PATH,例如:ENV PATH /usr/local/nginx/bin:$PATH将确保CMD [“nginx”]工作正常。

ENV指令用于提供特定服务所需要的环境变量

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

ADD or COPY

上述两个指令的功能上是类似的,都是复制文件到容器中。

COPY只支持讲本地文件复制到容器中
ADD不但支持讲本地文件复制到容器中,还支持本地提取文件和远程url下载

所以ADD最适合的恰当的使用就是讲压缩文件提取到容器中。如ADD rootfs.tar.xz /

COPY可以多次使用,例如下列例子可以使RUN缓存无效的数量减少:

COPY requirements.txt /tmp/
RUN pip install --requirement /tmp/requirements.txt
COPY . /tmp/

ADD不鼓励使用远程url并提取包。应该使用wget或者curl替代。可以在解压完成之后删除不需要的压缩包。
以下做法是正确的范例:

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

对于不需要提取文件的操作,我们应该均使用COPY来进行文件复制操作。

ADD

该指令有两种方式

  • ADD <src>...<dest>
  • ["<src>",... "<dest>"]

ADD指令将复制新文件,目录或远程文件URL <src> ,并将其添加到路径中图像的文件系统<dest>

<src>可以指定多个资源,但如果它们是文件或目录,则它们必须相对于正在构建的源目录(构建的上下文)。

每个<src>可能包含通配符,并使用Go的filepath.Match规则进行匹配 。例如

ADD hom* /mydir/        # adds all files starting with "hom"
ADD hom?.txt /mydir/    # ? is replaced with any single character, e.g., "home.txt"

<dest>是一个绝对路径,或相对于一个路径WORKDIR,到其中的源将在目标容器内进行复制

ADD test relativeDir/          # adds "test" to `WORKDIR`/relativeDir/
ADD test /absoluteDir/         # adds "test" to /absoluteDir/

当添加包含特殊字符(如[ 和])的文件或目录时,需要按照Golang规则转义这些路径,以防止它们被视为匹配模式。例如,要添加一个名为的文件arr[0].txt,请使用以下命令:

ADD arr[[]0].txt /mydir/    # copy a file named "arr[0].txt" to /mydir/

COPY

同样COPY也有两种形式:

  • COPY <src>... <dest>
  • COPY ["<src>",... "<dest>"] (此窗体是包含空格的路径所必需的)

COPY指令将复制新文件或目录<src ,并将其添加到该路径上容器的文件系统<dest>

其他内容参见ADD部分

ENTRYPOINT

该指令也有两种形式:

  • ENTRYPOINT ["executable", "param1", "param2"] (首选)
  • ENTRYPOINT command param1 param2 (外壳形式)

ENTRYPOINT允许你配置作为可执行文件运行的容器

例如,以下将使用默认内容启动nginx,在端口80上侦听:

docker run -i -t --rm -p 80:80 nginx

执行from ENTRYPOINT例子

您可以使用exec形式ENTRYPOINT设置相当稳定的默认命令和参数,然后使用任何一种形式CMD来设置更有可能更改的其他默认值。

FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]

运行容器时,您可以看到这top是唯一的过程:

$ docker run -it --rm --name test  top -H

top - 08:25:00 up  7:27,  0 users,  load average: 0.00, 0.01, 0.05
Threads:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.1 us,  0.1 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   2056668 total,  1616832 used,   439836 free,    99352 buffers
KiB Swap:  1441840 total,        0 used,  1441840 free.  1324440 cached Mem

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
    1 root      20   0   19744   2336   2080 R  0.0  0.1   0:00.04 top

执行外壳形式的 ENTRYPOINT例子

您可以指定一个纯粹的字符串,ENTRYPOINT并在其中执行/bin/sh -c。此表单将使用shell处理来替换shell环境变量,并将忽略任何CMD或docker run命令行参数。为了确保能够正确地docker stop发出任何长时间运行的ENTRYPOINT可执行文件,您需要记住启动它exec:

FROM ubuntu
ENTRYPOINT exec top -b

运行此镜像时,您将看到单个PID 1过程:

$ docker run -it --rm --name test top

Mem: 1704520K used, 352148K free, 0K shrd, 0K buff, 140368121167873K cached
CPU:   5% usr   0% sys   0% nic  94% idle   0% io   0% irq   0% sirq
Load average: 0.08 0.03 0.05 2/98 6
  PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
    1     0 root     R     3164   0%   0% top -b

该指令最恰当的用户是社会镜像的主要命令,允许该镜像像该命令一样运行,然后使用CMD作为默认标志

ENTRYPOINT ["s3cmd"]
CMD ["--help"]

我们可以输入以下命令来显示命令的帮助

$ docker run s3cmd

使用正确的参数执行该命令:

$ docker run s3cmd ls s3://mybucket

VOLUME

该指令用于公开暴露容器所创建的任何数据存储区域,配置存储文件或者文件夹。使用VOLUME指令配置任何可变的或是用户可维护的部分。

VOLUME ["/data"]

该VOLUME指令将创建具有指定名称的安装点,并将其标记为从本机主机或其他容器保存外部安装的卷。该值可以是JSON数组,VOLUME ["/var/log/"]或具有多个参数的纯字符串,例如VOLUME /var/log或VOLUME /var/log /var/db

USER

该指令用于配置运行服务的用户,一般用户将普通用户更改我root用户,解决权限不足的问题

USER <user>[:<group>] or
USER <UID>[:<GID>]

该USER指令设置用户名(或UID)和可选的用户组(或GID)在运行图像时使用RUN

注:当用户没有主组时,将使用该root组运行映像

WORKDIR

WORKDIR /path/to/workdir

该指令用于配置工作目录,其参数应该使用绝对目录。该命令其实也就是RUN cd … && do-something的变体。使其更清楚

该WORKDIR指令可以在一次使用多次Dockerfile。如果提供了相对路径,它将相对于上一条WORKDIR指令的路径 。例如:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

最终pwd命令的输出Dockerfile就是这样 /a/b/c

ARG

ARG <name>[=<default value>]

该ARG指令定义了用户可以docker build使用该--build-arg <varname>=<value> 标志使用命令在构建时传递给构建器的变量。如果用户指定了在Dockerfile中未定义的构建参数,则构建会输出警告[Warning] One or more build-args [foo] were not consumed.

Docker文件可以包括一个或多个ARG指令。例如,以下是一个有效的Docker文件

FROM busybox
ARG user1
ARG buildno
...

ARG默认值

ARG指令可以可选地包括一个默认值

FROM busybox
ARG user1=someuser
ARG buildno=1
...

如果ARG指令具有默认值,并且如果在构建时没有传递任何值,则构建器将使用默认值。

ONBUILD

该指令在当前Dockerfile构建完成后执行。ONBUILD在导出FROM当前图像的任何子图像中执行。将该ONBUILD命令视为父母Dockerfile给予孩子的指示Dockerfile。

注:

  • ddocker Version: 17.05.0-ce
  • docker-machine version 0.12.2, build 9371605
  • 上述环境在ubuntu16.04 lts中搭建测试成功
  • 上述文字皆为个人看法,如有错误或建议请及时联系我

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:EarthChen

查看原文:Docker学习笔记---Dockerfile

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

2831 次点击  ∙  1 赞  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传