Docker镜像总踩坑?掌握这6大痛点+8个核心法则,新手也能零失误

fLk6p99Sv

刚学 Docker 的你,是不是也踩过这些坑?

拉取镜像只知道敲docker pull nginx,生产环境用latest标签导致版本混乱;

想构建自己的镜像,对着 Dockerfile 一脸懵,改来改去还是构建失败;

删除镜像总提示 “被容器使用”,死活删不掉;

Docker 的核心是镜像,容器只是镜像的运行时实例。镜像的获取、管理、构建、发布是 Docker 的入门必修课。

今天,我们就把 Docker 镜像的核心操作讲透:从镜像的获取、查看、删除、导入导出;到用 Dockerfile/Commit 构建镜像;再到镜像发布到仓库。

Docker 镜像操作的 6 大高频痛点

不管是 Docker 新手还是入门不久的开发者,在镜像操作中都会遇到这些共性问题:

  1. 拉取镜像不指定版本,全程用latest,开发、测试、生产环境镜像版本不一致,线上问题层出不穷;
  2. 查看镜像只知道 docker image ls,看不懂镜像体积、分不清中间层镜像,磁盘占满了都不知道怎么清理;
  3. 删除镜像无脑敲 docker image rm,遇到 “容器占用” 提示就懵,不懂 Untagged 和 Deleted 的核心区别;
  4. 构建镜像只会用 Commit,镜像分层混乱、体积臃肿,无法复用和维护;
  5. 编写 Dockerfile 不规范,命令拼接错误、构建上下文没处理,反复构建失败;
  6. 发布镜像踩格式坑,不知道镜像名要和仓库账号匹配,推送时提示权限不足或格式错误。

这些问题的本质,要么是操作不规范,要么是没搞懂 Docker 镜像的底层逻辑。

Docker 镜像的核心逻辑

很多人镜像操作踩坑,不是记不住命令,而是没搞懂这 3 个核心逻辑,看似操作正确,实则埋下隐患,这也是镜像操作的核心冲突点:

01、镜像标签不是 “可有可无”,latest是最大的坑

标签(Tag)是镜像的版本标识符,未指定标签时 Docker 默认拉取latest。

但 **latest并非固定版本 **,只是指向仓库中最新推送的镜像,一旦仓库更新,latest对应的镜像就会变,直接导致环境不一致。

生产环境必须指定具体标签(如nginx:1.20.0)。

02、镜像体积的 “视觉差”,不是 Docker 出了错

你会发现docker image ls显示的镜像体积,和 Docker Hub 上的大小完全不同,这不是 bug:Docker Hub 显示的是压缩后体积(关注网络传输),本地显示的是展开后体积(关注磁盘占用);

本地镜像体积总和≠实际磁盘消耗,因为镜像分层存储,相同基础层会复用,只保存一份。

03、删除镜像的 “两步走”:Untagged ≠ Deleted

Docker 删除镜像时,先执行Untagged(取消标签),再执行Deleted(删除镜像层):

一个镜像可以有多个标签,若仅删除其中一个,只是取消标签,镜像主体还在;

只有当镜像的所有标签都被取消,且无容器 / 其他镜像依赖其底层层时,才会真正物理删除镜像层。

Docker 镜像的核心操作

镜像的全流程操作可以分为基础管理(获取 / 查看 / 删除 / 导入导出)、镜像构建(Dockerfile/Commit)、镜像发布、特殊镜像详解四部分。

(一) 基础管理:镜像的获取、查看、删除、导入导出

这是镜像最高频的操作,命令简单,但细节多。

1、获取镜像:docker pull,告别latest,指定版本是关键

核心命令:docker pull [Registry地址/][仓库名]:[标签]

# 从Docker Hub拉取指定版本nginx
docker pull nginx:1.20.0

# 从第三方仓库quay.io拉取镜像
docker pull quay.io/bitnami/nginx:latest

注意:

  1. 优先选择 Docker Hub 上的Docker Official Images(官方镜像)/Verified Content(认证镜像),安全性更高;

  2. 拉取速度慢时,配置国内镜像源(阿里云、网易云、中科大),大幅提升速度。

02、查看镜像:不止docker image ls,这些命令才是实用派

基础查看只是入门,学会过滤、格式化查看,才能高效管理镜像,核心命令如下:

# 基础查看:仓库名、标签、镜像ID、创建时间、体积
docker image ls

# 查看所有镜像(包括中间层镜像)
docker image ls -a

# 只查看镜像ID(批量操作必备)
docker image ls -q

# 过滤查看:只看nginx相关镜像
docker image ls nginx

# 格式化查看:自定义显示列(ID、仓库名、标签)
docker image ls --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"

# 查看镜像详细信息(如分层、环境变量、暴露端口)
docker image inspect 镜像ID/镜像名:标签

# 查看镜像/容器/数据卷的磁盘占用情况
docker system df
03、删除镜像:docker image rm,先清容器再删镜像

核心命令:docker image rm 镜像ID/镜像名:标签/镜像摘要

# 通过短ID删除(输入前3-4位即可,能唯一区分)
docker image rm 501

# 通过镜像名:标签删除
docker image rm nginx:1.20.0

# 批量删除:删除所有redis镜像
docker image rm $(docker image ls -q redis)

注意:

  1. 若提示 “镜像被容器使用”,先停止并删除相关容器:docker container stop 容器ID && docker container rm 容器ID;
  2. 批量删除前,先单独执行过滤命令(如docker image ls -q redis)确认结果,避免误删;
  3. 镜像摘要是最精确的标识,通过docker image ls --digests查看,适合生产环境精准操作。
04、导入导出:save/load,离线环境镜像共享的唯一方式

适用于无网络的离线环境,将镜像导出为 tar 包,再导入到其他服务器

# 导出镜像:-o 指定输出文件,可导出多个镜像
docker image save -o nginx_1.20.0.tar nginx:1.20.0

# 导入镜像:从tar包导入
docker image load -i nginx_1.20.0.tar

注意:

  1. 导出的 tar 包包含镜像的所有分层,体积较大,适合小范围离线共享;
  2. 团队 / 生产环境的镜像共享,优先用镜像仓库(Docker Hub / 私有仓库),而非手动拷贝 tar 包。
(二) 镜像构建:两种方式,Dockerfile 是核心,Commit 仅临时使用

构建自定义镜像是 Docker 的核心能力,有Dockerfile 构建和Commit 构建两种方式。

前者是官方推荐的标准方式,后者仅适用于临时测试。

05、Commit 构建:临时测试可用,生产环境严禁使用

核心逻辑:基于运行的容器做修改,再将容器保存为镜像,适合快速测试,但镜像分层混乱、无法追溯修改记录,体积臃肿。

# 1. 启动一个nginx容器,进入容器做修改
docker run -it --name nginx-test nginx:1.20.0 /bin/bash

# 2. 在容器内修改(如修改首页index.html)
echo "<h1>Hello Docker</h1>" > /usr/share/nginx/html/index.html

# 3. 退出容器,将容器保存为新镜像
docker container commit 容器ID/容器名 新镜像名:标签

# 示例:将nginx-test容器保存为my-nginx:1.0
docker container commit nginx-test my-nginx:1.0

注意:

Commit 构建的镜像被称为 “黑盒镜像”,团队协作中其他人无法知道镜像内的修改,严禁在生产环境使用。

06、Dockerfile 构建:标准化方式,必学必会

Dockerfile 是构建镜像的文本配置文件,包含构建镜像的所有指令,可追溯、可复用、可批量构建,是企业生产环境的标准方式。

Dockerfile 基础结构(规范示例)

# 基础镜像:指定基于哪个镜像构建,必选首行
FROM ubuntu:22.04

# 执行命令:安装python3环境,&&拼接命令减少分层,避免apt-get交互
RUN apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \
    python3.10 python3-pip python3.10-dev
    
# 添加文件:将本地hello.py添加到容器根目录
ADD hello.py /

# 容器启动命令:指定容器运行时执行的命令
CMD ["python3", "/hello.py"]

核心构建命令

# 构建镜像:-t 标记镜像名:标签,. 表示构建上下文为当前目录
docker image build -t hello-docker:1.0 .

注意:

  1. 构建上下文:docker build后的.表示构建上下文,Docker 会将该目录下的所有文件发送给 Docker 守护进程,因此构建目录要保持干净,避免无关文件增大镜像体积;
  2. 减少分层:用&&拼接RUN命令,避免多条RUN创建多个分层,导致镜像体积臃肿;
  3. 选择轻量基础镜像:优先用 alpine 版本(如nginx:1.20.0-alpine),比官方标准版体积小 80% 以上。
(三) 镜像发布:推送到仓库,团队协作的核心方式

构建好的自定义镜像,需要发布到公共仓库(Docker Hub)或私有仓库,才能实现团队共享和生产环境部署。

完整发布流程(以 Docker Hub 为例)

# 1. 注册并登录Docker Hub(终端登录)
docker login

# 2. 标记镜像:格式必须为「Docker Hub账号/仓库名:标签」
docker image tag 本地镜像名:标签 账号名/仓库名:标签

# 示例:将hello-docker:1.0标记为xiaopeng163/hello-docker:1.0
docker image tag hello-docker:1.0 xiaopeng163/hello-docker:1.0

# 3. 推送镜像到Docker Hub
docker image push xiaopeng163/hello-docker:1.0

# 4. 其他机器拉取该镜像
docker pull xiaopeng163/hello-docker:1.0

注意:

  1. 推送前必须先标记镜像,格式错误会直接推送失败;
  2. 私有仓库推送:镜像名格式为「私有仓库 IP: 端口 / 仓库名:标签」,如192.168.1.100:5000/my-nginx:1.0;
  3. 推送失败检查:确认仓库账号已登录、镜像名格式正确、网络能访问仓库。
(四) 特殊镜像详解:scratch,极简的空镜像

scratch 是 Docker 官方提供的空镜像,没有任何分层、没有操作系统、没有任何文件,是构建超轻量镜像的基础,很多官方基础镜像(如 alpine)都是基于 scratch 构建的。

核心要点:

  1. 无法拉取:docker pull scratch会失败,scratch 是 Docker 内置的空镜像,无需拉取,可直接在 Dockerfile 中使用FROM scratch;
  2. 适用场景:仅适用于静态可执行文件(如 C/C++ 编译的静态二进制文件),因为没有操作系统,无法运行解释型语言(如 Python/Java,需要运行环境);
  3. 核心优势:镜像体积几乎等于静态可执行文件的大小,极致轻量,安全性高(无多余文件和依赖,减少攻击面);
  4. 避坑要点:开发环境极少使用,仅在生产环境需要极致轻量镜像时使用,且必须保证可执行文件是静态编译(编译时加--static参数)。

核心总结

最后总结 8 个核心法则,记住这些,能让你避开 90% 的镜像操作坑,新手也能做到规范操作:

  1. 生产环境禁用latest标签,拉取 / 构建镜像必须指定具体版本,保证环境一致性;
  2. 优先用 Dockerfile 构建镜像,Commit 仅用于临时测试,严禁生产环境使用;
  3. Dockerfile 编写要精简,拼接 RUN 命令、选择轻量基础镜像,减少镜像分层和体积;
  4. 删除镜像先清容器,遇到占用提示,先停止并删除相关容器,再删镜像;
  5. 发布镜像必改格式,镜像名必须和仓库账号 / 私有仓库地址匹配,否则推送失败;
  6. 查看镜像多用过滤 / 格式化,docker system df定期检查磁盘占用,及时清理无用镜像;
  7. 离线共享用save/load,团队 / 生产环境用镜像仓库,拒绝手动拷贝 tar 包;
  8. scratch 镜像仅用于静态可执行文件,解释型语言不要用,避免构建后无法运行。

写在最后

镜像作为 Docker 的核心,是容器化部署的基础,掌握了镜像的获取、管理、构建、发布,你就已经跨过了 Docker 的入门门槛。

接下来,容器是 Docker 另一个核心概念。那我们应该如何管理容器呢?包括:如何创建,如何启动,如何停止。

下期,我将掰开了,揉碎了,把它们一次性讲清楚。

想要获取《Docker 镜像核心操作速查表》,请在 评论区 / 私信 回复 【Docker 核心速查】。

其他疑问

Docker 仓库别再踩坑了!Registry/ Harbor/ Nexus 选对,镜像管理效率翻倍

搞 Docker 必懂的镜像与容器:分层存储是关键,看完少走 3 年弯路

开发/测试/生产环境切换就报错?Flask多环境配置秘籍+增删改查封装,开发效率翻倍(避坑大全)

告别碎片化教程!3分钟从0到1系统搞定MySQL与ORM联动,看这篇就够了

别再手动验参了!Flask动态路由的3个技巧,让URL校验自动化,效率提升300%

相关内容我都给大家做好了,感兴趣的朋友来「我的主页」找一找,直接就可以看到。

欢迎关注 「王二哥的技术笔记」,每天分享「FastAPI」、「Docker」、「Flask」、「职场」有趣干货,千万不要错过!

更多推荐