使用docker build命令或使用Docker Hub的自动构建功能构建Docker镜像时,都需要一个Dockerfile文件。Dockerfile文件是一个由一系列构建指令组成的文本文件,docker build命令会根据这些构建指令完成Docker镜像的构建。本文将会介绍Dockerfile文件,及其中使用的构建指令。

  1. Dockerfile文件使用
  2. Dockerfile文件格式
  3. Dockerfile中使用指令

1. Dockerfile文件使用

docker build命令会根据Dockerfile文件及上下文构建新Docker镜像。构建上下文是指Dockerfile所在的本地路径或一个URLGit仓库地址)。构建上下文环境会被递归处理,所以,构建所指定的路径还包括了子目录,而URL还包括了其中指定的子模块。

构建镜像

将当前目录做为构建上下文时,可以像下面这样使用docker build命令构建镜像:

$ docker build .
Sending build context to Docker daemon 6.51 MB
...

说明:构建会在Docker后台守护进程(daemon)中执行,而不是CLI中。构建前,构建进程会将全部内容(递归)发送到守护进程。大多情况下,应该将一个空目录作为构建上下文环境,并将Dockerfile文件放在该目录下。

在构建上下文中使用的Dockerfile文件,是一个构建指令文件。为了提高构建性能,可以通过.dockerignore文件排除上下文目录下,不需要的文件和目录。

Dockerfile一般位于构建上下文的根目录下,也可以通过-f指定该文件的位置:

$ docker build -f /path/to/a/Dockerfile .

构建时,还可以通过-t参数指定构建成后,镜像的仓库标签等:

镜像标签

$ docker build -t shykes/myapp .

如果存在多个仓库下,或使用多个镜像标签,就可以使用多个-t参数:

$ docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .

在Docker守护进程执行Dockerfile中的指令前,首先会对Dockerfile进行语法检查,有语法错误时会返回:

$ docker build -t test/myapp .
Sending build context to Docker daemon 2.048 kB
Error response from daemon: Unknown instruction: RUNCMD

缓存

Docker 守护进程会一条一条的执行Dockerfile中的指令,而且会在每一步提交并生成一个新镜像,最后会输出最终镜像的ID。生成完成后,Docker 守护进程会自动清理你发送的上下文。

Dockerfile文件中的每条指令会被独立执行,并会创建一个新镜像,RUN cd /tmp等命令不会对下条指令产生影响。

Docker 会重用已生成的中间镜像,以加速docker build的构建速度。以下是一个使用了缓存镜像的执行过程:

$ docker build -t svendowideit/ambassador .
Sending build context to Docker daemon 15.36 kB
Step 1/4 : FROM alpine:3.2
---> 31f630c65071
Step 2/4 : MAINTAINER SvenDowideit@home.org.au
---> Using cache
---> 2a1c91448f5f
Step 3/4 : RUN apk update && apk add socat && rm -r /var/cache/
---> Using cache
---> 21ed6e7fbb73
Step 4/4 : CMD env | grep _TCP= | (sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/' && echo wait) | sh
---> Using cache
---> 7ea8aef582cc
Successfully built 7ea8aef582cc

构建缓存仅会使用本地父生成链上的镜像。如果不想使用本地缓存的镜像,也可以通过--cache-from指定缓存。指定后将再不使用本地生成的镜像链,而是从镜像仓库中下载。

2. Dockerfile文件格式

Dockerfile文件格式如下:

# Comment
INSTRUCTION arguments
# 注释
指令 参数

Dockerfile文件中指令不区分大小写,但为了更易区分,约定使用大写形式。

Docker 会依次执行Dockerfile中的指令,文件中的第一条指令必须是FROMFROM指令用于指定一个基础镜像。

#开头的行,Docker会认为是注释。但#出现在指令参数中时,则不是注释。如:

# Comment
RUN echo 'we are running some # of cool things'

3. Dockerfile中使用指令

3.1 FROM

FROM指令用于指定其后构建新镜像所使用的基础镜像。FROM指令必是Dockerfile文件中的首条命令,启动构建流程后,Docker将会基于该镜像构建新镜像,FROM后的命令也会基于这个基础镜像。

FROM语法格式为:

FROM <image>

FROM <image>:<tag>

FROM <image>:<digest>

通过FROM指定的镜像,可以是任何有效的基础镜像。FROM有以下限制:

  • FROM必须是Dockerfile中第一条非注释命令
  • 在一个Dockerfile文件中创建多个镜像时,FROM可以多次出现。只需在每个新命令FROM之前,记录提交上次的镜像ID。
  • tagdigest是可选的,如果不使用这两个值时,会使用latest版本的基础镜像

3.2 RUN

RUN用于在镜像容器中执行命令,其有以下两种命令执行方式:

shell执行

在这种方式会在shell中执行命令,Linux下默认使用/bin/sh -c,Windows下使用cmd /S /C

注意:通过SHELL命令修改RUN所使用的默认shell

RUN <command>

exec执行

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

RUN可以执行任何命令,然后在当前镜像上创建一个新层并提交。提交后的结果镜像将会用在Dockerfile文件的下一步。

通过RUN执行多条命令时,可以通过\换行执行:

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

也可以在同一行中,通过分号分隔命令:

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

RUN指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache参数,如:docker build --no-cache

3.3 CMD

CMD用于指定在容器启动时所要执行的命令。CMD有以下三种格式:

CMD ["executable","param1","param2"]
CMD ["param1","param2"]
CMD command param1 param2

CMD不同于RUNCMD用于指定在容器启动时所要执行的命令,而RUN用于指定镜像构建时所要执行的命令。

CMDRUN在功能实现上也有相似之处。如:

docker run -t -i itbilu/static_web_server /bin/true

等价于:

cmd ["/bin/true"]

CMDDockerfile文件中仅可指定一次,指定多次时,会覆盖前的指令。

另外,docker run命令也会覆盖DockerfileCMD命令。如果docker run运行容器时,使用了DockerfileCMD相同的命令,就会覆盖Dockerfile中的CMD命令。

如,我们在构建镜像的Dockerfile文件中使用了如下指令:

CMD ["/bin/bash"]

使用docker build构建一个新镜像,镜像名为itbilu/test。构建完成后,使用这个镜像运行一个新容器,运行效果如下:

$ sudo docker run -i -t itbilu/test
root@e3597c81aef4:/#

在使用docker run运行容器时,我们并没有在命令结尾指定会在容器中执行的命令,这时Docker就会执行在DockerfileCMD中指定的命令。

如果不想使用CMD中指定的命令,就可以在docker run命令的结尾指定所要运行的命令:

$ sudo docker run -i -t itbilu/test /bin/ps
PID TTY TIME CMD
1 ? 00:00:00 ps

这时,docker run结尾指定的/bin/ps命令覆盖了DockerfileCMD中指定的命令。

3.4 ENTRYPOINT

ENTRYPOINT用于给容器配置一个可执行程序。也就是说,每次使用镜像创建容器时,通过ENTRYPOINT指定的程序都会被设置为默认程序。ENTRYPOINT有以下两种形式:

ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2

ENTRYPOINTCMD非常类似,不同的是通过docker run执行的命令不会覆盖ENTRYPOINT,而docker run命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINTDockerfile中只允许有一个ENTRYPOINT命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT指令。

docker run运行容器时指定的参数都会被传递给ENTRYPOINT,且会覆盖CMD命令指定的参数。如,执行docker run <image> -d时,-d参数将被传递给入口点。

也可以通过docker run --entrypoint重写ENTRYPOINT入口点。

如:可以像下面这样指定一个容器执行程序:

ENTRYPOINT ["/usr/bin/nginx"]

完整构建代码:

# Version: 0.0.3
FROM ubuntu:16.04
MAINTAINER 何民三 "cn.liuht@gmail.com"
RUN apt-get update
RUN apt-get install -y nginx
RUN echo 'Hello World, 我是个容器' \
> /var/www/html/index.html
ENTRYPOINT ["/usr/sbin/nginx"]
EXPOSE 80

使用docker build构建镜像,并将镜像指定为itbilu/test

$ sudo docker build -t="itbilu/test" .

构建完成后,使用itbilu/test启动一个容器:

$ sudo docker run -i -t  itbilu/test -g "daemon off;"

在运行容器时,我们使用了-g "daemon off;",这个参数将会被传递给ENTRYPOINT,最终在容器中执行的命令为/usr/sbin/nginx -g "daemon off;"

3.5 LABEL

LABEL用于为镜像添加元数据,元数以键值对的形式指定:

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

使用LABEL指定元数据时,一条LABEL指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条LABEL指令指定,以免生成过多的中间镜像。

如,通过LABEL指定一些元数据:

LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"

指定后可以通过docker inspect查看:

$sudo docker inspect itbilu/test
"Labels": {
"version": "1.0",
"description": "这是一个Web服务器",
"by": "IT笔录"
},

注意;Dockerfile中还有个MAINTAINER命令,该命令用于指定镜像作者。但MAINTAINER并不推荐使用,更推荐使用LABEL来指定镜像作者。如:

LABEL maintainer="itbilu.com"

3.6 EXPOSE

EXPOSE用于指定容器在运行时监听的端口:

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

EXPOSE并不会让容器的端口访问到主机。要使其可访问,需要在docker run运行容器时通过-p来发布这些端口,或通过-P参数来发布EXPOSE导出的所有端口。

3.7 ENV

ENV用于设置环境变量,其有以下两种设置形式:

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

如,通过ENV设置一个环境变量:

ENV ITBILU_PATH /home/itbilu/

设置后,这个环境变量在ENV命令后都可以使用。如:

WORKERDIR $ITBILU_PATH

这些环境变量不仅可以构建镜像过程使用,使用该镜像创建的容器中也可以使用。如:

$ docker run -i -t  itbilu/test
root@196ca123c0c3:/# cd $ITBILU_PATH
root@196ca123c0c3:/home/itbilu#

3.8 ADD

ADD用于复制构建环境中的文件或目录到镜像中。其有以下两种使用方式:

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

通过ADD复制文件时,需要通过<src>指定源文件位置,并通过<dest>来指定目标位置。<src>可以是一个构建上下文中的文件或目录,也可以是一个URL,但不能访问构建上下文之外的文件或目录。

如,通过ADD复制一个网络文件:

ADD http://wordpress.org/latest.zip $ITBILU_PATH

在上例中,$ITBILU_PATH是我们使用ENV指定的一个环境变量。

另外,如果使用的是本地归档文件(gzipbzip2xz)时,Docker会自动进行解包操作,类似使用tar -x

3.9 COPY

COPY同样用于复制构建环境中的文件或目录到镜像中。其有以下两种使用方式:

COPY <src>... <dest>
COPY ["<src>",... "<dest>"]

COPY指令非常类似于ADD,不同点在于COPY只会复制构建目录下的文件,不能使用URL也不会进行解压操作。

3.10 VOLUME

VOLUME用于创建挂载点,即向基于所构建镜像创始的容器添加卷:

VOLUME ["/data"]

一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:

  • 卷可以容器间共享和重用
  • 容器并不一定要和其它容器共享卷
  • 修改卷后会立即生效
  • 对卷的修改不会对镜像产生影响
  • 卷会一直存在,直到没有任何容器在使用它

VOLUME让我们可以将源代码、数据或其它内容添加到镜像中,而又不并提交到镜像中,并使我们可以多个容器间共享这些内容。

如,通过VOLUME创建一个挂载点:

ENV ITBILU_PATH /home/itbilu/
VOLUME [$ITBILU_PATH]

构建的镜像,并指定镜像名为itbilu/test。构建镜像后,使用新构建的运行一个容器。运行容器时,需-v参将能本地目录绑定到容器的卷(挂载点)上,以使容器可以访问宿主机的数据。

$ sudo docker run -i -t -v ~/code/itbilu:/home/itbilu/  itbilu/test
root@31b0fac536c4:/# cd /home/itbilu/
root@31b0fac536c4:/home/itbilu# ls
README.md app.js bin config.js controller db demo document lib minify.js node_modules package.json public routes test views

如上所示,我们已经可以容器的/home/itbilu/目录下访问到宿主机~/code/itbilu目录下的数据了。

3.11 USER

USER用于指定运行镜像所使用的用户:

USER daemon

使用USER指定用户时,可以使用用户名、UIDGID,或是两者的组合。以下都是合法的指定试:

USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group

使用USER指定用户后,Dockerfile中其后的命令RUNCMDENTRYPOINT都将使用该用户。镜像构建完成后,通过docker run运行容器时,可以通过-u参数来覆盖所指定的用户。

3.12 WORKDIR

WORKDIR用于在容器内设置一个工作目录:

WORKDIR /path/to/workdir

通过WORKDIR设置工作目录后,Dockerfile中其后的命令RUNCMDENTRYPOINTADDCOPY等命令都会在该目录下执行。

如,使用WORKDIR设置工作目录:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

在以上示例中,pwd最终将会在/a/b/c目录中执行。

在使用docker run运行容器时,可以通过-w参数覆盖构建时所设置的工作目录。

3.13 ARG

ARG用于指定传递给构建运行时的变量:

ARG <name>[=<default value>]

如,通过ARG指定两个变量:

ARG site
ARG build_user=IT笔录

以上我们指定了sitebuild_user两个变量,其中build_user指定了默认值。在使用docker build构建镜像时,可以通过--build-arg <varname>=<value>参数来指定或重设置这些变量的值。

$ sudo docker build --build-arg site=itiblu.com -t itbilu/test .

这样我们构建了itbilu/test镜像,其中site会被设置为itbilu.com,由于没有指定build_user,其值将是默认值IT笔录

3.14 ONBUILD

ONBUILD用于设置镜像触发器:

ONBUILD [INSTRUCTION]

当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发。

如,当镜像被使用时,可能需要做一些处理:

[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]

3.15 STOPSIGNAL

STOPSIGNAL用于设置停止容器所要发送的系统调用信号:

STOPSIGNAL signal

所使用的信号必须是内核系统调用表中的合法的值,如:9SIGKILL

3.16 SHELL

SHELL用于设置执行命令(shell式)所使用的的默认shell类型:

SHELL ["executable", "parameters"]

SHELL在Windows环境下比较有用,Windows下通常会有cmdpowershell两种shell,可能还会有sh。这时就可以通过SHELL来指定所使用的shell类型:

FROM microsoft/windowsservercore

# Executed as cmd /S /C echo default
RUN echo default # Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default # Executed as powershell -command Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello # Executed as cmd /S /C echo hello
SHELL ["cmd", "/S"", "/C"]
RUN echo hello

更多参考:

原文链接:https://itbilu.com/linux/docker/VyhM5wPuz.html

Docker镜像构建文件Dockerfile及相关命令介绍的更多相关文章

  1. Docker 镜像构建之 Dockerfile

    在 Docker 中创建镜像最常用的方式,就是使用 Dockerfile.Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明.官方文档:https://d ...

  2. Docker镜像构建之Dockerfile

    在 Docker 中构建镜像最常用的方式就是使用 Dockerfile.Dockerfile 是一个用来构建镜像的文本文件. 官方文档:https://docs.docker.com/engine/r ...

  3. Dockerfile自动制作Docker镜像(二)—— 其它常用命令

    Dockerfile自动制作Docker镜像(二)-- 其它常用命令 前言 a. 本文主要为 Docker的视频教程 笔记. b. 环境为 CentOS 7.0 云服务器 c. 上一篇:Dockerf ...

  4. (转)Docker镜像构建上下文(Context)

    镜像构建上下文(Context) Docker在构建镜像时,如果注意,会看到 docker build 命令最后有一个 ... 表示当前目录,而 Dockerfile 就在当前目录,因此不少初学者以为 ...

  5. Docker镜像构建(五)

    Docker 镜像介绍 Docker镜像构建分为两种,一种是手动构建,另一种是Dockerfile(自动构建) 手动构建docker镜像 案例:我们基于centos镜像进行构建,制作自己的nginx镜 ...

  6. 4、Docker 镜像构建

    Docker 镜像构建 构建分为两种 手动构建 自动构建dockerfile 手动构建 首先启动一个Centos 容器,然后在容器中安装一个nginx [root@node ~]# docker ru ...

  7. Docker镜像构建原理解析(不装docker也能构建镜像)

    在devops流程里面 构建镜像是一个非常重要的过程,一般构建镜像是写dockerfile文件然后通过docker client来构建的image. docker client 会先检查本地有没有im ...

  8. redis事务及相关命令介绍

    redis事务及相关命令介绍 一.概述:和众多其它数据库一样,Redis作为NoSQL数据库也同样提供了事务机制.在Redis中,MULTI/EXEC/DISCARD/WATCH这四个命令是我们实现事 ...

  9. Docker镜像构建的两种方式

    关于Docker里面的几个主要概念 这里用个不太恰当的比方来说明. 大家肯定安装过ghost系统,镜像就像是ghost文件,容器就像是ghost系统.你可以拿别人的ghost文件安装系统(使用镜像运行 ...

随机推荐

  1. 处理输入为非对角阵的Clustering by fast search and find of density peak代码

    Clustering by fast search and find of density peak. Alex Rodriguez, Alessandro Laio 是发表在Science上的一篇很 ...

  2. JVM调优小结

    JVM调优浅谈 https://www.cnblogs.com/andy-zhou/p/5327288.html   1.数据类型 java虚拟机中,数据类型可以分为两类:基本类型和引用类型. 基本类 ...

  3. SQL Server 时间戳与时间格式互相转换

    时间戳(Unix timestamp) 是一种时间表示方式,定义为从格林威治时间1970年01月01日00时00分00秒起至现在的总秒数. Unix时间戳不仅被使用在Unix系统.类Unix系统中,也 ...

  4. VS2012编译php扩展

    注意:用VS2015来做会比较好! 开发前准备工作:cygwinvisual studio 2012php编译后的程序      使用的是 xampp集成安装包,所以编译后的程序路径为D:\xampp ...

  5. .Netcore 2.0 Ocelot Api网关教程(2)- 路由

    .Netcore 2.0 Ocelot Api网关教程(1) 路由介绍 上一篇文章搭建了一个简单的Api网关,可以实现简单的Api路由,本文介绍一下路由,即配置文件中ReRoutes,ReRoutes ...

  6. Docker Swarm常用命令

    #查看集群节点 docker node ls #创建nginx服务 #docker pull hub.test.com:5000/almi/nginx:0.1 #下载私有仓库镜像 docker ser ...

  7. Fabric1.4 链码开发,开发模式下的测试

    关闭之前已启动的网络环境 sudo docker-compose -f docker-compose-cli.yaml down 进入devmode目录:  cd ~/go/src/github.co ...

  8. PTA(Advanced Level)1083.List Grades

    Given a list of N student records with name, ID and grade. You are supposed to sort the records with ...

  9. Linux:shift 命令可以将参数依次向左移动一个位置

    在脚本中,命令行参数可以依据其在命令行中的位置来访问.第一个参数是 $1 ,第二个参数 是 $2 ,以此类推. 下面的语句可以显示出前3个命令行参数: echo $1 $2 $3 更为常见的处理方式是 ...

  10. foreach中的&用法

    原地址:https://blog.csdn.net/qq_38287952/article/details/79468321 例如,给数组添加一个新的元素. 这里的需求是统计商品收入,就可以用到&am ...