装 Docker CE 这事,看起来就是复制几条命令的事,但真到生产服务器上操作,你会遇到仓库连不上、GPG 校验失败、SELinux 拦路、存储驱动不对这类七七八八的问题。Ubuntu 和 CentOS 两套流程虽然最终都装的是同一个 Docker,但因为包管理器、系统初始化机制、安全模块的差异,很多细节必须分开处理。这篇文章就把两套安装流程完整走一遍,从装之前的系统检查、软件源配置,到安装后的验证和坑点排查,每一步都会给出实际命令和判断方法,适合准备给 Linux 服务器搭建容器环境、又不想反复踩坑的同学直接参考。
1. 安装前先搞清楚:为什么选 Docker CE,环境的坑在哪
1.1 社区版和企业版怎么选,顺手说说哪些版本不要碰
Docker 的引擎版本分成两类:Docker CE 社区版和 Docker EE 企业版。CE 是免费、开源、由社区维护的版本,功能上已经涵盖日常开发和绝大多数生产需求,容器运行、镜像构建、Compose 编排、网络管理这些核心能力都有。EE 主要是面向企业客户,附加了镜像安全扫描、集中管控、商业支持这些东西,普通团队基本用不上。
除了这两类,还有几个容易踩的坑。很多 Linux 发行版自带的软件源里有一个叫docker.io的包,那是发行版维护者自己打的旧版 Docker,版本往往落后官方一大截,我见过不少机器装了它之后,连新版docker compose的 v2 语法都不支持,后面迁回官方版时还得先清理干净。另外 Ubuntu 上还有一种通过 Snap 安装 Docker 的方式,安装确实快,但 Snap 对文件路径做了隔离,容器挂载目录、systemd 集成这些环节容易出现莫名其妙的问题,生产环境也不建议用。所以这篇文章的安装方式统一走官方软件源,也就是 Docker 官方维护的 apt/yum 仓库。
1.2 安装之前的四个硬性检查:内核、架构、包管理器、旧包残留
装 Docker 之前,我建议先花一分钟确认系统环境,别上来就复制粘贴命令。第一条是内核版本。Docker 的存储驱动默认用overlay2,它对内核版本有要求,一般建议内核 3.10 以上,新一些的发行版内核都在 4.x、5.x、6.x 了,没什么问题。CentOS 7 默认的 3.10 内核也能跑 overlay2,但要注意系统需要加载相关模块,这个后面排错部分会提到。
第二条是系统架构。Docker CE 官方支持 amd64、arm64、armhf 这些常见架构,但 32 位系统基本不用想了。可以用uname -m看一下,输出x86_64就说明是 64 位。第三条是包管理器的选择,Ubuntu 走 apt,CentOS 走 yum,命令和软件源格式完全不同,这也是我把两套流程拆开写的原因。第四条是检查机器上有没有装过旧的 Docker 包,如果以前用其他渠道装过,最好先卸载再装新版本,避免新旧文件混在一起,后面启动时各种冲突。
1.3 软件源和 GPG 密钥的作用:这一步省掉后面一堆麻烦
Docker 官方软件源的作用不用多说,就是告诉系统从哪里下载 Docker 的安装包。GPG 密钥的作用很多人容易忽略,它是用来验签的,确保你下载的软件包确实来自 Docker 官方,而不是某个中间源被污染后塞给你的恶意包。早期教程喜欢用apt-key add来导入密钥,但这个方式在新版本 apt 中已经标记为废弃,现在推荐的做法是把密钥文件存到/usr/share/keyrings/目录,然后在软件源配置里用signed-by参数指定它,这套机制更安全,也符合现代 Debian/Ubuntu 的实践。
安装 Docker 的过程其实就是三条主线:准备软件源、安装核心包、启动并验证服务。把这三条线理解了,Ubuntu 和 CentOS 的差异就只剩命令长什么样的问题了。
2. Ubuntu 装 Docker CE 完整步骤(apt 源 + GPG 校验)
2.1 先清掉旧 Docker,别让残留包搞乱依赖
如果你不确定机器上之前装没装过 Docker,我的建议是先把旧包卸载一遍。Ubuntu 上这个命令是:
sudo apt remove docker docker-engine docker.io containerd runc这个命令会把常见的旧版 Docker 相关包清掉,即使有些包不存在,apt remove也不会报错,它会正常继续。有一点要注意:卸载不会删除/var/lib/docker目录,这里面是历史的镜像层、容器文件系统、卷数据。如果你确定这些数据都不需要了,可以在卸载之后手动删除:
sudo rm -rf /var/lib/docker如果你是在老机器上升级 Docker,这个目录里可能存着重要业务的旧镜像,删除之前一定要确认。我见过有人清理旧包后习惯性把整个 Docker 数据目录删了,结果线上镜像全没了,只能重新构建。卸载和删数据是两件事,脑子要清醒。
2.2 安装依赖包并导入官方 GPG 密钥
接下来安装几个必需的依赖工具。Ubuntu 上这条命令:
sudo apt update sudo apt install -y ca-certificates curl gnupg lsb-release这里curl用来下载密钥,gnupg提供gpg命令来处理密钥文件,ca-certificates保证 HTTPS 证书校验能正常走通,lsb-release里的lsb_release命令后面要用来获取系统版本代号。缺了任何一个,后面的命令都可能卡住。
导入 Docker 官方 GPG 密钥并保存成二进制格式:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpgcurl的-fsSL这几个参数别去掉。-f让 curl 在返回 HTTP 错误时不往下执行,不然你可能会把一个错误提示页面的内容当成密钥文件导入,后续安装时验签报错;-sS是静默模式但保留错误输出;-L是跟随重定向。我见过有人精简参数后,导入密钥那一步花式报错,花了好久才反应过来是参数少了。
2.3 写入 apt 源并安装 Docker 核心组件
接下来把 Docker 官方仓库写进 apt 源列表。这里有一个好习惯:用dpkg --print-architecture自动获取当前系统架构,用lsb_release -cs获取系统版本代号,这样写出的命令在不同 Ubuntu 版本上都能直接用,不用手动替换:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.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-plugindocker-ce是 Docker 引擎本体,包括后台守护进程dockerd和命令行工具docker;docker-ce-cli是命令行客户端;containerd.io是底层的容器运行时,负责真正创建和管理容器进程;docker-buildx-plugin是新版镜像构建工具 Buildx;docker-compose-plugin是 Compose 编排插件。如果你只装了docker-ce,后面会发现docker compose命令根本不存在,所以这几个插件一起装上最省事。
2.4 启动服务并验证安装是否成功
安装完成后不会有弹窗提示你服务已启动,但 Ubuntu 上 Docker 包一般会自动把 systemd 服务文件放好并启动守护进程。可以用下面的命令确认:
sudo systemctl is-active docker sudo docker run hello-world如果输出active,并且hello-world容器能正常打印出信息,说明安装成功。这中间如果出现Cannot connect to the Docker daemon,先看服务状态,多半是 dockerd 没起来,原因五花八门,后面第五部分会展开排查。
最后还要做一步:把当前用户加进docker组,这样就不必每次敲命令都带sudo:
sudo usermod -aG docker $USER执行完这一步一定要重新登录,或者干脆重启一次终端会话。如果不重新登录,当前会话的权限缓存里还没有你加入 docker 组的记录,敲docker ps照样报 permission denied。这是一个非常容易让人误判是安装出问题的小坑。
3. CentOS 装 Docker CE 完整步骤(yum 源 + systemctl 管理)
3.1 确认 CentOS 版本和生命周期状态,再清理旧包
CentOS 和 RHEL 系的仓库管理走 yum(CentOS 8 也可以走 dnf),先把系统版本确认了:
cat /etc/centos-release如果显示 7.x,那就用 yum 走下面的流程。如果显示 8.x,要留个心,CentOS 8 已经结束维护了,我建议这类机器尽快迁移到兼容的替代发行版上,安装 Docker 的流程和 CentOS 7 几乎一样,但系统的安全更新已经停了,继续跑生产是很有风险的事情。如果你手上还有这类老系统,后续换系统时 Docker 的数据目录/var/lib/docker是可以整体搬走的,这一点在准备迁移时很有用。
照例先清旧包:
sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine3.2 安装 yum-utils 并写入 Docker 官方 yum 源
CentOS 配置软件源需要先装一个yum-utils,里面提供了yum-config-manager命令,这个命令可以一键把 Docker 官方仓库写入系统:
sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo执行完第二条命令后,/etc/yum.repos.d/docker-ce.repo文件就出现了。如果yum-config-manager找不到,说明yum-utils确实没装上,先检查那一步是否报错。CentOS 8 上如果默认没有yum-config-manager,同样用yum install yum-utils解决。
然后安装 Docker 组件,和 Ubuntu 那边的包名几乎一样:
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin这里 yum 会自动处理依赖关系,过程会比 apt 稍慢一点,耐心等它跑完就行。
3.3 systemd 启动、开机自启和安装后的验证
CentOS 和 Ubuntu 一个明显的差异是,Docker 安装完成后服务不会自动启动,必须手动用 systemd 把它拉起来。一条命令同时完成启动和配置开机自启:
sudo systemctl enable --now dockerenable是设置开机自启,--now表示立即启动服务,加减号一举两得。以前有些教程让你先systemctl start docker再systemctl enable docker,其实用enable --now一条就够了。启动后验证版本,确保客户端和服务端都能正常看到:
docker version docker infodocker version会输出 Client 和 Server 两段信息。如果只有 Client,没有 Server,说明守护进程没有正常启动或者你当前用户访问不了 socket,先去查服务状态。docker info能看到更详细的环境信息,存储驱动、容器数量、系统内核这些都在里面。
3.4 SELinux 与 firewalld:生产环境最常翻车的地方
CentOS 默认开启 SELinux,很多人在 CentOS 上装完 Docker 跑容器,结果遇到权限错误,第一反应就是关 SELinux。我的建议是:不要一上来就setenforce 0,SELinux 本身和 Docker 是兼容的,Docker 官方在 RHEL/CentOS 上做了大量适配工作,正常情况下不需要关闭。如果你是因为某个容器挂载了宿主机目录而报 permission denied,可以查一下/var/log/audit/audit.log里有没有avc denied记录,如果确认是文件上下文问题,用这条命令给挂载目录打上容器文件标签:
sudo chcon -Rt container_file_t /你的挂载路径另外,CentOS 的 firewalld 和 Docker 的 iptables 规则可能会互相影响。Docker 在启动容器时会把规则插入 iptables,而 firewalld 也在管理 iptables,两者配合不好时可能出现容器间网络不通、端口映射失败等问题。遇到这类情况,先看 firewalld 状态,再查看当时的 iptables 规则,确认 Docker 创建的链是否被其他规则干扰了。直接systemctl stop firewalld是一种常见的临时手段,但生产环境我建议还是搞清楚是谁在冲突,毕竟防火墙关了你的服务可能直接暴露到外网。
4. 装完别急着跑:验证容器、基础配置与生产级细节
4.1 hello-world 验证全链路:本地没镜像时会发生什么
很多新手执行完docker run hello-world看到一大段英文输出后,也不知道这算成功还是失败。其实这个镜像是 Docker 官方设计的一个极简测试镜像,它本身只做一件事:打印一段欢迎信息。关键不是这段文字说了什么,而是这个过程验证了什么。运行命令时,Docker 客户端会去连接守护进程,守护进程发现本地没有hello-world镜像,就会去远程仓库拉取,拉完创建容器,启动进程,打印输出,退出。整条链路:客户端权限、守护进程、镜像拉取、容器运行时、进程隔离,全都会在这条命令中走一遍。能成功跑完,说明安装基本靠谱。
如果卡在拉镜像那一步,多半是网络问题,解决办法在 4.3 节的镜像加速里,先把加速配置好再跑验证。
4.2 docker info 里的三个关键字段,新手最容易忽略
安装完别急着关终端,执行一下docker info,重点关注几个字段。第一个是Storage Driver,正常情况下应该是overlay2,这是 Docker 推荐的高性能存储驱动,镜像层可以共享,启动容器快,写操作直接落在文件系统上,效率高。如果显示vfs,说明内核模块支持有问题,Docker 被迫降级使用了最原始的存储方式,性能差得离谱,这种情况不要继续用,去查内核和 overlay 模块。第二个是Cgroup Driver,在主流系统上是systemd,这表示容器资源控制通过 systemd 统一管理。第三种情况是cgroupfs,在老版本 Docker 或特殊配置下会出现,混用两种 cgroup 驱动在整机跑多容器时容易出问题。第三个是Logging Driver,一般是json-file,后面配置日志上限时改的就是它。
想快速过滤某个字段,可以用 Go 模板:
docker info --format '{{.ServerVersion}} {{.Driver}} {{.CgroupDriver}}'4.3 镜像加速与 daemon.json 配置:下载提速的通用做法
在国内环境使用 Docker,镜像拉取慢是逃不开的问题。官方仓库在国外,直接拉一个小镜像可能几百 KB 都能卡半天。通用解法是在 Docker 守护进程配置里加上镜像加速器,镜像加速器一般由各大云厂商提供。修改配置文件/etc/docker/daemon.json,如果文件不存在就新建,内容大概是这样的结构:
{ "registry-mirrors": ["https://你的加速地址"] }改完重启 Docker 生效:
sudo systemctl restart docker这里有个常见的配置错误:文件内容如果是空的{},Docker 会当成没有额外配置来读,但如果你把 JSON 写错了,比如少了逗号或多了注释,Docker 守护进程可能直接启动失败。改完配置文件后先执行sudo systemctl restart docker,然后马上docker info看看有没有报错,别等跑容器时才发现。加速器的地址要选择当前可用的,网上很多年初还能用年底就失效的地址,直接用错了反而是浪费时间。
4.4 生产环境进阶:日志上限、存储路径迁移、开机自启
线上环境用 Docker,有两件事我建议装完就做。第一是限制容器日志大小。Docker 默认会把容器写出来的标准输出和标准错误都存成 json-file 日志,而且不设上限,如果有个容器疯狂打日志,/var/lib/docker/containers下的文件能涨到几个 GB,最后把整块磁盘塞满。在daemon.json里加日志上限配置:
{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }这样单个容器日志最大 10 MB,保留 3 个文件,滚出来的老日志自动删掉,磁盘压力会小很多。
第二是如果根分区空间不大,我建议把 Docker 的数据目录迁到大磁盘上。Docker 默认数据目录是/var/lib/docker,如果你的系统盘只有 40 GB,随便拉几个大镜像就满了。迁移步骤不复杂:先把 Docker 服务停了,把数据整个复制到新目录,然后改daemon.json里的>{ "data-root": "/data/docker" }
实际迁移命令:
sudo systemctl stop docker sudo rsync -avxP /var/lib/docker/ /data/docker/ sudo systemctl start docker迁移完成后先确认原来目录里的镜像在docker images里还能看到,再考虑清理旧目录。rsync 过程中不要中断,否则数据不一致,Docker 启动后可能报错。
至于开机自启,Ubuntu 上 Docker 包一般装完就默认开了,CentOS 上通常需要手动执行一次sudo systemctl enable --now docker。装完之后可以顺手确认一下:
sudo systemctl is-enabled docker输出enabled就说明开机自启已经配置好了。
5. 实战排错速查表:我踩过的 Docker 安装故障
5.1 Cannot connect to the Docker daemon 这类启动问题
这个报错是安装后最常遇到的,出现时先不要怀疑命令敲错了,基本方向是守护进程没有正常监听。第一步看服务状态:
sudo systemctl status docker sudo journalctl -u docker -n 50 --no-pagersystemctl status会显示当前服务是否 active (running),如果显示 failed,journalctl里基本会有堆栈信息,照着错误往下查。如果你是非 root 用户,报错内容是permission denied while trying to connect to the Docker daemon socket,这其实和守护进程没关系,就是当前用户不在docker组里,重新执行sudo usermod -aG docker $USER并重新登录即可。
5.2 下载超时、仓库连接失败、镜像拉取卡住
这类问题在网络层面表现多种多样,有的是apt update时连接download.docker.com超时,有的是docker pull卡在waiting。先做基础判断,执行curl -I https://download.docker.com看能不能正常访问,如果能访问但很慢,说明是网络到国外站点延迟高,这时候就配镜像加速器。如果是 DNS 解析失败,看一下cat /etc/resolv.conf,确认系统 DNS 配置正常。还有一种情况是宿主机在公司内网,需要走 HTTP 代理才能访问外网,这时候 Docker 的拉取一般是配在/etc/systemd/system/docker.service.d/http-proxy.conf里面,而不是在 daemon.json。普通场景下,镜像加速器基本能解决 80% 的拉取问题。
5.3 overlay2 和 iptables:内核特性相关故障
如果docker info显示存储驱动不是 overlay2,或者启动容器时报ERROR: overlay2 is not supported,说明内核模块没加载或者当前文件系统不支持 overlay。先手动加载模块:
sudo modprobe overlay如果提示modprobe: FATAL: Module overlay not found,说明内核里根本没有这个功能,那就不是配置能解决的,需要升级内核。CentOS 7 上偶尔还会遇到 XFS 文件系统不支持d_type导致 overlay2 无法使用的问题,这种情况通常会回退成 vfs,性能下降明显。遇到文件系统相关的问题,排查方向就是系统本身的内核和文件系统格式,而不是 Docker 配置。
还有一类报错是iptables failed: Resource temporarily unavailable,这通常发生在 firewalld 或其他网络管理工具同时操作 iptables 的时候,锁冲突导致 Docker 插入规则失败。可以试着重启一下 firewalld 或 Docker,也可以稍等重试,但更要紧的是搞清楚为什么会有两个程序同时操作 iptables,长期解决方案是把规则管理职责拆清楚。
5.4 端口冲突、磁盘打满、容器名重复等运行期报错
装完 Docker 开始跑容器,还会遇到几类高频报错,我把常见情况和应对方法整理了一下:
| 报错症状 | 常见原因 | 排查 / 解决 |
|---|---|---|
| port is already allocated | 宿主机端口被其他进程或容器占用 | ss -lntp查看端口占用,换映射端口 |
| name already in use | 同名容器已存在 | 改名,或先docker rm 旧容器名 |
| no space left on device | 磁盘满了或 inode 耗尽 | df -h、df -i,再用docker system df查 Docker 占用 |
| device or resource busy | 挂载目录被占用,删除容器/卷失败 | 找到占用进程,先停容器再删卷 |
| deadline exceeded | 拉镜像或容器操作超时 | 多半和网络相关,配合镜像加速器重试 |
磁盘满是最隐蔽的,因为很多人只看df -h,忽略 inode 耗尽的情况,Docker 数据目录里大量小文件很容易把 inode 用光,这时df -h显示空间还有剩余,但写文件还是报no space left。遇到这种情况,执行df -i确认一下,顺便说一句,清理 Docker 数据用docker system prune或者docker image prune -a都比手动删文件安全,手动删/var/lib/docker里目录搞坏 Docker 的概率非常大。
5.5 几个经常被忽略的小细节
有些细节不能算严格意义的报错,但不注意会持续消耗你的时间。
Docker 的补全功能:装完 Docker 后,Ubuntu 和 CentOS 上如果装有bash-completion,Docker 包自带的补全脚本一般在/usr/share/bash-completion/completions/docker。如果 tab 键敲不出docker run的子命令提示,检查一下这个文件是否存在,重新加载 shell 后补全就能用了,这条提升命令行体验很明显。
GPG 密钥过期问题:如果你是在老机器上配置的 apt 源,可能某一天apt update突然报密钥签名错误,那就是旧版的 GPG 密钥过期了。解决方式是按文章前面的方式重新导入一次官方最新密钥,不用卸载 Docker。
最后说一下守护进程的操作习惯:Docker 服务在运行中,尽量不要直接用kill命令杀dockerd进程,这会绕过 systemd 的服务状态管理,留下残留的 pid 文件和 socket,下次启动时各种奇怪问题。一律用sudo systemctl restart docker,处理干净又不会破坏状态。
我在实际维护服务器的过程里,最深的体会是:Docker CE 安装本身真的不难,难的是对系统现状的判断。同样的命令,在 Ubuntu 20.04 和 24.04 上跑出来的行为不完全一样,CentOS 7 和 CentOS 8 的依赖处理也各有脾气。所以别把教程当成机械的命令复制工具,装的过程里多看一眼每一步的输出,尤其是docker info和docker version的服务端部分,确认它真起来了再继续。装完之后马上把镜像加速、日志上限、存储路径这几件基本配置做了,后面省的心远不止这点时间。如果你接下来准备在这台机器上跑业务容器,建议先用几个简单镜像把网络、存储、端口映射都测试一遍,有问题在没上真实业务前暴露出来,处理成本是最低的。