Docker之Dockerfile用法
一、Dockerfile简介
Dockerfile用于自动化创建Docker镜像。 Docker通过阅读Dockerfile中的指令代码来构建镜像文件。
1、Dockerfile编写示例
# 基础镜像node:8.11-slim
FROM node:8.11-slim
#帮助信息了,类似于代码的注释信息
LABEL "about"="This file is just am example to demonstarte the LABEL"
#环境变量
ENV workdirectory /usr/node
#工作目录
WORKDIR $workdirectory
WORKDIR app
#复制文件
COPY package.json .
RUN ls -ll
# command executable and version
ENTRYPOINT ["node"]
2、Dockerfile编写思路
首先是,准备原镜像;
然后是,准备环境。比如需要的依赖文件、环境变量、工作目录、暴露的端口、用户等;
最后是,运行容器时执行的命令。
二、Dockerfile常用指令
1、FROM
FROM
指令是构建镜像的初始阶段,它指明了基础镜像的来源,后续的操作都是基于该镜像。因此,有效的Dockerfile
必须从FROM
指令开始。
RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'
2、MAINTAINER(不推荐)
该MAINTAINER
指令设置生成图像的作者字段。
MAINTAINER <name>
不过,MAINTAINER并不推荐使用,更推荐使用LABEL来指定镜像作者,例如:
#示例:
LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
3、LABEL
LABEL <key>=<value> <key>=<value> <key>=<value> ...
Label 指令可以向镜像中添加元数据信息。 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."
一个镜像中可以有多个标签。 也可以在一行中指定多个标签。
#一行中指定多个标签
LABEL multi.label1="value1" multi.label2="value2" other="value3"
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
4、RUN
执行命名并创建新的Image Layer。有以下两种格式:
- shell 格式:
# <命令行命令> 等同于,在终端操作的 shell 命令。
RUN <command>
- exec 格式:
RUN ["executable", "param1", "param2"]
RUN ["可执行文件", "参数1", "参数2"]
注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:
FROM centos
RUN yum install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz
以上执行会创建 3 层镜像。可简化为以下格式:
FROM centos
RUN yum install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz
如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。
5、COPY
复制指令,从上下文目录中复制文件或者目录到容器里指定路径。
COPY [--chown=<user>:<group>] <源路径1>... <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
这个---- chown 特性只支持用于构建 Linux 容器的 Dockerfiles,不支持 Windows 容器。
6、ADD(不推荐)
ADD 指令和 COPY 的使用格式一致(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:
ADD [--chown=<user>:<group>] <源路径1>... <目标路径>
ADD [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]
- ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
- ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。
7、ENV
设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。
ENV <key> <value>
ENV <key>=<value> ...
以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:
ENV NODE_VERSION 7.2.0
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"
8、VOLUME
Volume 指令创建具有指定名称的挂载点,并将其标记为保存来自本机主机或其他容器的外部挂载的卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。
作用:
- 避免重要的数据,因容器重启而丢失,这是非常致命的。
- 避免容器不断变大。
格式:
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>
在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。
Dockerfile示例:
FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol
9、EXPOSE
Expose 指令通知 Docker 容器在运行时监听指定的网络端口。 您可以指定端口是否侦听 TCP 或 UDP,如果没有指定协议,则默认为 TCP。
EXPOSE <port> [<port>/<protocol>...]
默认情况下,EXPOSE 假设为 TCP。您也可以指定 UDP:
EXPOSE 80/udp
10、WORKDIR
指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。
WORKDIR <工作目录路径>
11、CMD
设置容器启动后默认执行的命令和参数,需要注意的是docker run指定了其他的命令,CMD命令将会被忽略。如果定义了多个CMD,只有最后一个会执行。
[root@xtank test]# docker build -t centos-run-shell .
Sending build context to Docker daemon 3.072kB
Step 1/3 : FROM centos
---> 470671670cac
Step 2/3 : ENV name Docker
---> Using cache
---> 09255c3a6fef
Step 3/3 : RUN echo "hello $name"
---> Running in 2b2494da2824
hello Docker
Removing intermediate container 2b2494da2824
---> 91fa3518d762
Successfully built 91fa3518d762
Successfully tagged centos-run-shell:latest
[root@xtank test]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos-run-shell latest 91fa3518d762 5 seconds ago 237MB
[root@xtank test]# docker run 91fa3518d762
hello Docker
#docker run指定了其他的命令,CMD命令将会被忽略,没有再打印hello Docker
[root@xtank test]# docker run -it 91fa3518d762 /bin/bash
[root@10b796f0c34f /]#
12、ENTRYPOINT
设置容器启动时运行的命令。让容器以应用程序或者服务的形式运行。它不会被忽略,一定会执行。
[root@xtank test]# docker build -t centos-shell .
Sending build context to Docker daemon 3.072kB
Step 1/3 : FROM centos
---> 470671670cac
Step 2/3 : ENV name Docker
---> Running in 33d9099aae96
Removing intermediate container 33d9099aae96
---> 09255c3a6fef
Step 3/3 : ENTRYPOINT echo "hello $name"
---> Running in 137f62845b79
Removing intermediate container 137f62845b79
---> a87036aba148
Successfully built a87036aba148
Successfully tagged centos-shell:latest
[root@xtank test]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos-shell latest a87036aba148 5 seconds ago 237MB
#设置容器启动时运行的命令,容器启动时会执行
[root@xtank test]# docker run a87036aba148
hello Docker
#设置容器启动时运行的命令,容器启动时一定会执行
[root@xtank test]# docker run -it a87036aba148 /bin/bash
hello Docker
注意:Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅有最后一个会生效。
三、参考
DockerFile示例:https://github.com/docker-library
DockerFile官方说明:https://docs.docker.com/engine/reference/builder/#from