本篇开始来学习关于 dockerfile 的知识。

注:环境为 CentOS7,docker 19.03。

dockerfile 是⼀个⽂本格式的配置⽂件, ⽤户可以使⽤ dockerfile 来快速创建⾃定义的镜像。

指令系统

dockerfile 主要是通过一个指令来实现想要的功能的。dockerfile 支持的指令如下

ARG

定义创建镜像过程中使⽤的变量。格式为:

ARG<name>[=<default value>]

在执⾏docker build时, 可以通过 -build-arg[=] 来为变量赋值。 当镜像编译成功后, ARG指定的变量将不再存在(ENV指定的变量将在镜像中保留)。

Docker内置了⼀些镜像创建变量, ⽤户可以直接使⽤⽽⽆须声明, 包括(不区分⼤⼩写) HTTP_PROXY、 HTTPS_PROXY、 FTP_PROXY、NO_PROXY。`

FROM busybox
ARG user1
ARG buildno=1
USER &user1
...

注:不要使用构建时变量来传递 github 密钥,用户凭据等重要信息。使用 docker history 命令可以查看构建时的变量信息。

FROM

指定所创建镜像的基础镜像。格式为:

  • FROM[AS]
  • FROM: [AS]
  • FROM@[AS]

任何 dockerfile中 第⼀条指令必须为FROM指令。 并且, 如果在同⼀个 dockerfile 中创建多个镜像时, 可以使⽤多个FROM指令(每个镜像⼀次)。

为了保证镜像精简, 可以选⽤体积较⼩的镜像如Alpine或Debian作为基础镜像。 例如:

ARG VERSION=9.3
FROM debian:${VERSION}

LABEL

LABEL指令可以为⽣成的镜像添加元数据标签信息。 这些信息可以⽤来辅助过滤出特定镜像。格式为 LABEL<key>=<value><key>=<value><key>=<value>

LABEL version="1.0.0-rc3"
LABEL author="yeasy@github" date="2020-01-01"
LABEL description="This text illustrates \
that label-values can span multiple lines."

EXPOSE

声明镜像内服务监听的端口。格式为 EXPOSE<port>[<port>/<protocol>...]

EXPOSE 22 80 8443/udp

注意该指令只是起到声明作⽤, 并不会⾃动完成端⼜映射

ENV

指定环境变量, 在镜像⽣成过程中会被后续RUN指令使⽤, 在镜像启动的容器中也会存在。格式为ENV<key><value>ENV<key>=<value>...

ENV APP_VERSION=1.0.0
ENV APP_HOME=/usr/local/app
ENV PATH $PATH:/usr/local/bin

指令指定的环境变量在运⾏时可以被覆盖掉, 如docker run --env <key>=<value> built_image。注意当⼀条ENV指令中同时为多个环境变量赋值并且值也是从环境变量读取时, 会为变量都赋值后再更新。

ENTRYPOINT

指定镜像的默认⼊⼜命令, 该⼊⼜命令会在启动容器时作为根命令执⾏, 所有传⼊值作为该命令的参数。⽀持两种格式:

  • ENTRYPOINT["executable", "param1", "param2"]: exec调⽤执⾏;
  • ENTRYPOINT command param1 param2: shell中执⾏。

此时, CMD指令指定值将作为根命令的参数。每个Dockerfile中只能有⼀个ENTRYPOINT, 当指定多个时, 只有最后⼀个起效。在运⾏时, 可以被 --entrypoint 参数覆盖掉, 如 docker run--entrypoint

VOLUME

创建⼀个数据卷挂载点。格式为 VOLUME["/data"]

运⾏容器时可以从本地主机或其他容器挂载数据卷, ⼀般⽤来存放数据库和需要保持的数据等。

USER

指定运⾏容器时的⽤户名或UID, 后续的RUN等指令也会使⽤指定的⽤户⾝份。格式为 USER daemon

当服务不需要管理员权限时, 可以通过该命令指定运⾏⽤户, 并且可以在Dockerfile中创建所需要的⽤户。 例如:

RUN groupadd -r postgres && useradd --no-log-init -r -g postgres postgres

要临时获取管理员权限可以使⽤gosu命令。

WORKDIR

为后续的RUN、 CMD、 ENTRYPOINT指令配置⼯作⽬录。格式为 WORKDIR/path/to/workdir

可以使⽤多个WORKDIR指令, 后续命令如果参数是相对路径, 则会基于之前命令指定的路径。 例如:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

则最终路径为/a/b/c。

注:为了避免出错, 推荐WORKDIR指令中只使⽤绝对路径。

ONBUILD

指定当基于所⽣成镜像创建⼦镜像时, ⾃动执⾏的操作指令。格式为 ONBUILD [INSTRUCTION]

例如, 使⽤如下的Dockerfile创建⽗镜像ParentImage, 指定 ONBUILD 指令:

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

使⽤ docker build 命令创建⼦镜像 ChildImage 时(FROM ParentImage),会⾸先执⾏ParentImage中配置的ONBUILD指令:

# Dockerfile for ChildImage
FROM ParentImage

等价于在 ChildImage 的 dockerfile 中添加了如下指令:

#Automatically run the following when building ChildImage
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src
...

由于ONBUILD指令是隐式执⾏的, 推荐在使⽤它的镜像标签中进⾏标注, 例如ruby: 2.1-onbuild。

ONBUILD指令在创建专门⽤于⾃动编译、 检查等操作的基础镜像时,⼗分有⽤。

STOPSIGNAL

指定所创建镜像启动的容器接收退出的信号值:

STOPSIGNAL signal

HEALTHCHECK

配置所启动容器如何进⾏健康检查(如何判断健康与否),⾃ docker1.12 开始⽀持。

格式有两种:

  • HEALTHCHECK[OPTIONS]CMD command: 根据所执⾏命令返回是否为0来判断;
  • HEALTHCHECK NONE: 禁⽌基础镜像中的健康检查。

OPTION⽀持如下参数:

  • --interval=DURATION(default: 30s): 过多久检查⼀次;
  • --timeout=DURATION(default: 30s): 每次检查等待结果的超时;
  • --retries=N(default: 3): 如果失败了, 重试⼏次才最终确定失败

SHELL

指定其他命令使⽤ shell 时的默认 shell 类型:

SHELL `["executable", "parameters"]`

默认值为 ["/bin/sh", "-c"]

对于Windows系统,Shell路径中使⽤了“\”作为分隔符, 建议在 dockerfile 开头添加 #escape='来指定转义符。

RUN

运⾏指定命令。格式为

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

注意后者指令会被解析为 JSON 数组, 因此必须⽤双引号。 前者默认将在shell终端中运⾏命令, 即/bin/sh-c; 后者则使⽤exec执⾏, 不会启动shell环境。

指定使⽤其他终端类型可以通过第⼆种⽅式实现, 例如RUN ["/bin/bash", "-c", "echo hello"]

每条RUN指令将在当前镜像基础上执⾏指定命令, 并提交为新的镜像层。 当命令较长时可以使⽤\来换⾏。 例如:

RUN apt-get update \
&& apt-get install -y libsnappy-dev zlib1g-dev libbz2-dev \
&& rm -rf /var/cache/apt \
&& rm -rf /var/lib/apt/lists/*

CMD

CMD 指令⽤来指定启动容器时默认执⾏的命令。

⽀持三种格式:

  • CMD ["executable", "param1", "param2"]: 相当于执⾏ executableparam1 param2, 推荐⽅式;
  • CMD command param1 param2: 在默认的Shell中执⾏, 提供给需要交互的应⽤;
  • CMD ["param1", "param2"]: 提供给ENTRYPOINT的默认参数。

每个 Dockerfile 只能有⼀条CMD命令。 如果指定了多条命令, 只有最后⼀条会被执⾏。如果⽤户启动容器时候⼿动指定了运⾏的命令(作为run命令的参数) , 则会覆盖掉CMD指定的命令。

ADD

添加内容到镜像。格式为 ADD <src> <dest>

该命令将复制指定的 路径下内容到容器中的路径下。其中可以是Dockerfile所在⽬录的⼀个相对路径(⽂件或⽬录);也可以是⼀个URL; 还可以是⼀个tar⽂件(⾃动解压为⽬录)可以是镜像内绝对路径, 或者相对于⼯作⽬录(WORKDIR) 的相对路径。

路径⽀持正则格式, 例如:

ADD *.c /code/

COPY

复制内容到镜像。格式为 COPY <src> <dest>

复制本地主机的 (为Dockerfile所在⽬录的相对路径, ⽂件或⽬录) 下内容到镜像中的。 ⽬标路径不存在时, 会⾃动创建。路径同样⽀持正则格式。

COPY与ADD指令功能类似, 当使⽤本地⽬录为源⽬录时, 推荐使⽤COPY。

创建镜像

创建镜像使用命令 docker [image] build, 格式为 docker build [OPTIONS] PATH | URL| -

该命令将读取指定路径下(包括⼦⽬录) 的Dockerfile, 并将该路径下所有数据作为上下⽂(Context) 发送给Docker服务端。 Docker服务端在校验Dockerfile格式通过后, 逐条执⾏其中定义的指令, 碰到ADD、 COPY和RUN指令会⽣成⼀层新的镜像。 最终如果创建镜像成功, 会返回最终镜像的ID。

docker build 支持以下的选项:





关于父镜像

dockerfile 使用 FROM 指令指定父镜像,一般我们使用系统镜像来作为父镜像,但是我们也可以使用基础镜像(scratch)来作为父镜像:

FROM scratch
ADD binary /
CMD ["/binary"]

docker 中镜像存在继承关系,用一张图来说明:

.docerignore 文件

如同 git 有 .gitignore 文件一样,docker 也有 .dockerignore 文件来让Docker忽略匹配路径或⽂件, 在创建镜像时候不将⽆关数据发送到服务端

*/temp*
*/*/temp*
tmp?
~*
Dockerfile
!README.md

dockerignore⽂件中模式语法⽀持Golang风格的路径正则格式:

  • “*”表⽰任意多个字符;
  • “? ”代表单个字符;
  • “!”表⽰不匹配(即不忽略指定的路径或⽂件) 。

多步骤创建

⾃17.05版本开始, Docker⽀持多步骤镜像创建(Multi-stage build) 特性, 可以精简最终⽣成的镜像⼤⼩。例如我们先指定一个编译的环境镜像进行编译,在指定一个运行的镜像来运行编译的代码。

以 Go 语言为例,创建一个空目录,在目录中创建 Go 代码文件 main.go

package main

import "fmt"

func main() {
fmt.Println("Hello World")
}

编写 dockerfile

FROM golang:1.9 as builder
RUN mkdir -p /go/src/test
WORKDIR /go/src/test
COPY main.go .
RUN CGO_ENABLED=0 GOOS=linux go build -o app . FROM alpine:latest
WORKDIR /root/
COPY --from=builder /go/src/test/app .
CMD ["./app"]

执行创建镜像

# docker build -t xingyys/test -f dockerfile .
Sending build context to Docker daemon 38.91kB
Step 1/9 : FROM golang:1.9 as builder
---> ef89ef5c42a9
...
Successfully built 73b66909a48d
Successfully tagged xingyys/test:latest
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
xingyys/test latest 73b66909a48d 8 minutes ago 7.44MB

使用多步骤发现生成的镜像很精简,当也可以用多个 dockerfile 实现这个功能,但需要两个 dockerfile,维护成本提高了。

dockerfile 要点

  • 编写 dockerfile 存在注意的点,遵守这些点可以生成更精简的镜像:
  • 精简镜像⽤途: 尽量让每个镜像的⽤途都⽐较集中单⼀, 避免构造⼤⽽复杂、 多功能的镜像;
  • 选⽤合适的基础镜像: 容器的核⼼是应⽤。 选择过⼤的⽗镜像(如Ubuntu系统镜像) 会造成最终⽣成应⽤镜像的臃肿, 推荐选⽤瘦⾝过的应⽤镜像(如node: slim) , 或者较为⼩巧的系统镜像(如alpine、 busybox或debian) ;
  • 提供注释和维护者信息: Dockerfile也是⼀种代码, 需要考虑⽅便后续的扩展和他⼈的使⽤;
  • 正确使⽤版本号: 使⽤明确的版本号信息, 如1.0, 2.0, ⽽⾮依赖于默认的latest。 通过版本号可以避免环境不⼀致导致的问题;
  • 减少镜像层数: 如果希望所⽣成镜像的层数尽量少, 则要尽量合并RUN、 ADD和COPY指令。 通常情况下, 多个RUN指令可以合并为⼀条RUN指令;
  • 恰当使⽤多步骤创建(17.05+版本⽀持) : 通过多步骤创建, 可以将编译和运⾏等过程分开, 保证最终⽣成的镜像只包括运⾏应⽤所需要的最⼩化环境。 当然, ⽤户也可以通过分别构造编译镜像和运⾏镜像来达到类似的结果, 但这种⽅式需要维护多个Dockerfile。
  • 使⽤.dockerignore⽂件: 使⽤它可以标记在执⾏docker build时忽略的路径和⽂件, 避免发送不必要的数据内容, 从⽽加快整个镜像创建过程。
  • 及时删除临时⽂件和缓存⽂件: 特别是在执⾏apt-get指令后, /var/cache/apt下⾯会缓存了⼀些安装包;
  • 提⾼⽣成速度: 如合理使⽤cache, 减少内容⽬录下的⽂件, 或使⽤.dockerignore⽂件指定等;
  • 调整合理的指令顺序: 在开启cache的情况下, 内容不变的指令尽量放在前⾯, 这样可以尽量复⽤;
  • 减少外部源的⼲扰: 如果确实要从外部引⼊数据, 需要指定持久的地址, 并带版本信息等, 让他⼈可以复⽤⽽不出错。

docker 实践六:dockerfile 详解的更多相关文章

  1. Docker系列07—Dockerfile 详解

    本文收录在容器技术学习系列文章总目录 1.认识Dockerfile 1.1 镜像的生成途径 基于容器制作  dockerfile,docker build 基于容器制作镜像,已经在上篇Docker系列 ...

  2. Docker 学习7 Dockerfile详解

    一.镜像的生成途径 1.使用当前进程替换上一个进程 exec 2.生成方式 3.dockerfile制作镜像要求 a.要有专有的工作目录. b.要有专门的制作文件,文件名首字母大写 c.如果要打包很多 ...

  3. Docker 学习8 Dockerfile详解2

    一.继续上章节Docker学习7 CMD命令后. 11.ENTRYPOINT a.容器启动后相当于会启动ENTRYPOINT + CMD 命令,CMD相当于参数传给entrypoint的 [root@ ...

  4. Docker入门02——Dockerfile详解

    基本示例 FROM MAINTAINER LABEL RUN ADD COPY CMD ENTRYPOINT ENV EXPOSE VOLUME WORKDIR USER ARG 基本示例 # Thi ...

  5. Dockerfile详解

    Dockerfile详解 利用Dockerfile文件,可以构建docker的image镜像 命令使用 通过-f参数指定Dockerfile路径,进行构建image docker build -f / ...

  6. Dockerfile详解及优化

    Dockerfile详解 0. Dockerfile的作用 docker可以根据Dockerfile中的指令来构建docker镜像.Dockerfile是一个文本文件,其应当包含用户想要构建一个镜像的 ...

  7. 最佳实战Docker持续集成图文详解

    最佳实战Docker持续集成图文详解 这是一种真正的容器级的实现,这个带来的好处,不仅仅是效率的提升,更是一种变革:开发人员第一次真正为自己的代码负责——终于可以跳过运维和测试部门,自主维护运行环境( ...

  8. docker entrypoint入口文件详解

    docker entrypoint入口文件详解 pasting Dockerfile创建自定义Docker镜像以及CMD与ENTRYPOINT指令的比较 [k8s]args指令案例-彻底理解docke ...

  9. 【转】Dockerfile详解

    Dockerfile详解 https://blog.csdn.net/wo18237095579/article/details/80540571 --------------------- 作者:大 ...

  10. Docker Swarm 负载均衡详解 or 模式选择

    Docker Swarm 负载均衡详解 Swarm模式内置DNS组件,可以自动为集群中的每个服务分配DNS记录. Swarm manager使用内部负载均衡,根据服务的DNS名称在集群内的服务之间分发 ...

随机推荐

  1. Java学习个人备忘录之入门基础

    临时配置环境方式:查看path下的环境变量 set path修改path下的环境变量 set path=haha删除path下的环境变量 set path=查看当前java的版本 javac -ver ...

  2. 北漂IT男返乡2年的三线楼市观察(宜昌夷陵篇)-原创

    一直想写点什么,这段时间总算有空,好嘞,正好有兴致来写一写楼市相关的文章以饕读者和粉丝朋友. 宜昌?说宜昌您可能不知道,但是说三峡大坝您就知道了 最近这两年,因为小宝的降临,我多半时间待在老家宜昌陪伴 ...

  3. Flutter: 运行新项目报错

    今天接手了一个客户传过来的Flutter项目,估计是客户直接拷贝过来的,无法直接运行,由于刚接手Flutter, 很多东西还不懂,折腾了一会给弄好了. 1. 提示Dart SDK is not con ...

  4. Flutter -------- 加载本地图片资源和网络图片

    在Flutter加载本地图片资源 在Flutter项目目录下创建文件夹 images ,在文件夹中添加几张图片 指定资源 pubspec.yaml文件中 version: 1.0.0+1 enviro ...

  5. PHP判断文件大小是MB、GB、TB...

    <?php date_default_timezone_set ("PRC" ); function getFilePro($fileName){ if (!file_exi ...

  6. Syntax error: "(" unexpected shell里面的报错解决

    author:headsen  chen date : 2019-08-08  11:11:38 notice : 个人原创 Ubuntu上运行shell脚本总是报下面这个错误,在centos下面或者 ...

  7. Docs-.NET-C#-指南-语言参考-关键字-值类型-:浮点数值类型

    ylbtech-Docs-.NET-C#-指南-语言参考-关键字-值类型-:浮点数值类型 1.返回顶部 1. 浮点数值类型(C# 引用) 2019/10/22 “浮点类型”是“简单类型”的子集,可以使 ...

  8. Typora 精美而强大的Markdown编辑器

    Typora 精美而强大的Markdown编辑器  转 https://www.jianshu.com/p/45e284645d30 Markdown编辑器千千万,可是有颜值.功能强并且免费的,就没有 ...

  9. ubuntu 关于curses头文件问题

    执行编译gcc -o badterm badterm.c -lcurses后报错情报如下:term.h: 没有那个文件或目录curses.h: 没有那个文件或目录很明显,程序找不到term.h和cur ...

  10. Spring cloud微服务安全实战-4-1章节概述

    过渡到复杂的微服务场景下面. 搭建起一个简单的微服务架构,一个网关,一个安全中心,两个微服务,然后会看到如何将安全相关的问题解构出来放在网关上. 然后与OAuth协议整合起来.