Docker 简明教程

Docker - Dockerfile

Dockerfile 是一种文本文档,你可以在其中写下要创建镜像的所有指令。该文件中的第一个条目指定基本镜像,基本镜像是一个预制的镜像,其中包含你的应用程序所需的所有依赖项。然后,你可以向 Dockerfile 发送命令,以安装附加软件、复制文件或运行脚本。其结果是一个 Docker 镜像:一个自给自足的可执行文件,其中包含运行应用程序所需的所有信息。

Dockerfile 是一种颇具吸引力的用于创建和部署应用程序的方式。它们有助于以一种更加轻松的方式和可重复的方式创建环境。Dockerfile 还能自动执行部署流程。

Dockerfile 用于创建根据具体需求单独准备的新自定义镜像。例如,Docker 镜像可以具有特定版本的 Web 服务器,或者例如数据库服务器。

Important Instructions used in Dockerfile

Dockerfile 是一种文本文档,其中包含所有用于构建 Docker 镜像的不同步骤和说明。Dockerfile 中描述的主要元素包括基本镜像、所需依赖项以及在容器中执行应用程序部署的命令。

Dockerfile 的基本指令如下所示 −

FROM

此指令设置用于在新镜像上构建的新镜像的基础镜像。它通常是 Dockerfile 中的第一个指令。

FROM ubuntu:22

RUN

这将是一条指令,它将用于在构建时运行容器内的命令。它通常可以被用于安装应用程序、更新程序库或执行常规设置。

RUN apt-get update && apt-get install -y python3

COPY

此指令将文件和目录从宿主机器复制到容器镜像中。

COPY ./app /app

ADD

它很像 COPY 但功能更加高级,例如自动解压存档并从 URL 中提取文件。

ADD https://example.com/file.tar.gz /app

WORKDIR

此指令设置工作目录,其中 Dockerfile 中的后继指令将被执行。

WORKDIR /app

ENV

此命令中的 ENV 指令定义容器内的环境变量。

ENV FLASK_APP=main.py

EXPOSE

此选项定义要让 Docker 在运行时侦听声明网络端口。

EXPOSE 8000

CMD

定义执行容器的默认设置。Dockerfile 中只可以有一个 CMD 指令。如果列出了多个 CMD,那么只有最后一个 CMD 将生效。

CMD ["python3", "main.py"]

ENTRYPOINT

一条指令,允许配置容器,以便将容器作为可执行文件运行。

ENTRYPOINT ["python3", "main.py"]

LABEL

此命令为镜像提供元信息,比如维护人员的详细信息、版本或说明。

LABEL maintainer="johndoe@example.com"

ARG

此命令定义了一个变量,允许用户在构建时通过 docker build 命令上的“--build-arg”标志传递给构建器。

ARG version=1

VOLUME

它只是创建一个挂载点并为其分配给定的名称,指出它将保存来自本机主机或其他容器的外置挂载卷。

VOLUME /app/data

USER

此指令允许设置用户名(或 UID),还可以可选地设置在运行该镜像时和 Dockerfile 中后续的任何 RUN、CMD 和 ENTRYPOINT 指令时使用的组(或 GID)。

USER johndoe

这些可能是在 Dockerfile 中使用最常见也是最重要的指令。然而,这些指令及其顺序当然会根据要容器化的特定应用程序而异。

Best Practices for Dockerfile

一份编写得当的 Dockerfile 对于所有高效且安全的容器化应用程序都至关重要。Dockerfile 是构建 Docker 镜像的蓝图,其中详细说明了顺畅运行应用程序所需的环境、依赖关系和配置。

通过最佳实践,你可以创建更精简、更快速且更可靠的 Docker 镜像,从而最终实现工作流的自动化,提高应用程序的效率。以下给出了一组 10 个基本的 Dockerfile 最佳实践−

  1. Use Official Base Images − 构建于官方的 Docker Hub 镜像之上。它们通常是最小的,并且维护良好。通常情况下,它们针对安全性和大小进行了优化,为自定义镜像奠定了坚实的基础。

  2. Use multi-stage builds 以便通过放弃不需要的构建工具和依赖关系来缩减最终的镜像大小。通过这种方式,你可以对构建和运行时环境进行分区,以达到最佳效率。

  3. Minimize the Number of Layers − 如前所述,Dockerfile 中的每条指令都会创建一个层。尽可能在一条 RUN 指令中组合任何相互关联的命令。这将有助于减少为任何构建创建的层数,从而使构建更具可缓存性。

  4. Leverage Build Cache − 确保 Dockerfile 中可能更频繁更改的指令(比如 COPY)放置在末尾。这将使在后期进行更改后能够更快速地再次构建。

  5. Install Only Necessary Packages − 在应用程序中仅安装必要的包和依赖关系,以减小镜像大小和潜在的漏洞。

  6. Use '.dockerignore' − 要从构建上下文中排除不必要的文件和目录,请添加一个“.dockerignore”文件。这将加快构建速度,并防止敏感信息泄露到镜像中。

  7. Use Non-Root User − 使用非 root 用户运行容器,以增强安全性。在 Dockerfile 中给特定用户和组提供另一个隔离层始终是个好主意。

  8. Image Scanning − 经常扫描你的 Docker 镜像中的漏洞。有许多工具可以使用,比如 Trivy 和 Clair。随时更新你的基础镜像和依赖关系,以最大程度地减少潜在的风险。

  9. Document your Dockerfile − 为 Dockerfile 添加注释和说明,你以后会感谢自己。这有助于其他人,甚至是以后的你,理解构建过程。

  10. Pin Versions − 固定基础镜像和依赖关系的版本,因为这确保了再现性,并通过更新避免任何意外问题。

现在,你可以通过在 Dockerfile 工作流中创建健壮且高效的容器化应用程序来针对速度、安全性和可维护性优化容器构建。

Dockerfile - Example

我们将编写一个 Dockerfile,用于一个简单的 Flask Web 应用程序,该应用程序提供消息“Hello, World!”。具体来说,我们将展示如何使用上面介绍的几条指令来创建和通过容器运行此应用程序。

Dockerfile Code

# Use the official Python image as a base
FROM python:3.9-slim-buster

# Set environment variables
ENV PYTHONUNBUFFERED 1
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0

# Set the working directory in the container
WORKDIR /app

# Copy the requirements file and install dependencies
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt

# Copy the application code into the container
COPY . /app

# Expose port 5000 to the outside world
EXPOSE 5000

# Run the Flask app when the container launches
CMD ["flask", "run"]

Code Explanation

  1. FROM python:3.9-slim-buster - 这行将基础镜像设置为来自 Docker Hub 的官方 Python 3.9 slim-buster 镜像 - 一个包含必要的 Python 运行时环境的轻量级镜像。

  2. ENV PYTHONUNBUFFERED 1 - 设置环境变量并确保不缓冲输出,这有助于调试。

  3. ENV FLASK_APP=app.py - 这指定了主应用程序文件。

  4. ENV FLASK_RUN_HOST=0.0.0.0 - Flask 应用程序将对 IP 地址 0.0.0.0 可用。

  5. WORKDIR /app - 这行将容器中的工作目录设置为 /app。从此处开始的每个其他命令都将在该目录中工作。

  6. COPY requirements.txt requirements.txt - 这将 requirements.txt 文件从本地机器复制到容器内的 /app 目录。

  7. RUN pip install -r requirements.txt - 这将安装 requirements.txt 文件中列出的 Python 包依赖项。

  8. COPY . /app - 这将将整个当前目录(Dockerfile 和应用程序代码所在的位置)复制到容器内的 /app 目录。

  9. EXPOSE 5000 - 这告诉 Docker 容器在运行时侦听端口 5000。

  10. CMD ['flask', 'run'] - 这是容器启动过程中执行的默认命令。它启动 Flask 开发服务器。

How Does It Work?

您需要生成一个 requirements.txt 文件,其中列出 Flask 应用程序的所有依赖项,例如 Flask。您在与 Flask 应用程序代码(app.py)的同一目录中将此 Dockerfile 保存为 Dockerfile,并且不带文件扩展名。然后,您可以通过执行命令 docker build -t my-flask-app 来创建 Docker 镜像。(将 my-flask-app 替换为您要为镜像指定的名称)。

最后,您可以使用 docker run -p 5000:5000 my-flask-app 来运行容器。这将启动 Flask 应用程序,您可以在 http://localhost:5000/ 中通过浏览器访问它。这样,您的应用程序将运行在可移植和可重现的环境中,可以在不同的环境中轻松部署和管理。

Conclusion

总之,Docker 改变了我们进行应用程序开发、部署和整体管理的方式。通过 Docker 实现容器化,帮助开发者在各种不同的环境中实现更高的可移植性、可扩展性和一致性。简单来说,Dockerfile 是容器化的单元;如果没有 Dockerfile,组件和配置将无从谈起。

我们在本文中学习了如何使用探索的最佳实践和示例使 Dockerfile 有效且安全。优化镜像大小、利用构建缓存并遵循安全准则,以便我们的应用程序在任何 Docker 环境中都能顺畅可靠地运行。之后,请记住,掌握 Dockerfile 是释放 Docker 的全部能力并在单击之间减少数小时例行工作的方法。

FAQ

Q 1. What is a Dockerfile and why do you need it?

Dockerfile 或多或少是一个包含指令的纯文本文件。它提供了 Docker 镜像的构建蓝图,即容器的蓝图。Dockerfile 详细说明了要安装的所有内容,从操作系统基础到其他每个包依赖项,甚至指定容器启动时需要运行的命令。

Dockerfile 将使镜像创建过程变得高效,并且能够确保在多种环境中的一致性和可复制性。

Q 2. What are some key instructions in a Dockerfile?

其中一些必要的指令有:FROM - 它定义了从中开始构建的基础镜像;RUN - 它执行包含在镜像构建过程中作为一部分的命令,例如软件安装;COPY - 它将文件或目录从本地机器复制到镜像;EXPOSE - 用于声明容器内应用程序将使用的端口;最后 CMD,它设置了容器启动时要运行的默认命令。

Q 3. How are COPY and ADD different in a Dockerfile?

ADD 命令会在 Dockerfile 中将文件添加到您的镜像中。但是,ADD 和 COPY 之间存在重要的差异。COPY 是以透明且可预测的方式从本地机器将文件或目录传输到镜像的首选方法。

ADD 的其他一些功能是能够从远程 URL 提取文件,甚至可以自动提取压缩档案,就像它对 .tar 或 .zip 文件所做的那样。这使得 ADD 看起来更加灵活,但它在提取方面的古怪行为通常导致 COPY 由于简单而更加受欢迎。

请注意,如果您必须下载远程文件,则通常应该使用 curl 或 wget 等下载工具将它们分隔成不同的 RUN 指令,以减少不必要的图像层。

Q 4. How can the Dockerfile be optimized for small images?

较小的图像会有所帮助,因为它们占用的空间更小,传输速度更快,启动也很快捷。为了最大程度地缩小图像尺寸,请使用一个最小的基础镜像,将多个 RUN 命令链接在一起以减少中间层的数量、运用多阶段构建、丢弃不需要的工件,以及清理在构建过程中使用的中间文件和软件包。

Q 5. What is a Multi-stage build in Docker?

多阶段构建是指可以在一个 Dockerfile 中使用多个 FROM 指令进行指定。其核心思想是在一个阶段内构建应用程序,其中包含进行编译所需的全部工具和依赖关系;在下一个阶段,只将需要带入更小、可投入生产的镜像的最终工件。这样,最终的图像更小,因为构建环境并不是它的组成部分,部署也更有效率和安全。