Docker 镜像克隆教程:一步一步教你复制 Docker 容器镜像

DockerDockerBeginner
立即练习

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

简介

本教程将指导你完成 Docker 容器镜像的克隆过程。Docker 镜像是一种打包模板,其中包含运行应用程序所需的一切,克隆允许你创建可以自定义的副本。在本指南结束时,你将了解如何克隆 Docker 镜像、修改它,并将其共享以进行部署。

了解 Docker 并验证你的环境

在开始克隆 Docker 镜像之前,了解 Docker 是什么以及验证我们的环境是否正确设置非常重要。

什么是 Docker?

Docker 是一个使用容器来开发、部署和运行应用程序的平台。容器将应用程序与其所有依赖项打包在一起,确保它在不同的环境中一致地工作。这使得 Docker 对于开发和部署工作流程特别有用。

验证 Docker 安装

首先,让我们确保 Docker 已正确安装在我们的系统上。打开一个终端窗口并运行:

docker --version

你应该看到类似如下的输出:

Docker version 20.10.21, build baeda1f

接下来,检查 Docker 服务是否正在运行:

sudo systemctl status docker

输出应该表明 Docker 处于活动状态(正在运行)。如果它没有运行,你可以使用以下命令启动它:

sudo systemctl start docker

测试 Docker 功能

让我们运行一个简单的测试命令来验证 Docker 是否正常工作:

docker run hello-world

此命令下载并运行 hello-world 镜像,该镜像打印确认消息并退出。你应该看到类似如下的输出:

Hello from Docker!
This message shows that your installation appears to be working correctly.

列出 Docker 镜像

要查看你的系统上当前可用的 Docker 镜像,请运行:

docker images

此命令列出当前存储在本地的所有 Docker 镜像。输出显示镜像仓库、标签、镜像 ID、创建日期和大小。

现在我们已经确认 Docker 正常工作,我们已准备好在下一步开始使用 Docker 镜像。

拉取并运行 Docker 镜像

在这一步中,我们将从 Docker Hub 拉取一个 Docker 镜像,并在我们的本地系统上运行它。这是克隆 Docker 镜像过程中的第一步。

什么是 Docker Hub?

Docker Hub 是一个基于云的注册表服务,用户可以在其中查找和共享容器镜像。它包含由软件供应商维护的许多官方镜像以及社区贡献的镜像。

从 Docker Hub 拉取镜像

让我们从 Docker Hub 拉取官方的 Nginx Web 服务器镜像。Nginx 是一个流行的 Web 服务器,我们将在本教程中使用它作为示例。

运行以下命令以下载 Nginx 镜像:

docker pull nginx:latest

此命令下载最新版本的 Nginx 镜像。你应该看到显示下载进度的输出:

latest: Pulling from library/nginx
a2abf6c4d29d: Pull complete
a9edb18cadd1: Pull complete
589b7251471a: Pull complete
186b1aaa4aa6: Pull complete
b4df32aa5a72: Pull complete
a0bcbecc962e: Pull complete
Digest: sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

验证已下载的镜像

要确认镜像已成功下载,请再次列出你的 Docker 镜像:

docker images

你现在应该在列表中看到 Nginx 镜像:

REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
nginx        latest    605c77e624dd   2 weeks ago    142MB

运行 Nginx Docker 容器

现在让我们运行一个基于我们刚刚拉取的 Nginx 镜像的容器:

docker run --name my-nginx -d -p 8080:80 nginx

此命令执行以下操作:

  • --name my-nginx:将我们的容器命名为 "my-nginx"
  • -d:在分离模式(后台)运行容器
  • -p 8080:80:将我们主机上的端口 8080 映射到容器中的端口 80
  • nginx:使用我们之前拉取的 Nginx 镜像

你应该看到一个长字符串输出,这是容器 ID。

验证正在运行的容器

要检查容器是否正在运行:

docker ps

你应该看到类似如下的输出:

CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                  NAMES
f8d3e9c5b9a7   nginx     "/docker-entrypoint.…"   30 seconds ago   Up 29 seconds   0.0.0.0:8080->80/tcp   my-nginx

你现在可以通过打开 Web 浏览器并导航到 http://localhost:8080 或使用 curl 来访问 Nginx 默认页面:

curl http://localhost:8080

你应该看到 Nginx 欢迎页面的 HTML 内容。

现在我们已经成功拉取并运行了 Docker 镜像,我们已准备好在下一步中基于它创建我们自己的自定义镜像。

创建自定义 Docker 镜像

现在我们有了一个正在运行的 Nginx 容器,我们将通过修改它来创建一个自定义镜像。这是克隆过程的核心。我们将:

  1. 对正在运行的容器进行更改
  2. 从这些更改中创建一个新镜像
  3. 运行一个基于我们新镜像的容器

了解 Docker 镜像创建

Docker 镜像可以通过两种方式创建:

  1. 使用 Dockerfile(推荐用于生产环境的方法)
  2. 通过提交对正在运行的容器所做的更改(适用于探索和实验)

在本教程中,我们将使用第二种方法,因为它更直接地理解克隆过程。

修改正在运行的容器

首先,让我们创建一个自定义 HTML 文件来替换默认的 Nginx 欢迎页面。我们需要进入正在运行的容器并修改其文件。

使用以下命令在正在运行的容器内执行一个 shell:

docker exec -it my-nginx bash

这将在容器内打开一个交互式 bash shell。现在,让我们创建一个自定义 HTML 文件:

echo "<html><body><h1>My Custom Docker Image</h1><p>This is a custom Nginx image created in the LabEx tutorial.</p></body></html>" > /usr/share/nginx/html/index.html

你可以通过检查文件的内容来验证更改:

cat /usr/share/nginx/html/index.html

现在退出容器 shell:

exit

测试更改

让我们测试一下我们的更改是否已应用,方法是再次访问 Nginx 服务器:

curl http://localhost:8080

你现在应该看到我们的自定义 HTML 内容,而不是默认的 Nginx 欢迎页面。

从修改后的容器创建新镜像

现在我们已经修改了容器,我们将创建一个包含这些更改的新镜像。这是使用 docker commit 命令完成的:

docker commit my-nginx my-custom-nginx:v1

此命令基于 my-nginx 容器的当前状态,创建一个名为 my-custom-nginx 且标签为 v1 的新镜像。

验证新镜像

让我们验证一下我们的新镜像是否已创建:

docker images

你应该在列表中看到你的新镜像:

REPOSITORY        TAG       IMAGE ID       CREATED          SIZE
my-custom-nginx   v1        a1b2c3d4e5f6   10 seconds ago   142MB
nginx             latest    605c77e624dd   2 weeks ago      142MB

从新镜像运行容器

现在,让我们停止并删除原始容器,然后基于我们的自定义镜像运行一个新容器:

docker stop my-nginx
docker rm my-nginx
docker run --name my-custom-container -d -p 8081:80 my-custom-nginx:v1

这些命令:

  1. 停止原始容器
  2. 删除原始容器
  3. 基于我们的自定义镜像创建一个新容器,映射到端口 8081

测试新容器

让我们验证一下我们的新容器是否正在正确运行:

docker ps

你应该在列表中看到你的新容器:

CONTAINER ID   IMAGE                COMMAND                  CREATED          STATUS          PORTS                  NAMES
g9h8i7j6k5l4   my-custom-nginx:v1   "/docker-entrypoint.…"   10 seconds ago   Up 9 seconds    0.0.0.0:8081->80/tcp   my-custom-container

现在,访问新端口上的 Nginx 服务器:

curl http://localhost:8081

你应该看到相同的自定义 HTML 内容,确认我们的新镜像包含我们所做的更改。

恭喜你!你已经成功克隆并自定义了一个 Docker 镜像。在下一步中,我们将学习如何共享这个自定义镜像。

标记和共享你的 Docker 镜像

现在我们已经创建了一个自定义 Docker 镜像,我们将学习如何正确地标记它并准备共享。在实际场景中,你将把镜像推送到像 Docker Hub 这样的注册表,但在本教程中,我们将专注于准备步骤。

了解 Docker 镜像标签

Docker 镜像通过它们的仓库名称和标签来标识。标签有助于镜像的版本控制和组织。默认标签是 latest,但使用有意义的版本标签是一个好习惯。

为你的镜像添加更多标签

让我们为我们的自定义镜像添加更多标签:

docker tag my-custom-nginx:v1 my-custom-nginx:latest
docker tag my-custom-nginx:v1 my-custom-nginx:stable

这些命令为我们的镜像创建了两个额外的标签:lateststable。实际的镜像数据在所有三个标签之间共享,因此此操作非常有效。

验证标签

让我们再次检查我们的镜像:

docker images

你现在应该看到 my-custom-nginx 的多个条目:

REPOSITORY        TAG       IMAGE ID       CREATED          SIZE
my-custom-nginx   v1        a1b2c3d4e5f6   10 minutes ago   142MB
my-custom-nginx   latest    a1b2c3d4e5f6   10 minutes ago   142MB
my-custom-nginx   stable    a1b2c3d4e5f6   10 minutes ago   142MB
nginx             latest    605c77e624dd   2 weeks ago      142MB

请注意,所有 my-custom-nginx 镜像都具有相同的 Image ID,这表明它们是具有不同标签的同一镜像。

准备镜像分发

在实际场景中,你将把你的镜像推送到像 Docker Hub 这样的注册表。为此,你需要:

  1. 在 Docker Hub 上创建一个帐户
  2. 从你的终端登录到 Docker Hub
  3. 使用你的 Docker Hub 用户名标记你的镜像
  4. 推送镜像

为了演示目的,让我们假设你的 Docker Hub 用户名是 yourusername。以下是你准备推送镜像的方式:

docker tag my-custom-nginx:v1 yourusername/my-custom-nginx:v1

要推送镜像(在实际场景中),你将使用:

## 这仅用于演示 - 我们实际上不会推送
## docker push yourusername/my-custom-nginx:v1

将 Docker 镜像保存到文件

除了推送到注册表之外,你还可以将 Docker 镜像保存到文件以进行手动传输:

docker save -o my-custom-nginx.tar my-custom-nginx:v1

此命令将镜像保存到名为 my-custom-nginx.tar 的 tarball 文件中。你可以验证文件是否已创建:

ls -lh my-custom-nginx.tar

你应该看到类似如下的输出:

-rw------- 1 labex labex 142M Nov 10 12:34 my-custom-nginx.tar

从文件加载镜像

要从另一台机器上的 tarball 加载镜像(或在删除镜像后在同一台机器上),你将使用:

## 我们实际上不会将此命令作为教程的一部分运行
## docker load -i my-custom-nginx.tar

导出容器文档

为了帮助其他人理解你的自定义镜像,最好记录你所做的更改。让我们创建一个简单的文档文件:

cat > my-custom-nginx-doc.txt << EOF
## My Custom Nginx Image

This is a custom Nginx image created by cloning the official Nginx image.

### Changes Made
- Replaced the default welcome page with a custom HTML page

### How to Run
docker run --name my-custom-container -d -p 8080:80 my-custom-nginx:v1

### Version History
- v1: Initial custom version with modified welcome page
EOF

你现在有了一个关于你的自定义镜像的文档文件。

恭喜你!你已经学会了如何标记你的 Docker 镜像并准备共享。在下一步中,我们将介绍一些最佳实践并清理我们的环境。

最佳实践和清理

在最后一步中,我们将介绍一些使用 Docker 镜像的最佳实践,并清理我们的环境。

Docker 镜像的最佳实践

1. 使用特定标签

始终使用特定的版本标签,而不是依赖于 latest 标签。这确保了你部署的一致性。

## 更好的方法
docker pull nginx:1.23.2

## 较不可预测的方法
docker pull nginx:latest

2. 保持镜像小巧

较小的镜像下载速度更快,并且占用更少的存储空间。尽可能考虑使用基于 alpine 的镜像:

## 让我们看看大小差异
docker pull nginx:alpine
docker images | grep nginx

你可能会看到如下输出:

nginx         alpine    2bc7edbc3cf2   2 weeks ago    40.7MB
nginx         latest    605c77e624dd   2 weeks ago    142MB

alpine 版本明显更小!

3. 使用多阶段构建

使用 Dockerfile 创建镜像时,使用多阶段构建以保持最终镜像小巧。这是一个简单的例子(你不需要运行它):

## Build stage
FROM golang:1.17 AS builder
WORKDIR /app
COPY . .
RUN go build -o app

## Final stage
FROM alpine:3.15
COPY --from=builder /app/app /app
CMD ["/app"]

4. 记录你的镜像

始终为你的自定义镜像维护文档,包括:

  • 镜像的用途
  • 如何使用它
  • 你所做的更改
  • 任何配置选项

我们在上一步中创建了一个简单的文档文件。

5. 扫描漏洞

定期扫描你的镜像以查找漏洞:

## 扫描示例(Docker Desktop 内置了此功能)
## docker scan my-custom-nginx:v1

检查 Docker 镜像

让我们探索一个用于检查 Docker 镜像的有用命令:

docker inspect my-custom-nginx:v1

此命令显示有关镜像的详细信息,包括其层、配置和环境变量。

查看镜像历史

你可以查看镜像的构建历史:

docker history my-custom-nginx:v1

这显示了镜像的每一层以及创建它们的命令。

清理

现在让我们通过删除我们创建的容器和镜像来清理我们的环境:

  1. 首先,停止并删除我们的自定义容器:
docker stop my-custom-container
docker rm my-custom-container
  1. 删除我们创建的镜像:
docker rmi my-custom-nginx:v1 my-custom-nginx:latest my-custom-nginx:stable
  1. (可选)删除 Nginx 镜像:
docker rmi nginx:latest nginx:alpine
  1. 检查是否已删除所有容器和镜像:
docker ps -a
docker images

使用 Docker System Prune

Docker 提供了一个方便的命令来清理未使用的资源:

docker system prune

这将删除所有已停止的容器、未使用的网络、悬空的镜像和构建缓存。在继续之前,系统会要求你确认。

为了更积极的清理,你可以使用:

docker system prune -a

这还会删除所有未使用的镜像,而不仅仅是悬空的镜像。

总结

你现在已经学会了如何:

  1. 拉取和运行 Docker 镜像
  2. 修改正在运行的容器
  3. 提交更改以创建新的自定义镜像
  4. 标记镜像以进行组织和分发
  5. 将镜像保存到文件以进行手动传输
  6. 记录你的自定义镜像
  7. 清理你的 Docker 环境

这些技能构成了使用 Docker 镜像的基础,并且在你继续你的容器化之旅时将非常有用。

总结

在这个实践教程中,你已经学习了克隆 Docker 容器镜像的完整过程。你首先了解了 Docker 的基础知识并验证了你的环境。然后,你拉取了一个官方的 Nginx 镜像并将其作为容器运行。接下来,你通过修改其内容来自定义此容器,并将这些更改提交以创建你自己的自定义镜像。

你还学习了如何正确地标记你的镜像以进行版本控制和分发,如何将镜像保存到文件以进行手动传输,以及如何记录你的更改。最后,你探索了使用 Docker 镜像的最佳实践并清理了你的环境。

这些技能为在开发和生产环境中与 Docker 合作奠定了坚实的基础。你现在可以自信地创建和自定义 Docker 镜像以满足你的特定需求,从而使你的应用程序在不同环境中更具可移植性和一致性。