使用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. easyUI之progressbar进度条

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...

  2. Swagger介绍及使用

    相信无论是前端还是后端开发,都或多或少地被接口文档折磨过.前端经常抱怨后端给的接口文档与实际情况不一致.后端又觉得编写及维护接口文档会耗费不少精力,经常来不及更新.其实无论是前端调用后端,还是后端调用 ...

  3. VBA MD5加密算法(转)

    ) ) Private Function LShift(lValue, iShiftBits) Then LShift = lValue Exit Function Then Then LShift ...

  4. 数据中心网络架构的问题与演进 — 云网融合与 SD-WAN

    目录 文章目录 目录 前文列表 云网融合 云网融合的应用场景 SD-WAN SD-WAN 的应用场景 企业组网互联 SD-EN 数据中心互联 SD-DCI 云间互联 SD-CX 企业用户接入云 数据中 ...

  5. zabbix通过SDK和API获取阿里云RDS的监控数据

    阿里云的RDS自带的监控系统获取数据不怎么直观,想要通过API获取数据通过zabbix显示,因为网上资料缺乏和其他一些原因,获取API签名很困难,但使用阿里云的SDK可以完美避开获取签名的步骤. 阿里 ...

  6. mysql RPM 包比较全的网站

    https://pkgs.org/download/mysql-devel https://pkgs.org/download/mysql-server https://pkgs.org/downlo ...

  7. jvm小白

    tomcat设置可被jconsole监控: 在catalina.bat或catalina.sh里面加上. set JAVA_OPTS=-Djava.rmi.server.hostname=127.0. ...

  8. 测试ssh转发

    端口转发提供: 1.加密 SSH Client 端至 SSH Server 端之间的通讯数据. 2.突破防火墙的限制完成一些之前无法建立的 TCP 连接. 但是只能转发tcp连接,想要转发UDP,需要 ...

  9. 【Zookeeper】利用zookeeper搭建Hdoop HA高可用

    HA概述 所谓HA(high available),即高可用(7*24小时不中断服务). 实现高可用最关键的策略是消除单点故障.HA严格来说应该分成各个组件的HA机制:HDFS的HA和YARN的HA. ...

  10. Golang gRPC微服务02: helloworld

    安装protobuf 在windows下,直接下载release版本https://github.com/protocolbuffers/protobuf/releases/tag/v3.9.0然后把 ...