ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Ubuntu安装Docker完整指南:从环境预检到排错实战

Ubuntu安装Docker完整指南:从环境预检到排错实战

从零开始:Ubuntu 装机路上的一次 Docker 安装记录

作为一个长期折腾 Linux 桌面和服务器的用户,我几乎每次重装系统都要和 Docker 打交道。这篇文章是我前段时间在一台全新的 Ubuntu 设备上安装 Docker 的完整记录,包含了每一步操作的背后逻辑、我踩过的坑,以及最终稳定运行的配置方案。如果你正准备在 Ubuntu 上部署容器化应用,或者只是想弄清楚 Docker 安装过程中那些“为什么必须这样做”的细节,这篇内容应该能帮你省下不少排查时间。

我默认你的系统是 Ubuntu 20.04 或 22.04 这类 LTS 版本,因为生产环境和日常折腾我都更推荐 LTS,毕竟安全更新周期长,Docker 官方对 LTS 的支持也最稳定。文章里的命令我都实际跑过,但每台机器的硬件、内核、网络环境不同,你执行时如果遇到差异,可以对照最后的排查章节逐项检查。

1. 安装前的环境检查:别急着敲命令

很多人上来就是一条curl -sSL https://get.docker.com | sh,图省事。我不反对这种官方脚本,但如果你想知道系统里到底发生了什么,或者你所在的环境网络受限,脚本式安装会让人很被动。所以我的习惯是:先花两分钟确认系统状态,再手动按步骤装。

1.1 为什么要先确认系统架构和内核

Docker 的安装包依赖 CPU 架构,最常见的是 amd64 和 arm64。树莓派这类 ARM 设备如果用了 x86 的源,装出来的要么报错要么性能异常。确认架构就一条命令:

uname -m

输出x86_64就是 amd64,输出aarch64就是 arm64。后续添加 apt 源的时候,Docker 官方会把架构信息写进源地址,你手动操作时也要保证架构一致。

另一个重要前提是内核版本。Docker 正常运行需要内核支持一些关键特性,比如overlay网络模块和cgroups。Ubuntu 20.04 默认内核是 5.4 以上,完全满足要求。但如果你用的是非常老的内核(比如 3.x),建议先升级系统再装 Docker,否则运行容器时会出现奇怪的挂载错误。

检查内核:

uname -r

看到类似5.15.0-xxx-generic这样的版本就放心继续。

1.2 我常用的几个预检命令

除了架构和内核,我还会顺手检查系统是否已经存在 Docker 痕迹。这一步很容易被跳过,但如果你曾经用旧版本安装过,残留的配置文件可能会干扰新版本。预检命令如下:

which docker dpkg -l | grep -i docker snap list | grep docker

如果which docker有输出,说明已经装过;如果dpkg -l里有docker.io或docker-ce,就需要先卸载。还有一点:Ubuntu 自带的 snap 版本 Docker 有时会悄悄存在,用snap list能看到。我自己就遇到过 snap 版 Docker 和 docker-ce 冲突导致 socket 文件被占用的情况,所以预检这一步不可省。

2. 卸载旧版本与配置官方软件源:干净是成功的一半

这一步看起来像是在做无用功,但恰恰是很多安装失败的根源。Ubuntu 官方仓库里有一个名为docker.io的旧版本包,它和 Docker 官方维护的docker-ce包在文件路径上高度重叠,混装的话,运行docker ps时经常报Cannot connect to the Docker daemon,但实际上服务又没启动。

2.1 清理历史残留的常见坑

如果你像我一样曾经折腾过,建议依次执行:

sudo apt remove docker docker-engine docker.io containerd runc

注意,这个命令只会卸载应用本体,不会删掉/var/lib/docker里的数据。如果你只是想重装系统、所有容器数据都不要了,那可以手动删除这个目录:

sudo rm -rf /var/lib/docker

但这句话请务必谨慎,删除之前想清楚里面有没有你需要的镜像和容器数据。我一般会先把/var/lib/docker压缩备份,再执行清理,这样就算后面遇到问题也有后悔药。

如果用的是 snap 版,卸载命令是:

sudo snap remove docker

2.2 添加官方 Apt 源的完整流程

为什么要用官方源而不是 Ubuntu 自带的源?因为官方源里的docker-ce版本更新快,能及时拿到安全补丁和新特性,而自带源可能停留在很老的版本。添加方式比较固定:

sudo apt update sudo apt install ca-certificates curl gnupg 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

这里有个关键细节:Docker 官方文档要求把 gpg 密钥放到/etc/apt/keyrings目录,并给a+r权限,这样 apt 才能正常读取。如果你以前是用apt-key add方式,那种做法在新版 apt 里会弹出警告,甚至直接拒绝使用。所以我建议直接按上面这版来,干净又正规。

接着是写入源列表。我用的是 Ubuntu 22.04,对应编译代号 jammy。如果你用 20.04 就改成 focal。一条命令写入:

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

lsb_release -cs会自动识别你的系统版本代号,不用手写,省事。执行完记得再跑一次sudo apt update,如果源没问题,更新列表里就会出现docker-ce相关的候选版本。

提示:如果你的网络访问download.docker.com很慢,可以在源地址前加一个国内镜像前缀,比如清华源或阿里云的 Docker 仓库地址。但要注意,镜像站的 gpg 密钥路径不变,只是把域名替换掉。

3. 安装 Docker 引擎与命令行工具:从依赖到 Hello-world

源配置好之后,安装本身反而简单。但我还是想拆开讲一下,因为很多人只抄命令,不明白为什么装这几个包。

3.1 核心包之间的依赖关系

需要安装的包有四个:docker-ce、docker-ce-cli、containerd.io、docker-buildx-plugin以及docker-compose-plugin。其中:

  • docker-ce是 Docker 引擎本体,负责管理容器生命周期;
  • docker-ce-cli是命令行工具,你敲的docker pull、docker run都由它解释;
  • containerd.io是底层容器运行时,引擎通过它真正创建和运行容器;
  • docker-buildx-plugin是构建镜像的扩展,新版构建工具;
  • docker-compose-plugin是 Docker Compose v2 的官方插件,如果你以后想用docker compose up一键启动多容器,这个必须装。

安装命令:

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

如果系统里没有冲突包,这一步会很快。装完不要急着测试,先看一眼服务状态:

sudo systemctl status docker

正常应该是active (running)。如果状态是dead,多半是 swap 分区或 iptables 配置的问题,后面排查章会说。

3.2 安装完成后的第一件事:运行测试容器

我的习惯是跑一个最轻量的 hello-world 镜像,验证整个链路是否通畅。命令很简单:

sudo docker run hello-world

第一次运行会去拉取镜像。如果网络正常,你会看到一段Hello from Docker!的提示,同时容器会运行完自动退出。这一步能确认三件事:引擎能启动、内核能创建容器、网络能拉取镜像。

如果你看到 pull 超时或 connection refused,那大概率是网络问题。常见的临时解决办法是先配置镜像加速,再重新 pull。加速配置写在这个文件里:

sudo mkdir -p /etc/docker sudo nano /etc/docker/daemon.json

填入:

{ "registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"] }

保存后重启 Docker:

sudo systemctl restart docker

之后再跑docker run hello-world,拉取速度会明显改善。这里提醒一句:加速器地址属于第三方,如果你所在环境要求严格,可以选官方源或自己搭建的私有仓库,这个因人而异。

4. 免 sudo 执行 docker 命令:用户组配置的正确姿势

安装完成后的第一件烦心事是:每次敲docker都要带sudo,容易忘,而且会污染日志权限。解决方法是把当前用户加入docker组。

4.1 为什么默认需要 sudo

Docker 引擎其实监听在/var/run/docker.sock这个 socket 文件上,而这个文件的属主是root:docker,权限是srw-rw----。也就是说,只有 root 和 docker 组成员才能读写。如果你当前用户不在 docker 组里,操作系统就不允许你访问,于是 CLI 会报权限不足。

有人说这样设计不安全,我同意。毕竟能访问 docker.sock 就等于能操作宿主机上的容器,能力等同于 root。所以如果你在多人共享服务器上,尽量让管理员而不是所有人加入 docker 组;如果是个人开发机,加入组确实能省很多事。

4.2 配置当前用户加入 docker 组

一条命令搞定:

sudo usermod -aG docker $USER

执行完成后,必须退出当前 shell 再重新登录,或者干脆重启一次系统。因为用户组的新增权限只在新的登录会话中生效,直接继续用旧 shell 还是会提示权限不足。我以前就吃过这个亏,以为命令没生效,折腾半天才发现没重新登录。

验证是否生效:

docker ps

正常情况下会列出一个空的容器列表,不报任何错误。如果依然报permission denied,可以再试一次newgrp docker命令,这个命令会临时切换当前会话的主组,也能让权限生效,不过后续终端要重新开启才能永久保持。

5. 实测中的常见问题与我的排错思路

再顺手的安装流程,在真实环境里也会遇到幺蛾子。这里把我在不同 Ubuntu 版本上安装 Docker 时遇到的三个典型问题整理出来,每个都附上完整排查过程,希望能帮你省掉瞎试的时间。

5.1 网络超时与镜像加速的取舍

现象:执行sudo docker pull时一直卡在Waiting或直接Get "https://registry-1.docker.io/v2/": net/http: request canceled。

我当时的排查顺序是:先ping google.com测网络通断,再用curl -I https://download.docker.com测官方下载源,最后发现是默认的 Docker Hub 拉取超时。

解决方案是给 daemon 配置镜像加速,也就是前面提过的daemon.json。但这里有个细节值得注意:加速器只能加速镜像仓库的拉取,不会加速你docker build时从 GitHub 下载源码的过程。如果 build 阶段超时,那是网络问题,和 Docker 无关,得从代理或 DNS 角度解决。

我在配置daemon.json时只填一个加速器,避免多个源互相切换导致拉取缓存不一致。另外写完后一定要用这个命令验证 JSON 格式:

sudo docker info | grep -A2 "Registry Mirrors"

看到你自己的加速器地址就说明配置生效了。格式错误的话,Docker 会直接拒绝启动,日志里会报Error parsing daemon.json。

5.2 存储驱动与 overlay2 的注意事项

现象:容器运行时报error creating overlay mount ... /var/lib/docker/overlay2: invalid argument。

这个问题一般出现在特定文件系统上。Docker 默认推荐的存储驱动是overlay2,但前提是宿主机文件系统是 ext4 或 xfs,且开启了 d_type 支持。如果你的系统盘或者数据盘是 btrfs、zfs 或网络文件系统(NFS),overlay2 可能没法正常工作。

我遇到过一次是在 NFS 挂载的目录上安装 Docker,当时怎么跑都报错。排查完才发现/var/lib/docker默认位于根目录,而根目录被挂载成 NFS。解决办法是把 Docker 的数据根目录改到本地磁盘,在daemon.json里加一行:

{ "data-root": "/data/docker" }

之后sudo systemctl restart docker,再用sudo docker info确认Docker Root Dir已经是新路径。这种方法对数据量大的场景也比较友好,毕竟系统盘空间有限,把容器数据放到独立数据盘确实更稳妥。

还有一点是磁盘空间不足。Ubuntu 默认的/var/lib/docker分区如果只有 20G,拉几个常用镜像就满了。建议安装前检查df -h,如果空间紧张,提前改>sudo systemctl enable docker sudo systemctl start docker

另外我养成了一个习惯:每半个月检查一次 Docker 和插件的更新。Ubuntu 的 apt 源里既然配了 Docker 官方源,直接sudo apt upgrade就会把docker-ce和containerd.io一起更新。更新前先备份当前运行的容器列表,用docker ps -a > containers-backup.txt记录一下,再执行升级。实测下来,Docker 的升级通常不会中断正在运行的容器,但保险起见,重要服务我都会提前踢下线。

以上就是我在 Ubuntu 上安装 Docker 的完整记录。从环境预检、源配置、核心组件安装,到用户组调整和常见问题排查,每一步都有对应的原因和验证方式。我在实际使用中的体会是:与其追求一键脚本的快捷,不如花十分钟理解安装过程中涉及的几个关键点,这样遇到异常时才能真正对症下药,而不是反复重装系统。希望这篇记录能帮你省掉一些弯路,如果你在安装过程中碰到其他奇奇怪怪的问题,欢迎带着报错信息来交流。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进