创建 Docker 镜像

DockerDockerBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

本全面指南涵盖了从零创建 Docker 镜像的基本概念和最佳实践。你将学习如何构建 Docker 镜像、优化其大小、管理版本控制和标签,以及处理 Docker 镜像的整个生命周期。无论你是 Docker 新手还是有经验的用户,本教程都将为你提供掌握 Docker 镜像创建艺术所需的知识和工具。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL docker(("Docker")) -.-> docker/DockerfileGroup(["Dockerfile"]) docker(("Docker")) -.-> docker/ImageOperationsGroup(["Image Operations"]) docker/ImageOperationsGroup -.-> docker/pull("Pull Image from Repository") docker/ImageOperationsGroup -.-> docker/tag("Tag an Image") docker/ImageOperationsGroup -.-> docker/push("Push Image to Repository") docker/ImageOperationsGroup -.-> docker/rmi("Remove Image") docker/ImageOperationsGroup -.-> docker/images("List Images") docker/DockerfileGroup -.-> docker/build("Build Image from Dockerfile") subgraph Lab Skills docker/pull -.-> lab-391811{{"创建 Docker 镜像"}} docker/tag -.-> lab-391811{{"创建 Docker 镜像"}} docker/push -.-> lab-391811{{"创建 Docker 镜像"}} docker/rmi -.-> lab-391811{{"创建 Docker 镜像"}} docker/images -.-> lab-391811{{"创建 Docker 镜像"}} docker/build -.-> lab-391811{{"创建 Docker 镜像"}} end

Docker 镜像简介

Docker 镜像是 Docker 容器的基础,而 Docker 容器是 Docker 生态系统中的基本部署单元。Docker 镜像是一个只读模板,其中包含一组用于创建 Docker 容器的指令。这些指令包括应用程序代码、运行时环境、系统工具、库以及运行该应用程序所需的任何其他依赖项。

Docker 镜像是使用一组称为 Dockerfile 的指令构建的。Dockerfile 是一个文本文件,其中包含用户组装 Docker 镜像所需的所有命令。当你构建 Docker 镜像时,Docker 会从 Dockerfile 中读取指令,并逐层创建镜像。

Docker 镜像存储在 Docker 注册表中,Docker 注册表是 Docker 镜像的集中式存储库。最流行的 Docker 注册表是 Docker Hub,它是一个公共注册表,用户可以在其中共享和下载 Docker 镜像。

graph TD A[Dockerfile] --> B[Docker Image] B --> C[Docker Container] C --> D[Application]

Docker 镜像可用于创建同一应用程序的多个实例,确保在不同环境中进行一致且可靠的部署。它们还提供了一种打包和分发应用程序的方式,使项目的共享和协作变得更加容易。

命令 描述
docker build 从 Dockerfile 构建 Docker 镜像
docker pull 从注册表拉取 Docker 镜像
docker push 将 Docker 镜像推送到注册表
docker run 从 Docker 镜像运行 Docker 容器

在以下部分中,我们将更深入地探讨从零开始构建 Docker 镜像的过程、管理镜像层和缓存、优化镜像大小以及 Docker 镜像创建的最佳实践。

从零开始构建 Docker 镜像

从零开始构建 Docker 镜像需要创建一个 Dockerfile,并使用 docker build 命令来创建镜像。以下是关于如何从零开始构建 Docker 镜像的分步指南:

创建 Dockerfile

Dockerfile 是一个文本文件,其中包含构建 Docker 镜像的指令。以下是一个 Dockerfile 示例:

## 使用最新的 Ubuntu 基础镜像
FROM ubuntu:latest

## 设置工作目录
WORKDIR /app

## 复制应用程序代码
COPY. /app

## 安装所需的依赖项
RUN apt-get update && apt-get install -y \
  python3 \
  python3-pip

## 安装应用程序依赖项
RUN pip3 install -r requirements.txt

## 暴露应用程序端口
EXPOSE 8080

## 设置运行应用程序的命令
CMD ["python3", "app.py"]

此 Dockerfile 使用最新的 Ubuntu 基础镜像,设置工作目录,复制应用程序代码,安装所需的依赖项,暴露应用程序端口,并设置运行应用程序的命令。

构建 Docker 镜像

要构建 Docker 镜像,请在与 Dockerfile 相同的目录中运行以下命令:

docker build -t my-app.

此命令使用当前目录中的 Dockerfile 构建标签为 my-app 的 Docker 镜像。

graph TD A[Dockerfile] --> B[docker build] B --> C[Docker Image]

检查 Docker 镜像

构建 Docker 镜像后,你可以使用以下命令检查它:

## 列出所有 Docker 镜像
docker images

## 检查 Docker 镜像的详细信息
docker inspect my-app

docker images 命令列出系统上的所有 Docker 镜像,docker inspect 命令提供有关特定 Docker 镜像的详细信息。

通过从零开始构建 Docker 镜像,你可以完全控制镜像的内容,确保你的应用程序及其依赖项在不同环境中正确且一致地打包。

使用 Docker 镜像层与缓存

Docker 镜像是分层构建的,Dockerfile 中的每一行都代表一个新层。这些层会被 Docker 缓存,这可以显著加快构建过程。

理解 Docker 镜像层

当你构建 Docker 镜像时,Dockerfile 中的每条指令都会创建一个新层。这些层相互堆叠,形成最终的镜像。例如,上一节中的 Dockerfile 会创建以下几层:

graph TD A[FROM ubuntu:latest] --> B[WORKDIR /app] B --> C[COPY. /app] C --> D[RUN apt-get update && apt-get install -y...] D --> E[RUN pip3 install -r requirements.txt] E --> F[EXPOSE 8080] F --> G[CMD ["python3", "app.py"]]

利用 Docker 镜像缓存

Docker 会缓存镜像的层,所以如果某一层没有变化,Docker 可以重用缓存的版本而不是重新构建它。这可以显著加快构建过程,尤其是对于大型镜像。

为了利用 Docker 的缓存,重要的是将 Dockerfile 中的指令按变化可能性从低到高排序。这可确保在构建过程中尽可能多地重用缓存层。

以下是一个利用缓存的 Dockerfile 示例:

## 使用最新的 Ubuntu 基础镜像
FROM ubuntu:latest

## 设置工作目录
WORKDIR /app

## 复制应用程序代码
COPY. /app

## 安装所需的依赖项
RUN apt-get update && apt-get install -y \
  python3 \
  python3-pip

## 安装应用程序依赖项
RUN pip3 install -r requirements.txt

## 暴露应用程序端口
EXPOSE 8080

## 设置运行应用程序的命令
CMD ["python3", "app.py"]

在这个示例中,COPY 指令放在安装依赖项的 RUN 指令之前。这确保了如果应用程序代码没有变化,缓存层可以被重用,从而加快构建过程。

通过理解 Docker 镜像层和缓存的工作原理,你可以优化构建过程,并确保你的 Docker 镜像高效且一致地构建。

优化 Docker 镜像大小

保持 Docker 镜像体积小巧很重要,原因有多个,包括更快的下载速度、减少存储需求以及提升性能。以下是一些可用于优化 Docker 镜像大小的技巧:

使用更小的基础镜像

你为 Docker 镜像选择的基础镜像会对最终镜像大小产生重大影响。选择尽可能小的基础镜像,例如 alpinescratch 镜像,它们比传统的 ubuntucentos 镜像小得多。

尽量减少层数

Dockerfile 中的每条指令都会在镜像中创建一个新层。层数越多,最终镜像的大小就会越大。尽可能尝试将多条指令合并到单个层中。

使用多阶段构建

多阶段构建允许你在 Dockerfile 中使用多个 FROM 语句,每个语句使用不同的基础镜像。这对于构建需要多个依赖项的复杂应用程序很有用,同时能保持最终镜像体积小巧。

以下是一个多阶段 Dockerfile 的示例:

## 构建阶段
FROM golang:1.16 AS builder
WORKDIR /app
COPY..
RUN go build -o myapp

## 最终阶段
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/myapp.
CMD ["./myapp"]

在此示例中,第一阶段使用 golang:1.16 镜像来构建应用程序,而最终阶段使用小得多的 alpine:latest 镜像来运行应用程序。

删除不必要的软件包

确保只安装应用程序运行所需的软件包和依赖项。删除任何不必要的软件包或工具以减小镜像大小。

使用.dockerignore

.dockerignore 文件允许你从 Docker 构建上下文排除文件和目录,这可以显著减小最终镜像的大小。

通过遵循这些技巧,你可以优化 Docker 镜像的大小,使其更高效且更易于管理。

Docker 镜像的版本控制与标记

对 Docker 镜像进行版本控制和标记是管理基于 Docker 的应用程序的一个重要方面。恰当的版本控制和标记有助于你跟踪更改、回滚到先前版本,并确保在不同环境中的一致性。

标记 Docker 镜像

当你构建一个 Docker 镜像时,可以为其分配一个标记。标记是一个标签,你可以用它来标识镜像的特定版本。标记可以是任何字符串,但通常使用语义化版本控制(例如 v1.0.0v1.1.2v2.0.0-beta)。

以下是如何构建并标记一个 Docker 镜像的示例:

docker build -t my-app:v1.0.0.

此命令构建一个标记为 v1.0.0 的 Docker 镜像。

对 Docker 镜像进行版本控制

对你的 Docker 镜像进行版本控制对于跟踪更改以及确保使用正确版本的镜像部署应用程序很重要。你可以使用几种策略来对 Docker 镜像进行版本控制:

  1. 语义化版本控制:使用遵循语义化版本控制标准的版本号(例如 v1.2.3)。
  2. 基于日期的版本控制:使用包含镜像构建日期的版本号(例如 2023-04-15)。
  3. 基于 Git 的版本控制:使用 Git 提交哈希作为版本号(例如 abcd1234)。

无论你选择哪种版本控制策略,保持一致性并记录你的版本控制方法都很重要。

推送和拉取 Docker 镜像

一旦你构建并标记了 Docker 镜像,就可以将它们推送到 Docker 注册表,如 Docker Hub 或私有注册表。然后,你可以从注册表中拉取镜像并使用它们来部署你的应用程序。

以下是如何将 Docker 镜像推送到 Docker Hub 的示例:

docker push my-app:v1.0.0

以下是如何从 Docker Hub 拉取 Docker 镜像的示例:

docker pull my-app:v1.0.0

通过对你的 Docker 镜像进行版本控制和标记,你可以确保你的应用程序得到一致的部署,并且可以轻松跟踪和管理基于 Docker 的基础设施的更改。

推送和拉取 Docker 镜像

一旦你构建好了 Docker 镜像,就可以将它们推送到 Docker 注册表(如 Docker Hub 或私有注册表),然后从注册表中拉取它们来部署你的应用程序。

推送 Docker 镜像

要将 Docker 镜像推送到注册表,你首先需要向注册表进行认证。如果你使用的是 Docker Hub,可以使用 docker login 命令登录:

docker login

这将提示你输入 Docker Hub 用户名和密码。

登录后,你可以使用 docker push 命令将 Docker 镜像推送到注册表:

docker push my-app:v1.0.0

此命令会将 my-app:v1.0.0 镜像推送到 Docker 注册表。

拉取 Docker 镜像

要从注册表拉取 Docker 镜像,可以使用 docker pull 命令:

docker pull my-app:v1.0.0

此命令会从 Docker 注册表拉取 my-app:v1.0.0 镜像并存储在你的本地机器上。

graph TD A[Docker Image] --> B[Docker Registry] B --> C[Docker Image] C --> D[Docker Container]

你也可以通过在 docker pull 命令中指定注册表 URL 来从私有注册表拉取镜像:

docker pull myregistry.example.com/my-app:v1.0.0

此命令会从 myregistry.example.com 注册表拉取 my-app:v1.0.0 镜像。

通过推送和拉取 Docker 镜像,你可以轻松地在不同环境和团队之间共享和分发你的应用程序,确保一致且可靠的部署。

创建 Docker 镜像的最佳实践

创建 Docker 镜像可能是一个复杂的过程,但通过遵循最佳实践,你可以确保你的镜像高效、安全且易于维护。以下是一些需要考虑的最佳实践:

使用最小化基础镜像

如前所述,使用最小化基础镜像,例如 alpinescratch,可以显著减小 Docker 镜像的大小。这不仅节省磁盘空间和带宽,还能减少攻击面以及潜在漏洞的数量。

优化 Dockerfile 结构

组织你的 Dockerfile 指令,以利用 Docker 的缓存机制。将相关指令分组,并将最不常更改的指令放在 Dockerfile 的顶部。

利用多阶段构建

多阶段构建允许你分离构建和运行时环境,从而生成更小、更安全的镜像。这对于像 Go 或 C++ 这样的编译型语言特别有用,在这些语言中,你可以在一个阶段构建应用程序,然后将编译后的二进制文件复制到更小的运行时镜像中。

使用.dockerignore

.dockerignore 文件允许你从 Docker 构建上下文排除文件和目录,从而减小构建上下文的大小并加快构建过程。

扫描漏洞

使用 trivysnyk 等工具扫描你的 Docker 镜像,查找已知的漏洞和安全问题。这可以帮助你在部署应用程序之前识别并解决潜在的安全风险。

实施安全实践

确保你的 Dockerfile 遵循安全实践,例如:

  • 以非 root 用户身份运行进程
  • 避免对基础镜像使用 latest 标签
  • 使你的基础镜像保持最新的安全补丁

记录并自动化

记录你的 Docker 镜像创建过程,包括 Dockerfile、构建脚本以及任何其他相关信息。使用 Jenkins、CircleCI 或 GitHub Actions 等工具自动化构建和部署过程,以确保一致性和可靠性。

通过遵循这些最佳实践,你可以创建高效、安全且易于维护的 Docker 镜像,为基于 Docker 的应用程序奠定坚实的基础。

管理 Docker 镜像生命周期

管理 Docker 镜像的生命周期是维护一个健康且高效的基于 Docker 的基础设施的重要方面。这包括诸如镜像版本控制、清理旧镜像以及管理镜像安全更新等任务。

版本控制与标记

如前所述,对你的 Docker 镜像进行版本控制和标记对于跟踪更改以及确保一致的部署至关重要。建立一个清晰的版本控制策略,比如语义化版本控制或基于日期的版本控制,并在你的所有 Docker 镜像中始终如一地应用它。

清理旧镜像

随着时间的推移,你的 Docker 镜像仓库可能会积累大量旧的和未使用的镜像,占用宝贵的存储空间。定期清理这些旧镜像以释放资源,并维护一个精简高效的镜像仓库。

你可以使用 docker image prune 命令来移除未使用的 Docker 镜像:

## 移除所有未使用的镜像
docker image prune -a

## 移除超过 30 天的镜像
docker image prune -a --filter "until=720h"

管理安全更新

与任何其他软件一样,Docker 基础镜像可能存在需要解决的安全漏洞。定期监控安全更新,并重新构建你的 Docker 镜像以纳入最新的安全补丁。

你可以使用 trivysnyk 等工具来扫描你的 Docker 镜像,查找已知漏洞并确定哪些镜像需要更新。

## 扫描 Docker 镜像中的漏洞
trivy image my-app:v1.0.0

通过管理你的 Docker 镜像的生命周期,你可以确保基于 Docker 的应用程序安全、最新且高效。

总结

在本教程结束时,你将对 Docker 镜像创建有深入的理解,从从头开始构建镜像到管理它们的生命周期。你将能够创建高效、安全且易于维护的 Docker 镜像,这些镜像将为你基于 Docker 的应用程序奠定坚实的基础。这些知识将使你能够简化基于 Docker 的部署,并确保一致且可靠的应用程序交付。