☰
Ubuntu安装Docker实战指南:从GPG密钥到镜像加速的完整排障手册
2026/10/14 4:28:25 网站建设 项目流程

在Ubuntu上装Docker,是个典型的“看着简单、动手复杂”的操作。官方文档把流程写得清清楚楚,实际执行时却总有人在GPG密钥、软件源、用户权限、镜像拉取这些环节上卡壳。我从Ubuntu 18.04一路用到24.04,在本地虚拟机、云服务器、公司内网机器上都装过Docker,也帮朋友排查过不少安装现场。这篇文章把一套完整、可靠、出了问题知道怎么退的流程整理出来,顺便把那些文档里语焉不详的细节一次说清楚。

这里说的Docker是Docker Engine,也就是社区版引擎,不是Docker Desktop。Linux服务器上需要的是前者,Desktop版是给macOS和Windows桌面系统用的,装在Ubuntu服务器上反而多余。文章适合刚接触Ubuntu的新手,也适合装过Docker但一直被各种报错折磨的老手,照着做能少走不少弯路。

1. 安装前的准备工作

1.1 确认系统版本与架构

我习惯在任何机器上动手安装之前,先花两三分钟确认系统信息。网上很多报错案例,最后查下来都是安装前没看系统版本,导致软件源里写了一个不存在的系统代号,apt直接找不到Release文件。

cat /etc/os-release

这条命令会输出系统名称、版本号和版本代号。比如Ubuntu 22.04的代号是jammy,24.04的代号是noble。稍后配置Docker软件源时需要用到这个代号,它是apt下载地址的一部分。如果代号写错,整个源就废了,安装时会提示找不到对应的Release文件。

接着查看CPU架构:

uname -m dpkg --print-architecture

前者看内核架构,后者看apt包管理器识别的架构。x86_64机器上通常分别是x86_64和amd64,ARM机器上会显示aarch64和arm64。Docker官方支持amd64、arm64等主流架构,只要不是i386这类老32位架构,基本都能正常安装。继续看一下内核版本:

uname -r

Docker对内核的最低要求是3.10,Ubuntu 20.04之后内核普遍在5.x以上,这步只是走个过场。如果用的是很老的Ubuntu版本,内核太旧会直接影响容器运行时的兼容性,我一般建议直接升级系统,而不是在老内核上硬装。

1.2 清理旧版本与相关残留

检查一下机器上是不是已经装过Docker相关组件:

which docker docker --version dpkg -l | grep -i docker

如果之前用Ubuntu自带的软件源装过docker.io,或者手工装过旧版Docker,建议先卸载再装新版。Ubuntu软件源里的docker.io版本更新偏慢,而且默认不包含buildx、compose插件这些新特性。我见过有人先装了docker.io,过了几个月想用docker compose发现命令不存在,然后陷入“我明明装了Docker”的困惑。要清理旧版本,执行:

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

这条命令只移除软件包,不会动/var/lib/docker目录里的镜像和容器数据,可以放心执行。如果机器上还运行着跟容器相关的服务,卸载前建议先sudo systemctl stop docker停掉服务,避免文件占用导致卸载不干净。接下来先更新一次apt索引并安装基础依赖:

sudo apt update sudo apt install -y curl ca-certificates

ca-certificates这个包很容易被忽略,少了它,后续用curl下载Docker的GPG密钥时可能直接报证书校验失败。先装上,后面省得返工。

2. 配置Docker软件源

2.1 添加官方GPG密钥

很多人不理解为什么装个软件还要先配密钥。apt包管理器在安装软件时会校验软件源的签名,确保下载到的包确实来自官方、没有被篡改。这一步配的就是Docker官方软件源的信任凭证。

老教程里常见的做法是curl ... | sudo apt-key add -,但apt-key在Ubuntu 22.04之后已经明确废弃,全局信任所有用apt-key添加的密钥,既不安全也难管理。现在官方推荐的做法是把密钥文件下载到/etc/apt/keyrings目录,并在软件源条目里用signed-by参数显式指定,这样每个源只信任自己声明的密钥文件。

sudo apt-get update sudo apt-get install -y ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc

我来拆一下命令。install -m 0755 -d是创建目录并设置权限,0755表示属主可读写执行、其他用户可读可执行,目录创建后apt才有地方放密钥文件。curl -fsSL分别表示静默失败、静默进度、显示错误、跟随重定向,如果下载超时会直接报错而不是卡在那里装死。下载完成后必须chmod a+r,让所有用户都能读这个密钥文件,否则apt运行在非root用户上下文时可能因为读不到密钥而误报签名错误。

2.2 写入apt软件源

密钥准备妥当后,把软件源写入apt的源列表:

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

这条命令里有几个自动化的关键点。arch=$(dpkg --print-architecture)会自动填入当前机器的架构,省得手写amd64或arm64。signed-by指向刚才下载的密钥文件。$(. /etc/os-release && echo "$VERSION_CODENAME")会读取系统版本代号并自动拼进源地址,这样换机器时不用手动改代号。最后通过tee把内容写入/etc/apt/sources.list.d/docker.list,> /dev/null用于屏蔽输出。

写完后跑一下apt update,让软件源生效:

sudo apt-get update

这一步如果没报错,说明源已经通了。如果看到Release文件不存在的报错,多半是版本代号有问题,往下看到第7章的排障部分。

2.3 软件源镜像替换建议

如果你所在的网络环境访问download.docker.com速度比较慢,curl下载密钥或者apt update可能反复超时。这种情况下,最实用的办法是使用国内云厂商提供的Docker软件源镜像。

做法很简单:把上面源地址里的https://download.docker.com整体替换成云厂商提供的镜像地址,保留后面的/linux/ubuntu路径结构不变。具体地址要去你所用云厂商的软件源文档里查,格式通常是类似https://<镜像服务域名>/docker-ce/linux/ubuntu这样的完整URL。比如在一台云服务器上装,厂商控制台的软件源页面一般会直接给出可复制的地址,照抄就行。

提示:换源后出现“证书校验失败”的报错,先确认ca-certificates已经安装,再看系统时间是否准确。证书校验依赖系统时间,机器时间偏差过大也会导致握手失败。

3. 安装Docker引擎与常用组件

3.1 用apt安装Docker

软件源配好后,安装就变得很简单:

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

这里一次装了五个包,它们的职责不同,我列个表说明:

包名作用
docker-ceDocker引擎主程序,负责容器生命周期管理
docker-ce-cli命令行工具,执行docker命令时依赖它
containerd.io容器运行时,真正负责创建、启动、销毁容器
docker-buildx-plugin镜像构建插件,支持多架构构建等高级能力
docker-compose-plugin官方Compose v2插件,多容器编排必备

为什么一次性装齐而不是只装docker-ce?很多教程只装主程序,后面要用docker compose时才发现没有这个命令,再回头补装,纯属浪费时间。装了compose插件后,直接用docker compose而不是老式的docker-compose,命令格式也更简洁。

安装完成后可以先看版本确认一下:

docker --version docker compose version

3.2 启动服务与设置开机自启

Ubuntu上Docker安装完,服务不一定会自动处于运行状态,建议手动启动并设置开机自启:

sudo systemctl enable --now docker systemctl status docker

enable --now是enable和start的合并操作,一条命令完成“开机自启”和“立即启动”。status输出里看到Active: active (running)就说明服务正常。如果状态不是running,用这个命令看日志:

journalctl -u docker -n 50 --no-pager

日志会直接说明docker守护进程为什么起不来,最常见的原因就是daemon.json的JSON格式写错——这个问题在后面的排障章节还会详细说。

3.3 验证安装:跑一个hello-world

验证Docker是否真的能用,最经典的方式是拉一个hello-world镜像并运行:

sudo docker run hello-world

这条命令的执行流程是:docker先检查本地有没有hello-world镜像,没有就按配置的镜像源去拉取,拉取成功后创建一个临时容器,容器启动后会打印一段“Hello from Docker!”的提示信息。看到这段输出,说明引擎、运行时、镜像拉取链路都是通的。

如果卡在这一步报网络超时,别着急,这不会影响Docker本身的安装质量,只是说明Docker Hub拉取路径不太顺畅,下一步配好镜像源后重试即可。

4. 让镜像拉取不再超时的配置

4.1 为什么容器镜像需要镜像源

Docker Hub是Docker默认的公共镜像仓库,但它的服务器部署在海外,直接拉取时,小镜像要等很久,大镜像经常拉到一半断开。这个问题在云服务器上尤其明显,几乎每个刚装完Docker的人都会遇到。

Docker为此提供了一种叫作registry-mirrors的机制。简单理解,就是给镜像仓库配一个“本地分诊站”:拉取镜像时,Docker会优先去你指定的镜像源地址查询,如果那台服务器已经缓存了对应镜像,就直接从那里拉取,速度会有明显改观。这属于Docker官方支持的常规配置,不需要改变网络链路的任何环节,机器还是走普通的网络连接。

4.2 获取专属镜像源地址并写入daemon.json

先确认你已经有一台可以访问的镜像源服务器。如果你用的是某家云厂商的云服务器,通常可以在它的控制台里找到“容器镜像服务”相关入口,进去后一般能看到一个“镜像源”或者类似命名的页面,系统会为你生成一个专属地址,形如https://xxxx.mirror.xxx.xxx。如果只是本机实验环境,也可以直接搜索“Docker镜像源”找公开可用的地址,但优先使用你自己所属云平台提供的地址,速度和可靠性都有保障。

拿到地址后,编辑Docker守护进程的配置文件:

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

写入如下内容:

{ "registry-mirrors": ["https://<你的专属镜像源地址>"] }

注意,json格式非常严格,最后一个键值对后面不能有多余的逗号,字符串要用英文双引号包裹。写错一个符号,docker服务都起不来。写完建议先cat /etc/docker/daemon.json看一眼再重启。

4.3 重启Docker并验证配置

修改daemon.json后需要重载配置并重启docker服务:

sudo systemctl daemon-reload sudo systemctl restart docker

daemon-reload是让systemd重新读取服务配置,不是必须但对避免干扰有好处。重启后验证一下配置是否生效:

docker info | grep -A 2 "Registry Mirrors"

输出里能看到你填写的镜像源地址就说明生效了。这时候再执行一次docker run --rm hello-world,拉取速度正常情况下要比刚才快得多。如果依旧超时,检查是不是地址写错,或者该镜像源本身服务不稳定,换一个再试。

5. 安装后的权限、日志与存储优化

5.1 免sudo执行docker命令

安装完Docker后,默认只有root用户能直接使用docker命令。普通用户执行docker ps会报“permission denied”错误。每次都加sudo太影响体验,更省心的做法是把当前用户加入docker用户组:

sudo usermod -aG docker $USER newgrp docker docker ps

usermod -aG把用户追加到docker组,newgrp docker是让当前终端立即刷新用户组身份,省掉一次重新登录。执行完docker ps能看到空的容器列表,说明权限已经正常。

安全提示:能操作docker的用户实际上等同于拥有root权限,因为docker socket可以直接操作宿主机文件系统。生产环境千万别随便把不信任的人加入docker组,一旦加入他就是变相root。

5.2 给日志加上限,别让磁盘悄悄爆掉

很多刚上手的人不知道,容器默认的日志驱动是json-file,会一直往宿主机写日志文件。如果容器日志输出量很大,一个月就能把磁盘填满。这几乎是Docker最常见的磁盘隐患。

我的习惯是装完Docker后立刻在daemon.json里加上日志限制:

{ "registry-mirrors": ["https://<你的专属镜像源地址>"], "log-driver": "json-file", "log-opts": { "max-size": "50m", "max-file": "3" } }

max-size设置单个日志文件的最大体积,50m表示达到50MB就滚动;max-file设置最多保留的日志文件数,3个就是最多150MB。改完后重启docker:

sudo systemctl restart docker

注意这个配置只对新创建的容器生效,已经存在的容器还是在用旧配置。如果机器上已经有很多容器且日志失控,可以临时清空一下:

find /var/lib/docker/containers -name "*-json.log" -exec truncate -s 0 {} \;

这条命令会把所有容器日志文件清空,属于救急手段,执行前请评估是否还需要保留日志。

5.3 数据目录迁移到大数据盘

默认情况下,Docker的镜像、容器、数据卷都放在/var/lib/docker。如果系统盘分区比较小,很快会被镜像撑爆。把数据目录迁移到大容量数据盘是生产环境很常见的操作。

步骤如下:

  1. 先停掉docker服务:sudo systemctl stop docker
  2. 准备新目录,比如sudo mkdir -p /data/docker
  3. 把原有数据整体同步到新目录:sudo rsync -avz /var/lib/docker/ /data/docker/
  4. 在daemon.json里加上data-root配置:"data-root": "/data/docker"
  5. 执行sudo systemctl daemon-reload && sudo systemctl restart docker
  6. 验证:docker info | grep "Docker Root Dir",看到路径变成/data/docker即成功

这里我不建议直接mv加ln -s软链接,虽然能凑合用,但systemd管理下路径混乱容易出奇怪问题,直接在daemon.json里声明data-root最干净,升级也不会被覆盖。另外,不要把data-root放在NFS或者性能差的网络盘上,容器运行时I/O压力很大,网络盘会成为整个系统的瓶颈。

6. 升级、卸载与备份迁移

6.1 升级Docker组件版本

Docker版本更新很快,升级操作也不复杂:

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

升级完成后跑一下docker version,确认client和server两栏都已经是新版本。如果出现client和server版本不一致的警告,通常是因为docker服务没有重启,重启一下就好。

生产环境追求稳定,我一般建议锁版本,防止apt upgrade时不小心把Docker升了:

sudo apt-mark hold docker-ce docker-ce-cli containerd.io

需要解除锁定升级时再unhold:

sudo apt-mark unhold docker-ce docker-ce-cli containerd.io

6.2 彻底卸载Docker

卸载Docker也是门学问。只remove docker-ce是不彻底的,containerd还在运行,/var/lib/docker目录里的数据还占着磁盘,重新安装后新旧残留混在一起很容易出问题。彻底卸载的做法:

sudo systemctl stop docker sudo apt purge -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo rm -rf /var/lib/docker sudo rm -rf /var/lib/containerd sudo rm -f /etc/apt/sources.list.d/docker.list sudo rm -f /etc/apt/keyrings/docker.asc

需要特别提醒:删除/var/lib/docker和/var/lib/containerd会把所有镜像、容器、数据卷一并清空。如果里面有要保留的东西,先按下一小节做好备份,别直接删。

6.3 把镜像和容器数据备份带走

如果你要换机器或者重装系统,最想带走的是自定义镜像、容器配置、持久化数据。

镜像备份用docker save。把本机所有镜像打成一个tar包:

docker save -o myimages.tar $(docker images -q)

还原时执行:

docker load -i myimages.tar

容器配置建议用docker compose管理的项目直接备份整个项目目录,包含docker-compose.yml和env文件,到新机器上直接docker compose up -d就能恢复整套服务。单容器场景用docker ps -a导出一份容器列表,再结合镜像备份,基本能还原。

持久化数据是最容易遗忘的部分。用bind mount或者volume挂载的数据,数据其实在宿主机上,备份时要把挂载目录一起拷走。没做挂载的容器数据都在容器可写层里,容器一删就没了,这种情况需要先用docker cp拷贝出来。

7. 实际排障经验与常见问题速查

7.1 apt源相关的报错

安装过程中如果报Release文件不存在、GPG签名错误、证书校验失败,基本都是源配置环节的问题。我把常见报错整理成一张速查表:

报错信息可能原因解决办法
The repository ... does not have a Release file系统代号写错,或该版本官方源没有对应版本检查/etc/apt/sources.list.d/docker.list的内容,确认代号与cat /etc/os-release一致
GPG error: ... public key not available密钥文件缺失或未正确导入重新下载密钥到/etc/apt/keyrings/docker.asc,执行chmod a+r后apt update
Certificate verification failedca-certificates未安装,或系统时间偏差过大安装ca-certificates,用date检查系统时间并校准

我遇到过一种很隐蔽的情况:系统从老版本升级上来后,/etc/os-release里的VERSION_CODENAME还是旧版本代号,配置源时手一抖就写错了。后来固定用自动化那段shell命令生成源,彻底避免手写代号出错。

7.2 Docker服务与权限报错

刚装完Docker后最常见的两个报错,一个是连不上守护进程,一个是权限不足。

报错信息可能原因解决办法
Cannot connect to the Docker daemon ... Is the docker daemon running?docker服务没启动,或daemon.json格式错误导致启动失败systemctl status docker查看状态;journalctl -u docker -n 50看日志
Got permission denied while trying to connect to the Docker daemon socket当前用户不在docker组,或组身份未刷新sudo usermod -aG docker $USER,然后newgrp docker或重新登录

第一种报错里,daemon.json的JSON解析错误是最阴的。docker服务起不来,systemctl status只提示失败,真正原因要翻journal日志才能看到,里面一般会直接指出某个字符位置的多余逗号。所以每次改daemon.json我都习惯先用python3 -m json.tool /etc/docker/daemon.json校验一下,再重启服务。

7.3 镜像拉取和磁盘问题

运行阶段的高频问题集中在镜像拉取和磁盘空间上。

报错信息可能原因解决办法
Get https://registry-1.docker.io/v2/: ... timeout镜像源未配置,或配置地址不可用检查daemon.json的registry-mirrors,重启docker后重试
failed to register layer: no space left on device磁盘分区已满,或inode耗尽df -h和df -i查看磁盘与inode使用率;docker system prune -af --volumes清理
Error response from daemon: pull access denied镜像名拼写错误,或私有镜像未登录核对镜像名;私有仓库先docker login登录

磁盘满的情况要特别警惕:df -h看不出问题但容器仍然报no space,很可能是inode用尽。检查命令用df -i,inode耗尽通常是因为大量小文件堆积,最典型的场景就是容器日志文件过多。清理磁盘时有个实用命令组合:

docker system df docker system prune -af --volumes

docker system df先看什么占了空间,prune -af --volumes一键清理所有停止的容器、未使用的网络、悬空镜像、未被引用的数据卷。注意prune会删数据,执行前确认没有需要保留的东西。

我个人的实际体会是,Docker安装链条上真正影响体验的往往不是安装本身,而是安装前后那几个小配置。这两年我装完Docker后的第一件事永远是改daemon.json,把镜像源、日志限制、数据目录一次性写完再重启,等于把后面几个月要踩的坑提前填平。后来有几次图省事直接用默认配置跑测试机,结果日志一次吃掉40G磁盘,教训相当深刻。

最后再分享一个经验:升级Docker前一定先看一眼官方变更说明,升级后第一时间docker version确认client和server版本一致,避免出现版本不匹配的诡异问题。按照这篇流程走一遍,Docker的安装、使用、排障基本都能心里有底。祝少踩坑。

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

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

立即咨询