Dockerfile-官网翻译

Dockerfile 命令详解—官方文档
Dockerfile 最佳实践—官方文档

用法

docker build -t 镜像名:标签 .
# 用来指定Dockerfile地址,如果执行此命令所在目录就是Dockerfile目录,则可以省略
-f /etc/Dockerfile
# 可以指定构建多个镜像
-t 镜像名:标签1 -t 镜像名:标签2

Windows情况

  • 错误
    1
    2
    3
    FROM microsoft/nanoserver
    COPY testfile.txt c:\\
    RUN dir c:\
  • 正常
    1
    2
    3
    4
    5
    # escape=`

    FROM microsoft/nanoserver
    COPY testfile.txt c:\
    RUN dir c:\

    环境替换

  • $variable_name${variable_name}表达意思一致,但是大括号可以用来表示拼接${foo}_bar
  • ${variable_name}语法支持bash指定的一些标准修饰符
    • ${variable:-word}表示如果variable设置,则结果为该值.未设置则为word
    • ${variable:+word}表示如果variable设置,则结果为word.未设置则为空字符串
  • 转义\ 例如\$foo\${foo}将分别转换为$foo${foo}字符串 不会是变量
    1
    2
    3
    4
    5
    FROM busybox
    ENV foo /bar
    WORKDIR ${foo} # WORKDIR /bar
    ADD . $foo # ADD . /bar
    COPY \$foo /quux # COPY $foo /quux
  • Dockerfile支持的关键词
    • ADD
    • COPY
    • ENV
    • EXPOSE
    • FROM
    • LABEL
    • STOPSIGNAL
    • USER
    • VOLUME
    • WORKDIR
    • ONBUILD 当与上面支持的一个指令结合使用时

.dockerignore文件

除了README.md所有的.md文件都忽略

1
2
*.md
!README.md
  • temp?匹配根目录下的/tempa/tempb 被忽略
  • */temp*表示/somedir/temporary.txt/somedir/temp被忽略
  • */*/temp*表示/somedir/subdir/temporary.txt被忽略

FROM

1
2
3
4
FROM 镜像名:标签

如果标签为`latest`时
FROM 镜像名

指定基本镜像,放在第一行
可以多次出现,创建多个镜像,也可以在一个镜像继续构建镜像

RUN

将长的复杂的RUN尽可能使用\反斜杠分割,提高可读性
如果指定了apt-get更新失败,因为有RUN指令缓存,可以使用指定版本号进行更新

1
2
3
4
RUN apt-get update && apt-get install -y \
package-bar \
package-baz \
package-foo=1.3.*

如果失败,执行另外一个命令

1
2
如果`wget -O - https://some.site`失败 就执行`wc -l > /number`
RUN wget -O - https://some.site | wc -l > /number

这里的命令为Shell命令,默认是Linux的/bin/sh -ccmd /S /CWindows

1
RUN 命令

exec形式

1
RUN ["executable", "param1", "param2"]

可以使用\来继续到下一行,下面两者相等

1
2
3
4
RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'

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

如果想用/bin/sh以外的形式,使用exec形式,这里需要使用双引号,因为exec形式会解析为JSON数组
例如RUN ["/bin/bash", "-c", "echo hello"]

对于exec形式RUN [ "echo", "$HOME" ]不会进行变量替换,可以使用RUN [ "sh", "-c", "echo $HOME" ]

对于JSON形式必须转义\反斜杠.
在Windows中\反斜杠是路径分隔符
RUN ["c:\windows\system32\tasklist.exe"]执行异常
RUN ["c:\\windows\\system32\\tasklist.exe"]执行正常

对于RUN指令,下一次构建继续生效.
可以使用--no-cache来对RUN指令缓存失效docker build --no-cache

CMD

CMD ["executable","param1","param2"] 这是首选的exec形式
CMD ["param1","param2"]作为ENTRYPOINT的默认参数
CMD command param1 param2这是shell形式

支持这三种形式,但在Dockerfile中只支持最后一条CMD命令生效
exec形式会解析为JSON数组,因此需要使用双引号
运行容器docker run ...会覆盖CMD指令

LABEL

两种效果相同,可以使用多个LABEL标签来标注信息,但最好合并为一个

1
2
3
4
5
LABEL multi.label1="value1" multi.label2="value2" other="value3"

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

使用双引号或者使用\反斜杠转义

1
2
LABEL vendor1="ACME Incorporated"
LABEL vendor2=ZENITH\ Incorporated

MAAINAINER 已弃用

LABEL灵活替代
LABEL maintainer="mritd <mritd@linux.com>"

EXPOSE

可以指定向外暴露端口

也可以指定协议TCP还是UDP 默认TCP
EXPOSE 80/udp指定UDP协议的80端口

要同时在TCP和UDP上公开,请包括以下两行

1
2
EXPOSE 80/tcp
EXPOSE 80/udp

运行它们使用-p来覆盖
docker run -p 80:80/tcp -p 80:80/udp ...

ENV

1
2
ENV key value
ENV key=value key=value ...

第一种形式,只能设置一个值
key后面空格 后面的全部值都视为字符串value的值,包括空格

第二种形式,可用于反斜杠 双引号
例如 下面两种相同

1
2
3
4
5
6
ENV myName="John Doe" myDog=Rex\ The\ Dog \
myCat=fluffy

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

运行容器时可以使用docker run --env key=value...来改变

ADD

1
ADD Linux路径 容器路径

复制文件到镜像中
ADD hom* /mydir/# 表示以hom开头的所有文件
ADD hom?.txt /mydir/# 表示复制一个字符,例如home.txt

后面一个路径是绝对路径或相对WORKDIR的路径
ADD test relativeDir/添加到WORKDIR/relativeDir/
ADD test /absoluteDir/添加到/absoluteDir/
ADD arr[[]0].txt /mydir/添加arr[0].txt

注意事项:

  • Linux路径如果是目录,则容器路径也是目录,斜杠结尾,复制后容器路径/Linux路径
  • Linux路径直接或由于使用通配符而指定了多个资源,则容器路径必须是目录,并且必须以/斜杠结尾
  • 容器路径不以斜杠结尾,则将其视为常规文件,并将其内容Linux路径写入容器路径
  • 容器路径不存在,它将与路径中所有缺少的目录一起创建

COPY

同上

1
COPY Linux路径 容器路径

ENTRYPOINT

ENTRYPOINT ["executable", "param1", "param2"]这是首选的exec形式
ENTRYPOINT command param1 param2这是shell形式
会覆盖所有的CMD指令,只有最后一条ENTRYPOINT生效
也可以在容器运行时覆盖docker run --entrypoint

如果想用/bin/sh以外的形式,使用exec形式,这里需要使用双引号,因为exec形式会解析为JSON数组
例如ENTRYPOINT ["/bin/bash", "-c", "echo hello"]

对于exec形式ENTRYPOINT [ "echo", "$HOME" ]不会进行变量替换,可以使用ENTRYPOINT [ "sh", "-c", "echo $HOME" ]

VOLUME

1
2
3
4
5
6
7
8
exec形式
VOLUME ["/var/log/"]

shell形式
VOLUME /var/log/

指定多个
VOLUME /var/log /var/db

如果已经是容器卷,再次构建更改了这个容器卷,更改将不生效

USER

1
2
3
USER <user>[:<group>]

USER <UID>[:<GID>]

USER指令设置运行映像时以及用于任何映像时使用的用户名(或UID)和可选的用户组(或GID)

ARG

指定一个变量
通常使用ARGENV来指定变量供RUN使用
同名情况下ENV会覆盖ARG的变量
例如

1
2
3
4
5
6
7
8
FROM alpine:3.7

LABEL maintainer="mritd <mritd@linux.com>"

ARG TZ="Asia/Shanghai"

ENV TZ ${TZ}
...

WORKDIR

1
WORKDIR /path/to/workdir

用来指定工作目录

1
2
3
4
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd # /a/b/c
1
2
3
ENV DIRPATH /path
WORKDIR $DIRPATH/aaa
RUN pwd # /path/aaa

Dockerfile实例

1
2
3
4
5
6
7
# Nginx
#
# VERSION 0.0.1

FROM ubuntu
LABEL Description="This image is used to start the foobar executable" Vendor="ACME Products" Version="1.0"
RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Firefox over VNC
#
# VERSION 0.3

FROM ubuntu

# Install vnc, xvfb in order to create a 'fake' display and firefox
RUN apt-get update && apt-get install -y x11vnc xvfb firefox
RUN mkdir ~/.vnc
# Setup a password
RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
# Autostart firefox (might not be the best way, but it does the trick)
RUN bash -c 'echo "firefox" >> /.bashrc'

EXPOSE 5900
CMD ["x11vnc", "-forever", "-usepw", "-create"]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Multiple images example
#
# VERSION 0.1

FROM ubuntu
RUN echo foo > bar
# Will output something like ===> 907ad6c2736f

FROM ubuntu
RUN echo moo > oink
# Will output something like ===> 695d7793cbe4

# You'll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with
# /oink.