使用Dockerfile构建Docker镜像

Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。

我的新书《LangChain编程从入门到实践》 已经开售!推荐正在学习AI应用开发的朋友购买阅读!
LangChain编程从入门到实践

Dockerfile 是什么

  • Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等),镜像不包含任何动态数据,其内容在构建之后也不会被改变。
  • 镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    FROM python:3.6-alpine

    WORKDIR /app

    # Install dependencies.
    ADD requirements.txt /app
    RUN cd /app && \
    pip install -r requirements.txt

    # Add actual source code.
    ADD blockchain.py /app

    EXPOSE 5000

    CMD ["python", "blockchain.py", "--port", "5000"]

    Dockerfile语法说明

    FROM: 指定基础镜像。

  • 定制镜像的时候都是以一个镜像为基础,在这个基础上面进行定制。FROM在Dockerfile中是必须的指令,而且必须是第一条指令。
  • 在Docker Hub上有非常多的官方镜像,比如服务类(nginx/redis)、语言类(node/openjdk/python)、操作系统类(ubuntu/debian/centos)等,我们可以直接拿来使用。
  • 除了选择现有的镜像作为基础镜像外,Docker还存在一个特殊的镜像,名为scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。如果以 scratch 为基础镜像的话,意味着不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。

    WORKDIR: 指定工作目录

  • 格式为 WORKDIR <工作目录路径>。
  • 使用 WORKDIR 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,WORKDIR 会帮你建立目录。

    COPY: 复制文件

  • COPY 指令有两种格式,一种类似于命令行,一种类似于函数调用:
    • COPY <源路径>… <目标路径>
    • COPY [“<源路径1>”,… “<目标路径>”]
  • COPY 指令将从构建上下文目录中<源路径>的文件复制到新的一层的镜像内的<目标路径>位置。

    ADD: 更高级的复制文件

  • ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。如果 <源路径> 为一个 tar 压缩文件的话,ADD 指令将会自动解压缩这个压缩文件到 <目标路径> 去,而使用 COPY 还需要额外的一层 RUN 指令进行解压缩。
  • 但在某些情况下,如果我们真的是希望复制个压缩文件进去,而不解压缩,这时就不可以使用 ADD 命令了。在 Docker 官方的 Dockerfile 最佳实践文档中要求,尽可能的使用 COPY,因为 COPY 的语义很明确,就是复制文件而已,而 ADD 则包含了更复杂的功能,其行为也不一定很清晰。最适合使用 ADD 的场合,就是所提及的需要自动解压缩的场合。
  • 另外需要注意的是,ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。因此在 COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD。

    RUN: 执行命令

  • RUN 指令是用来执行命令行命令的,由于命令行的强大能力,RUN 指令在定制镜像时是最常用的指令之一。其格式有两种:
    • shell格式: RUN 命令,就像直接在命令行中输入的命令一样,如 RUN echo 'hello, world!' > hello.txt
    • exec格式:RUN [‘可执行文件’, ‘参数1’, ‘参数2’],类似于函数调用,将可执行文件和参数分开,如 RUN [ "sh", "-c", "echo $HOME" ]
  • Dockerfile 中每一个指令都会建立一层,RUN也不例外。每一个RUN的行为:新建立一层,在其上执行这些命令,执行结束后,commit这一层的修改,构成新的镜像。所以我们在使用的时候尽可能将指令进行整合(可以使用&&将各个所需命令串联起来)。

    EXPOSE: 声明端口

  • 格式为 EXPOSE <端口1> [<端口2>...]
  • EXPOSE指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在Dockerfile中写入这样的声明有两个好处:
    • 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;
    • 在运行时使用随机端口映射时,也就是docker run -P时,会自动随机映射EXPOSE的端口。
  • 要将EXPOSE和在运行时使用-p <宿主端口>:<容器端口>区分开来。后者是将容器的对应端口服务公开给外界访问,而EXPOSE仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。

    CMD: 容器启动命令

  • CMD 指令的格式和 RUN 相似,也是两种格式:
    • shell 格式:CMD <命令>
    • exec 格式:CMD ["可执行文件", "参数1", "参数2"...]
  • 在指定了 ENTRYPOINT 指令后,用 CMD 指定具体的参数。参数列表格式:CMD [ “参数1”, “参数2” … ]

    ENV: 设置环境变量

  • 格式有两种:
    • ENV <key> <value>
    • ENV <key1>=<value1> <key2>=<value2>...
  • 这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。
    1
    2
    ENV VERSION=1.0 DEBUG=on \
    NAME="Happy Feet"
  • 这个例子中演示了如何换行,以及对含有空格的值用双引号括起来的办法,这和 Shell 下的行为是一致的。

    CI/CD系统

    CI/CD与Docker集成后,一次应用从源码提交到线上部署的自动化流程:
    Snipaste_2020-01-10_09-58-31.png
    开发人员提交代码后,代码仓库(git)里的钩子(hook)触发CI系统的应用构建测试和发布流程,将通过测试的应用打包成Docker镜像上传到Docker镜像仓库中,调用管理节点上的应用部署接口,发起部署,整个过程无须人工干预,自动完成创建、打包和部署到计算节点上。

    参考链接

  • 使用 Dockerfile 定制镜像

使用Dockerfile构建Docker镜像

https://liduos.com/write-dockerfile.html

作者

莫尔索

发布于

2019-12-20

更新于

2024-05-19

许可协议

评论