Docker学习笔记---Dockerfile
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是为了确保不被缓存所干扰,保证安装的软件是比较新的版本。
以下是一个使用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/*
最后删除/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中搭建测试成功
- 上述文字皆为个人看法,如有错误或建议请及时联系我