Ubuntu上Docker入门:从核心概念到实战部署全解析
2026/9/18 8:17:57 网站建设 项目流程

我第一次正经在 Ubuntu 上装 Docker,是在某个加班的晚上。当时照着网上的帖子改 daemon.json,填了一堆 registry mirror,结果sudo docker info直接报错,Docker 服务彻底起不来。那时候我连“镜像”和“镜像加速器”都分不清,只知道复制粘贴,最后只能把整个 Docker 卸载重装,才算救回来。

后来把 Ubuntu + Docker 这对组合用了两三年,回过头看,入门阶段真正挡人的根本不是命令记不住,而是脑子里没有一个完整的模型:镜像到底是什么,容器和虚拟机的差别在哪,数据卷为什么要单独挂出来,端口映射到底映射了什么。这篇文章打算一次性把这些讲透,顺便把我踩过的坑也列出来。如果你刚接触 Linux,或者之前在 Windows 上只用过 Docker Desktop,这篇内容会比较对胃口。

我会把安装步骤、常用命令、一次完整的实战部署,还有新手翻车最频繁的五个场景全部串起来讲。跟着走一遍,你对 Docker 的认识会比单纯看文档清楚很多。

1. 为什么偏偏是 Ubuntu:学 Docker 之前的环境选择题

很多人学 Docker 的第一个问题不是“怎么装”,而是“装在哪”。Docker 虽然也支持 Windows 和 macOS,但你只要在 Ubuntu 上体会过一遍容器启动的速度,就回不去了。这不是心理作用,是底层机制决定的。

1.1 Linux 才是 Docker 的“原乡”,内核能力决定起点

Docker 的核心是 Linux 内核的 namespace 和 cgroups 两项能力。namespace 负责隔离:进程、网络、文件系统、用户,每一层都能独立成空间,让容器里的进程误以为自己独占一台机器;cgroups 负责限制:CPU、内存、磁盘 IO,都能精确管控。

Windows 和 macOS 没有这两个内核机制,Docker 只能套一层虚拟机兜底。以 macOS 为例,Docker Desktop 后台其实跑着一个轻量 Linux 虚拟机,所有容器都生存在那台虚拟机里。一旦做了这层中转,文件挂载、端口映射、网络通信都会多一道开销,你在测试时偶尔会碰到“Windows 上正常,放进容器就变慢”的情况。在原生 Ubuntu 上,Docker 直接调用宿主机内核,没有中间层,行为更干净,排错也更简单。

这也是为什么你搜 Docker 相关的论坛帖子,大量解决思路都默认“你是 Linux 环境”。学 Docker 选 Ubuntu,等于站在了官方主推的主场,二手信息少得多。

1.2 实体机、双系统、虚拟机、WSL2,到底选哪个

搞清楚原理之后,还是要落地。我按实际体验给四种方案排个序,适合不同情况的人。

方案上手难度性能适合人群注意点
实体机安装 Ubuntu最好准备长期用 Linux 做主力安装前备份数据,驱动确认清楚
双系统中高既不想放弃 Windows 又想有原生环境分区要留够,引导容易出问题
VMware/VirtualBox 虚拟机一般纯体验、怕折腾要开启嵌套虚拟化,磁盘别用动态容量到底
WSL2较好手头是 Windows,想快速起步文件跨系统读写慢,别把项目放在 /mnt/c 下

个人建议很直接:如果你是学生或开发者,愿意接受一段时间的不方便,直接用实体机装 Ubuntu,收获最大。如果只是想知道 Docker 是什么,虚拟机或 WSL2 足够了,没必要为了学容器专门重装系统。

用 WSL2 的话,有一个细节容易被忽略:项目文件尽量放在 WSL 的 Linux 文件系统里,比如~/projects,不要放在/mnt/c/Users/...下。放 Windows 盘会导致容器挂载和文件读写明显变慢,这个坑我见很多人踩过。

1.3 安装 Ubuntu 时提前埋好的几个“免坑设置”

既然决定在 Ubuntu 上学 Docker,那装系统时就要为 Docker 做准备。我第一次装 Ubuntu 时,分区只分配了 60GB,用半年后 Docker 镜像一多,磁盘直接满了,非常尴尬。

  • 磁盘分区给足:建议至少 80GB,如果你打算用 Docker 跑 GitLab、数据库这类大型服务,给到 150GB 以上更从容。Docker 默认把数据放在/var/lib/docker,所以根分区大就是硬道理。
  • swap 不能省:容器里跑编译任务,内存不够时 swap 能救急。重装系统时单独分一个 swap 分区,或者用 swapfile,8GB 内存配 4GB swap 起步。
  • 安装时选择“最小安装”:装完系统干净清爽,极大的程序可以后面再补。桌面环境之后跑 Docker 占用的资源也更少。
  • 配置好软件源再动手:安装完成后第一件事就是把/etc/apt/sources.list换成速度快的软件源,否则后面apt update能卡到你怀疑人生。

这些坑不解决,你的 Docker 学习之路会从“装系统”就埋下隐患。环境一旦乱掉,后面排查问题时分不清是 Docker 的问题还是系统的问题,那才是真的折磨。

2. 镜像、容器、仓库:先搞懂三个核心词,再谈操作

Docker 的概念体系里,最基础也最容易混淆的是三样东西:镜像、容器、仓库。很多时候命令记不住,就是因为这三个词背后的关系没建立起来。我试着用最朴素的方式讲清楚。

2.1 镜像不是安装包,是“只读模板”

传统认知里,装软件要下载安装包,运行后变成安装在系统里的程序。Docker 镜像完全不是这个逻辑。

镜像是一个只读的、分层存储的文件系统模板。你可以把它理解成做甜品的模具:不管你用它做多少次,模具本身不变,得到的每个成品都长得一样。镜像里已经打包好了运行一个软件所需的代码、运行时、系统库、环境变量和默认配置。

镜像还有一个特性:分层。每一层都在上一层之上做增量修改,Docker 拉取镜像时如果本地已有相同层,会直接复用,不重复下载。这就是为什么你拉很多镜像后,du -sh /var/lib/docker显示的大小不等于各个镜像大小之和,底层共享层已经被合并计算了。

2.2 容器是镜像的“运行实例”,本质是进程

当你用docker run基于某个镜像启动一个容器时,Docker 会在镜像的只读层之上,生成一个可写层,然后在独立的命名空间里启动进程。同一个镜像可以同时启动十个容器,它们彼此隔离,各自的写入互不干扰。

这里要扭转一个根深蒂固的理解:容器不是迷你虚拟机。虚拟机里有完整的操作系统,而容器只是一个进程,它共享宿主机的内核,只不过通过 namespace 让自己看起来拥有一套独立的系统环境。

理解了这个,很多命令就顺了。比如docker exec -it 容器名 bash,本质是往那个进程所在的命名空间里再塞一个进程;docker stop是给容器的 PID 1 进程发 SIGTERM 信号;容器里的主进程一退出,容器就进入 exited 状态。这套逻辑跟“进程”完全一致,而不是跟“虚机开机、关机”一致。

2.3 仓库和标签:镜像的“GitHub”

镜像要分发,就得有个地方存。Docker Hub 就是默认的公共镜像仓库。仓库名由命名空间和仓库名组成,例如library/nginx里的library是官方账号的命名空间,nginx是仓库名。标签则对应版本,比如nginx:1.27nginx:latest,不写标签默认拉 latest。

docker pull nginxdocker pull nginx:latest是等价的,但不建议在生产环境依赖 latest,因为它的指向会随官方更新而变化。代码里也好,Compose 文件里也好,最好写明确的具体标签,保证每次拉取的行为可预期。

2.4 用一个例子验证你是否真的懂了

来做一个简单的脑筋急转弯:执行docker run -d --name web -p 8080:80 nginx后,发生了什么?

完整过程是这样的:Docker 客户端先在本地找nginx:latest镜像,没有就去仓库拉取;拉下来后基于这个镜像创建容器,容器启动 nginx 主进程,监听 80 端口;-p 8080:80把宿主机的 8080 端口流量转发到容器的 80 端口;-d让它后台运行;最终你访问宿主机 IP 的 8080 端口,就能看到 nginx 欢迎页。

如果你能把这个过程完整复述出来,说明你基本理解镜像和容器的关系了。如果你脑子里是“在容器里装了个 nginx”,那理解还需要调整:nginx 早就在镜像里了,容器只是在跑它。

3. Ubuntu 下安装 Docker 的完整过程与安装后的必改项

进入实操环节。Ubuntu 装 Docker 有几种路径,我推荐直接用官方 apt 仓库安装,这种方式的后续升级体验最好,也方便你用 systemd 管理服务。

3.1 安装方式对比:不要一上来就用脚本

常见的安装方式有四种:官方 apt 仓库、Convenience script 脚本、手动下载 deb 包、Docker Desktop。前三者都是社区版 Docker Engine,本质相同,但有细微差别。

方式优点缺点
官方 apt 仓库升级方便、可用 systemctl 管理需要手动添加 GPG key 和源
Convenience script一条命令装完官方不推荐生产环境用;遇到错误难排查
手动下载 deb可离线安装依赖要自己处理,升级麻烦
Docker Desktop带图形界面,开箱即用虚拟机化,性能有损耗;个人试用免费但涉及授权细节

我个人建议老老实实走官方 apt 仓库,你还能借着安装过程理解 Docker 各组件的构成。很多教程让你直接复制脚本,装完出了问题你连 Docker 由哪几个进程组成都不知道,很被动。

3.2 从官方 apt 仓库安装 Docker Engine 的详细步骤

以下命令兼容当前主流 Ubuntu 版本(20.04 到 24.04)。先更新索引,并安装依赖包:

sudo apt update sudo apt install -y ca-certificates curl gnupg lsb-release

添加 Docker 官方 GPG key:

sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod a+r /etc/apt/keyrings/docker.gpg

添加 apt 软件源。下面这段根据你的 Ubuntu 版本动态生成配置,复制即可:

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

安装 Docker:

sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

注意我特意加上了docker-buildx-plugindocker-compose-plugin。新版 Docker 把 BuildX(增强镜像构建)和 Compose(多容器编排)都插件化了,不装的话后面跑docker compose会提示缺命令。

安装完成后查看服务状态:

sudo systemctl status docker

看到 active (running),就可以跑sudo docker run hello-world验证。能打印出那句 “Hello from Docker!”(请以实际输出为准),环境基本就通了。

3.3 配置镜像加速器:提升体验的关键一步

这一步在搜索引擎里非常常见,理由也简单:默认的 Docker Hub 域名在国内访问不稳定,直接拉镜像经常超时。配置镜像加速器的本质,是让 Docker 在拉取公共镜像时,优先从更快的镜像源获取层数据。

修改/etc/docker/daemon.json(如果文件不存在就新建):

{ "registry-mirrors": [ "https://docker.m.daocloud.io", "https://dockerproxy.com", "https://docker.nju.edu.cn" ] }

重启 Docker 使其生效:

sudo systemctl daemon-reload sudo systemctl restart docker

然后sudo docker info,在输出里找Registry Mirrors字段,确认配置已经生效。

注意,镜像加速器的可用性随时间和网络环境变化很大。你配置了几个都不稳定时,多试几个公开源。这类源本质是公共缓存,并不保证所有镜像都一定加速成功,遇到某个镜像拉不下来的情况,换个源再试是常规操作。

3.4 让普通用户免 sudo 运行 Docker

每次敲sudo docker很烦,而且会带来一个隐患:用 sudo 运行时容器文件归属 root,你在宿主机的普通用户目录下想删容器日志或数据卷文件时,会碰到 Permission denied。

解决方案是把当前用户加入 docker 用户组:

sudo usermod -aG docker $USER newgrp docker

重新登录终端后,直接敲docker version不需要 sudo 了。之所以能这样,是因为 Docker CLI 本质是通过/var/run/docker.sock这个 Unix Socket 与 Docker 守护进程通信,docker 用户组对该 socket 有访问权。

这里我要多说一句:加入 docker 用户组的用户,权限上等同于宿主机 root,因为 Docker 提供了挂载宿主机目录进容器的能力。你的机器如果只有自己用,没问题;如果在团队服务器上,给用户加 docker 组要谨慎,这不是普通“组权限”这么简单。

3.5 开机自启与服务管理

Ubuntu 上用 apt 安装的 Docker 一般默认已设置开机自启,但保险起见可以执行:

sudo systemctl enable docker sudo systemctl enable containerd

后面排查问题时,常用的管理命令也一并记住。sudo systemctl stop docker停机,sudo systemctl start docker启动,sudo systemctl restart docker重启。跑 Kubernetes 或一些复杂容器环境时,containerd服务也可能需要单独重启,别把它忘了。

4. 学 Docker 先练熟这些命令:容器生命周期与日常操作

命令不需要背,但要建立“命令对应场景”的直觉。我按容器从创建到销毁的整个生命周期来讲,每一条都有明确的使用时机。

4.1 容器生命周期:run/start/stop/rm 的状态流转

创建并启动一个后台运行的 nginx 容器:

docker run -d --name web -p 8080:80 nginx:1.27

这条命令里的-d表示 detached 后台运行,--name web给容器起名,-p 8080:80做端口映射。如果不加-d,容器会以前台方式运行,你 Ctrl+C 退出时容器也跟着停止,适合调试用。

容器启动后,查看当前状态:

docker ps

docker ps只显示运行中的容器,要看所有状态加-a。停止、启动、重启容器分别对应:

docker stop web docker start web docker restart web

删除容器,必须先在停止态或强制删:

docker rm web docker rm -f web

docker rm -f相当于先强制停止再删除。这里注意一个新手常犯的错:改了容器里的配置或代码,执行docker restart后一切恢复正常,就以为任务完成。实际上容器内的可写层还是原来的,真正的配置修改通常需要重新构建镜像或挂载配置文件,restart 只是重新执行启动命令。

4.2 进入容器与查看日志:exec/logs/attach 的差异

容器运行起来后,你常常需要进去看进程、看环境变量、手动执行命令。常用的是 exec:

docker exec -it web bash

-it是由-i(交互式保持标准输入)和-t(分配伪终端)组成,缺一不可。进容器后可以用ps aux查看进程,echo $VAR查看环境变量,Ctrl+D 退出。

docker attach 也能进入容器,但它直接附着到容器的主进程上,效果等同于“接上了容器的标准输入输出”。对交互型程序(比如 redis-cli)有特定用途,但对多数 Web 类容器,attach 进去按 Ctrl+C 会直接把容器主进程杀掉,危险且不实用。日常建议只用 exec。

看容器日志是排错高频操作:

docker logs web docker logs -f web # 持续跟踪输出 docker logs --tail 50 web # 只看最后 50 行

-f这个参数要重点记住,跟 Linux 下的tail -f完全一个思路。有些容器没写日志到 stdout,而是写到容器内文件,这时需要docker exec进去看,或把日志目录挂载出来。

4.3 端口映射和数据卷:容器与外界互通的两种方式

容器默认有一个隔离的网络空间,外部无法直接访问。端口映射就是把宿主机端口和容器端口绑定,翻译成人话:发给宿主机 8080 端口的请求,Docker 原样转发给容器里 80 端口正在监听的进程。

再看数据卷。容器一旦删除,里面所有写入内容都没了,这符合“不可变基础设施”的理念。要想数据持久化,必须挂数据卷。三种方式对比如下:

方式写法数据位置场景
命名卷-v mydata:/var/lib/mysql/var/lib/docker/volumes/mydata推荐,Docker 管理
绑定挂载-v /home/user/app:/app宿主机指定路径开发调试,改代码即生效
tmpfs 挂载--tmpfs /tmp内存只要临时数据,不落盘

用起来很简单:

docker run -d --name db \ -v dbdata:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD=123456 \ mysql:8.0

这个-v dbdata:/var/lib/mysql就是典型的命名卷用法,容器删掉重来,数据还在卷里。

4.4 镜像管理:pull/images/rmi/tag 的日常配合

镜像相关的命令没有容器那么繁琐,但有一个点要特别说明:镜像标签是可以随意起的,不要把 tag 当作唯一的身份标识。

docker pull mysql:8.0 docker images docker rmi mysql:8.0 docker tag mysql:8.0 my-mysql:backup

docker tag只是给镜像加了另一个名字,不会复制镜像数据。docker rmi删除的是镜像的标签引用,如果多个标签指向同一个镜像 ID,删除一个标签不会释放空间,镜像仍在。要真正释放空间,得把所有关联标签都删掉,或者用docker image prune清理悬空的镜像层。

导出导入镜像也偶尔用得到:

docker save -o mysql.tar mysql:8.0 docker load -i mysql.tar

save/load适合内网环境迁移镜像,但镜像一般很大,大量镜像最好还是用私有仓库分发。

4.5 常用命令速查表

场景命令
运行容器docker run -d --name app -p 8080:80 nginx
列出容器docker ps / docker ps -a
停止容器docker stop app
删除容器docker rm -f app
进入容器docker exec -it app bash
查看日志docker logs -f app
构建镜像docker build -t myapp .
删除镜像docker rmi myapp
清理无用资源docker system prune -a
查看资源占用docker stats

docker stats是排查性能问题的利器,能看到每个容器的 CPU 和内存实时占用,新手尽早学会看它,能省很多日子找“为什么电脑变卡”的时间。

5. 一次完整的实战:用 Docker Compose 部署带数据库的 Web 应用

光练命令不够,得有一个串起来的实战。我选一个最经典、也最能覆盖 Docker 核心场景的组合:WordPress + MySQL,用 Docker Compose 一条命令全部起来。你自己玩的时候可以替换成任何技术栈,思路完全一致。

5.1 先选型再动手:最小可用的容器化方案

我故意选 WordPress,因为它不需要你写任何代码,却能把环境变量、数据卷、端口映射、服务依赖四个核心概念全部演示一遍。

最终架构是两台容器:MySQL 8.0 负责存数据,WordPress 应用容器读取数据库并对外提供 Web 服务。WordPress 容器启动时要连数据库,所以依赖 MySQL 先就绪。

在项目目录下创建一个docker-compose.yml

services: db: image: mysql:8.0 container_name: wp-db restart: always environment: MYSQL_DATABASE: wordpress MYSQL_USER: wpuser MYSQL_PASSWORD: wppass MYSQL_ROOT_PASSWORD: rootpass volumes: - dbdata:/var/lib/mysql networks: - wpnet app: image: wordpress:6.4 container_name: wp-app restart: always depends_on: - db ports: - "8080:80" environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wpuser WORDPRESS_DB_PASSWORD: wppass WORDPRESS_DB_NAME: wordpress volumes: - wpdata:/var/www/html networks: - wpnet volumes: dbdata: wpdata: networks: wpnet:

这个 Compose 文件信息量很大,拆开看几个关键点。

db服务里那个MYSQL_DATABASEMYSQL_USERMYSQL_PASSWORD环境变量,是 MySQL 官方镜像首次初始化数据库时使用的。镜像会自动执行一段初始化脚本,根据这些变量创建数据库和账号。MYSQL_ROOT_PASSWORD则是 root 用户的密码,本地测试可以随意,上生产必须换强密码。

app服务端口映射写的是"8080:80",这意味着你访问宿主机的 8080 端口就是访问容器里的 WordPress。还有个不起眼的restart: always,它的意思是容器异常退出时 Docker 会自动拉起,这是生产部署里非常实用的配置。

depends_on只保证 db 容器先启动,不保证数据库已经就绪。实际遇到 WordPress 容器先启动连不上数据库的情况,别慌,重启 app 容器就行。这属于编排工具都存在的“有状态等待”问题,生产环境要彻底解决需要上健康检查,入门阶段知道现象即可。

5.2 启动与验证:一条命令看到完整应用

docker-compose.yml所在目录执行:

docker compose up -d

-d让所有服务后台运行。看到Started或 container created/running 状态说明启动成功。查看状态:

docker compose ps

然后在浏览器访问http://你的服务器IP:8080,能看到 WordPress 安装界面就说明整套部署已经通了。别急着点安装,先验证数据持久化:

docker compose down docker compose up -d

docker compose down会删除容器,但因为数据卷还在,再次启动后 WordPress 的配置和文章应该全部还在。能通过这个验证,就说明你对数据卷的理解到位了。

5.3 数据备份与恢复:持久化之后的必修课

容器化部署后,数据备份的方式变了,你不再是去登录机器拷贝 /var/lib/mysql 目录,而是借助容器来帮你导出。

MySQL 数据导出:

docker exec wp-db sh -c 'exec mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" wordpress' > wordpress_backup.sql

恢复时,把备份文件拷入容器再导入:

cat wordpress_backup.sql | docker exec -i wp-db mysql -u root -p"$MYSQL_ROOT_PASSWORD" wordpress

这种做法的优雅之处在于,mysqldump命令在镜像本身就存在,你不必在宿主机再装一份 MySQL 客户端,也不会污染宿主机的软件环境。

5.4 应用升级的正确姿势

WordPress 或 MySQL 发布新版本后,升级操作有讲究。直接改 Compose 文件里的镜像标签,然后执行:

docker compose pull docker compose up -d

docker compose pull会提前把新镜像拉下来,等镜像层面确认无误后再重建容器。重建过程中,WordPress 容器会短时间内不可用,但数据不会丢,因为在卷里。需要注意 MySQL 跨大版本升级有兼容性风险,比如从 5.7 升到 8.0,建议先在测试环境跑一遍再动生产。

6. 新手翻车重灾区:我在 Ubuntu 上踩过的五个 Docker 坑

下面说的五个问题,全是我自己或身边的同行真实遇到过的。每个我都会从现象出发,带一遍排查链路,而不是直接甩答案。

6.1 daemon.json 写错导致 Docker 服务起不来

现象:sudo systemctl start docker后,docker ps报“Cannot connect to the Docker daemon”。systemctl status docker显示 failed 状态。

我第一次遇到时很懵,其实这是 daemon.json 语法或路径问题。排查链路如下:

sudo systemctl status docker sudo journalctl -u docker --no-pager -n 50

日志里会明确提示/etc/docker/daemon.json解析失败,或者配置的镜像加速器地址格式有问题。最稳的排错方法是把 daemon.json 临时改名,重启 Docker,确认能起来后,再一行行加回配置。

这里分享一个通用的 JSON 校验方法,不用装任何工具:

python3 -m json.tool /etc/docker/daemon.json

如果 JSON 有问题,它会直接告诉你哪一行错了。这个命令我用了无数次,比肉眼找逗号靠谱一百倍。

6.2 容器启动后立刻退出,日志里却什么都没有

现象:docker run -d nginxdocker ps -a看到容器已经是 Exited (0) 状态。

这类问题十有八九是前台进程没有保持运行。Docker 容器活着的前提是 PID 1 进程还活着,一旦主进程退出,容器就退出。比如你运行docker run -d ubuntu,Ubuntu 镜像默认没有常驻进程,启动后立刻退出是正常现象,不是故障。

排查方法是看退出状态码和日志:

docker ps -a docker logs 容器名

如果日志为空,说明主进程连输出都没产生,多半是镜像本身的启动命令与容器不匹配。你自定义镜像时,务必确保启动命令是前台运行的。以 nginx 为例,应该用nginx -g "daemon off;",而不是直接nginx,因为守护进程模式会让主进程 fork 到后台后立即退出,容器就跟着退出。

6.3 端口被占用的迷茫

现象:docker run -p 8080:80 nginx报错port is already allocated

这个很好理解:宿主机 8080 端口已经有一个进程在监听。可能是另一个容器占用了,也可能是宿主机自己的服务占着。

查找占用端口的进程:

ss -lntp | grep 8080 sudo lsof -i:8080

如果确认是宿主机进程,要么杀掉进程,要么换一个宿主端口映射。我习惯把端口规划写在 Compose 文件注释里,避免多个项目互相抢端口。

另一个常见情形是:你跑着容器 A 占用 8080,docker stop A后端口并没有马上释放。这种情况罕见但存在,通常是因为容器内进程有 TCP 连接处于 TIME_WAIT 状态。解决办法很简单:换个宿主机端口,或者稍等几秒重试,不要和内核较劲。

6.4 镜像拉取过慢、超时,加速器还是一样慢

现象:docker pull一个大镜像,进度条在某个层卡住,然后报 timeout。

反复配置多个镜像加速器仍然慢,可能的原因有几个,按优先级排查:

  1. 加速器本身不稳定。公共加速器的可用性谁也无法保证,可以换个时间再试,也可以换一个源。
  2. IPv6 优先问题。部分 Ubuntu 系统的 DNS 返回了 IPv6 地址,但你的网络 IPv6 路由不通,导致连接卡死。临时禁用 IPv6 试试:
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1
  1. DNS 解析缓慢。检查/etc/resolv.conf,必要时改成223.5.5.5这类公共 DNS。

总的来说,镜像拉取慢在特定网络环境下是个长期问题。我的习惯是:把常用的基础镜像(nginx、mysql、python、node 等)提前在网络顺畅时拉好,构建应用镜像时基础层不会再来一次。

6.5 /var/lib/docker 磁盘爆炸

现象:Ubuntu 系统盘报警,du -sh /var/lib/docker占了几十个 G。

Docker 默认把所有镜像层、容器可写层、数据卷都存在/var/lib/docker,没有自动清理机制。常见清理手段:

docker system df # 查看磁盘占用 docker system prune # 清理停止的容器、无用网络、悬空镜像 docker system prune -a # 再清理所有未被容器引用的镜像 docker volume prune # 清理无主数据卷

docker system prune -a会把你本地所有未被运行的容器引用的镜像都删掉,即使这些镜像你只是构建时用了一下。第一次执行时它会征求你的确认,看清楚再按 y。

还有一个从源头控制的方法:给 Docker 的数据目录单独改位置,或把/var/lib/docker迁到大分区。迁移方法是先停止 Docker,再把整个目录 rsync 到新位置,最后修改 daemon.json 里的>

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询