欢迎光临
我们一直在努力

Docker-玩转 Docker 镜像:从拉取、构建到发布

头图

Docker-玩转 Docker 镜像:从拉取、构建到发布

文章目录

  • Docker-玩转 Docker 镜像:从拉取、构建到发布
    • 摘要
    • 一、镜像是什么?为什么它是只读的?
      • 1.1 镜像的本质:分层文件系统
      • 1.2 镜像 ≠ 容器
    • 二、从 Docker Hub 拉取镜像
      • 2.1 查找镜像
      • 2.2 拉取镜像
    • 三、管理本地镜像:查看、删除与清理
      • 3.1 查看本地镜像
      • 3.2 删除镜像
    • 四、实战:用 `docker commit` 创建自定义镜像
      • 4.1 场景:定制一个带 `curl` 的 Nginx 镜像
        • 步骤 1:启动基础容器
        • 步骤 2:在容器内安装 curl
        • 步骤 3:提交为新镜像
        • 步骤 4:验证新镜像
      • 4.2 `docker commit` 的局限性
    • 五、镜像标签(Tag)与推送(Push)
      • 5.1 为镜像打标签
      • 5.2 推送镜像到私有仓库(以阿里云为例)
    • 六、常见误区与最佳实践
      • ❌ 误区 1:“镜像越大越好,功能越全越好”
      • ❌ 误区 2:“每次修改都要重新 pull 整个镜像”
      • ✅ 最佳实践清单:
    • 七、进阶预告:Dockerfile 才是王道
    • 结语

关键字:
Docker、
docker pull、
docker commit、
Docker Hub、
私有镜像仓库
UnionFS、
镜像分层

摘要

镜像,是 Docker 世界的“源代码”。 容器只是它的运行时实例,而镜像决定了容器能做什么、依赖什么、如何启动。

在上一篇《Docker 终极入门》中,我们成功运行了 hello-world 容器,初步理解了镜像与容器的关系。但那只是冰山一角。真正掌握 Docker,必须深入理解镜像的生命周期——如何获取、如何创建、如何管理、如何共享。

本文将带你系统掌握 Docker 镜像的核心操作:从官方仓库拉取镜像、查看本地镜像列表、删除无用镜像,到通过 docker commit 快速构建自定义镜像,并为后续使用 Dockerfile 打下基础。最后,我们还将简要介绍如何将镜像推送到私有仓库(如阿里云容器镜像服务),实现团队协作与持续交付。

准备好了吗?让我们一起“玩转” Docker 镜像!


一、镜像是什么?为什么它是只读的?

1.1 镜像的本质:分层文件系统

Docker 镜像并不是一个单一的文件,而是一个由多层只读文件系统叠加而成的联合文件系统(Union File System,简称 UnionFS)。

每一层代表一次变更:比如安装一个软件包、复制一个配置文件、设置环境变量等。这些层按顺序堆叠,最终形成完整的根文件系统。

#mermaid-svg-PhssyHgb1HW2jWth {font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-PhssyHgb1HW2jWth .error-icon{fill:#552222;}#mermaid-svg-PhssyHgb1HW2jWth .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PhssyHgb1HW2jWth .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-PhssyHgb1HW2jWth .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PhssyHgb1HW2jWth .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PhssyHgb1HW2jWth .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PhssyHgb1HW2jWth .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PhssyHgb1HW2jWth .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PhssyHgb1HW2jWth .marker.cross{stroke:#333333;}#mermaid-svg-PhssyHgb1HW2jWth svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PhssyHgb1HW2jWth .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-PhssyHgb1HW2jWth .cluster-label text{fill:#333;}#mermaid-svg-PhssyHgb1HW2jWth .cluster-label span{color:#333;}#mermaid-svg-PhssyHgb1HW2jWth .label text,#mermaid-svg-PhssyHgb1HW2jWth span{fill:#333;color:#333;}#mermaid-svg-PhssyHgb1HW2jWth .node rect,#mermaid-svg-PhssyHgb1HW2jWth .node circle,#mermaid-svg-PhssyHgb1HW2jWth .node ellipse,#mermaid-svg-PhssyHgb1HW2jWth .node polygon,#mermaid-svg-PhssyHgb1HW2jWth .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PhssyHgb1HW2jWth .node .label{text-align:center;}#mermaid-svg-PhssyHgb1HW2jWth .node.clickable{cursor:pointer;}#mermaid-svg-PhssyHgb1HW2jWth .arrowheadPath{fill:#333333;}#mermaid-svg-PhssyHgb1HW2jWth .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PhssyHgb1HW2jWth .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PhssyHgb1HW2jWth .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-PhssyHgb1HW2jWth .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-PhssyHgb1HW2jWth .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PhssyHgb1HW2jWth .cluster text{fill:#333;}#mermaid-svg-PhssyHgb1HW2jWth .cluster span{color:#333;}#mermaid-svg-PhssyHgb1HW2jWth div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PhssyHgb1HW2jWth :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

Base Layer: OS (e.g., Ubuntu)

Layer 1: Install curl

Layer 2: Copy app code

Layer 3: Set ENV PORT=8080

Top Read-Only Image

这种设计带来两大优势:

  • 高效复用:多个镜像若基于同一基础镜像(如 ubuntu:22.04),则底层共享,节省磁盘空间;
  • 快速构建:修改某一层时,只需重建该层及之后的层,前面的缓存可直接复用。

💡 当你运行一个容器时,Docker 会在镜像顶部动态添加一个可写层(Container Layer),所有运行时的写入操作(如日志、临时文件)都发生在这里。容器停止后,该层可被丢弃或保留。

1.2 镜像 ≠ 容器

再次强调这个关键区别:

项目镜像(Image)容器(Container)
状态 只读、静态 可写、动态(运行时实例)
类比 类(Class) 对象(Object)
存储位置 /var/lib/docker/image/… 镜像 + 可写层
是否可变 不可变 可变(但重启后可写层丢失,除非持久化)

二、从 Docker Hub 拉取镜像

Docker Hub 是官方提供的公共镜像仓库,类似于 GitHub 之于代码。几乎所有主流软件都有官方镜像。

2.1 查找镜像

你可以通过以下方式查找镜像:

  • 浏览网站:搜索 “nginx”、“mysql”、“redis” 等;

  • 使用命令行:

    docker search nginx

    输出示例:

    NAME DESCRIPTION STARS OFFICIAL
    nginx Official build of Nginx. 18000 [OK]
    jwilder/nginx-proxy Automated Nginx reverse proxy 5800

✅ 建议优先选择带 [OK] 标记的官方镜像(Official Images),它们经过安全审计、文档完善、更新及时。

2.2 拉取镜像

使用 docker pull 命令下载镜像:

# 拉取最新版 Nginx
docker pull nginx

# 拉取指定版本(强烈推荐!)
docker pull nginx:1.25-alpine

📌 最佳实践:永远不要在生产环境中使用 latest 标签!它可能随时变动,导致不可预测的行为。应明确指定版本号(如 1.25、8u292-jre)。


三、管理本地镜像:查看、删除与清理

3.1 查看本地镜像

docker images

输出示例:

REPOSITORY TAG IMAGE ID CREATED SIZE
nginx 1.25-alpine a6bd7d1c5b3a 2 weeks ago 42.3MB
hello-world latest feb5d9fea6a5 12 months ago 13.3kB

  • REPOSITORY:镜像名(通常对应软件名);
  • TAG:版本标签(如 latest, 1.0, alpine);
  • IMAGE ID:镜像唯一标识(SHA256 哈希值前几位);
  • SIZE:仅显示顶层大小,不包括共享层。

3.2 删除镜像

# 删除指定镜像(需先停止并删除相关容器)
docker rmi nginx:1.25-alpine

# 强制删除(即使有容器引用)
docker rmi -f <IMAGE_ID>

# 删除所有未被使用的镜像(悬空镜像 + 无标签镜像)
docker image prune -a

⚠️ 注意:如果某个镜像正在被容器使用(即使是已停止的容器),Docker 默认不允许删除。可先执行 docker rm $(docker ps -aq) 清理所有容器(谨慎操作!)。


四、实战:用 docker commit 创建自定义镜像

虽然正式项目应使用 Dockerfile,但在调试或快速原型阶段,docker commit 是一个非常实用的技巧。

4.1 场景:定制一个带 curl 的 Nginx 镜像

假设我们需要一个既能运行 Nginx,又能用 curl 测试内部服务的容器。

步骤 1:启动基础容器

docker run -it –name my-nginx nginx:alpine sh

步骤 2:在容器内安装 curl

# 在容器 shell 中执行
apk add –no-cache curl
curl -I http://127.0.0.1 # 测试是否安装成功(会失败,因为 Nginx 未启动)

💡 注意:此时 Nginx 进程并未运行,因为我们覆盖了默认 CMD(nginx -g 'daemon off;')为 sh。

步骤 3:提交为新镜像

另开一个终端,执行:

docker commit my-nginx my-nginx-with-curl:v1

现在,my-nginx-with-curl:v1 就包含了 curl 工具!

步骤 4:验证新镜像

docker run -d –name test-nginx my-nginx-with-curl:v1
docker exec test-nginx curl -I http://127.0.0.1

输出应包含 HTTP/1.1 200 OK,说明一切正常。

4.2 docker commit 的局限性

虽然方便,但 commit 方式存在明显缺点:

  • 不可追溯:无法知道镜像是如何构建的;
  • 难以复现:手动操作步骤容易遗漏;
  • 镜像臃肿:可能包含临时文件或调试工具。

因此,仅建议用于临时调试。正式项目请使用 Dockerfile(下一篇重点讲解)。


五、镜像标签(Tag)与推送(Push)

5.1 为镜像打标签

你可以为同一镜像设置多个标签:

# 为刚创建的镜像添加新标签
docker tag my-nginx-with-curl:v1 registry.cn-hangzhou.aliyuncs.com/your-namespace/my-nginx:v1

格式:<仓库地址>/<命名空间>/<镜像名>:<标签>

5.2 推送镜像到私有仓库(以阿里云为例)

  • 登录阿里云容器镜像服务 访问 阿里云容器镜像服务控制台,创建命名空间和镜像仓库。

  • 登录 Docker Registry

    docker login –username=your-aliyun-account registry.cn-hangzhou.aliyuncs.com
    # 输入密码(可使用访问凭证)

  • 推送镜像

    docker push registry.cn-hangzhou.aliyuncs.com/your-namespace/my-nginx:v1

  • ✅ 成功后,团队成员即可通过 docker pull 拉取该镜像,实现标准化部署。


    六、常见误区与最佳实践

    ❌ 误区 1:“镜像越大越好,功能越全越好”

    正解:镜像应遵循最小化原则。只包含运行应用所必需的组件。Alpine Linux 镜像(几 MB)远优于 Ubuntu(几百 MB)。

    ❌ 误区 2:“每次修改都要重新 pull 整个镜像”

    正解:Docker 采用分层拉取。若基础层已存在,只会下载变更层,速度极快。

    ✅ 最佳实践清单:

    • 明确指定镜像 TAG,避免 latest;
    • 优先使用官方或可信来源镜像;
    • 定期清理无用镜像(docker system prune);
    • 敏感信息(密码、密钥)绝不写入镜像;
    • 生产环境使用私有仓库,避免依赖公网。

    七、进阶预告:Dockerfile 才是王道

    虽然 docker commit 能快速构建镜像,但它无法满足工程化需求。下一讲,我们将深入学习 Dockerfile —— 一种声明式的镜像构建脚本,让你:

    • 完全掌控构建过程;
    • 实现构建可重复、可审计;
    • 利用缓存加速构建;
    • 编写符合安全规范的镜像。

    届时,你会明白为什么所有 CI/CD 流水线都依赖 Dockerfile,而不是 commit。


    结语

    镜像,是 Docker 生态的基石。掌握其拉取、管理、构建与发布,是你迈向 DevOps 和云原生开发的关键一步。

    记住:好的镜像 = 小体积 + 明确版本 + 安全可靠 + 可复现。

    现在,你已经可以自信地说:“我不再只是运行容器,我还能打造属于自己的镜像!”


    系列预告: 下一篇 → 《Docker 容器生命周期管理:从创建到消亡》 我们将全面掌握 docker run、exec、stop、rm 等核心命令,并理解容器状态机!


    参考资料:

    • Docker 官方镜像指南:https://docs.docker.com/develop/develop-images/
    • 阿里云容器镜像服务文档:https://help.aliyun.com/product/60716.html
    • 《Docker in Action》 by Jeff Nickoloff

    博客签名2021

    赞(0)
    未经允许不得转载:171主机测评 » Docker-玩转 Docker 镜像:从拉取、构建到发布
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址