1. 为什么在Linux上安装Docker是开发者的必修课
如果你是一名后端开发者、运维工程师,或者正在学习云原生技术,那么“在Linux上安装Docker”这件事,大概率是你绕不开的第一道坎。这听起来像是一个简单的、有标准答案的操作,网上教程一搜一大把。但为什么我还是要花这么长的篇幅来聊它?因为根据我过去几年带团队和解决无数线上问题的经验,恰恰是这种“基础操作”,埋下了最多的坑。很多人照着教程敲完命令,看到docker version输出版本号就以为万事大吉,结果在后续构建镜像、运行容器、配置网络时,各种诡异问题层出不穷,根源往往就出在最初安装时某个被忽略的细节上。
Docker 的本质是一个客户端-服务器架构的应用。我们常说的“安装Docker”,实际上是在安装三样东西:Docker 客户端 (docker命令)、Docker 守护进程 (dockerd) 以及一套用于交互的 REST API。守护进程负责管理容器、镜像、网络和存储卷等核心对象,而客户端则是我们与之通信的工具。在Linux上,这意味着我们需要处理软件源、依赖包、用户权限、存储驱动、网络配置等一系列底层系统交互,远比在Windows或macOS上使用 Docker Desktop 来得复杂,但也正因为如此,理解这个过程能让你真正掌握Docker在Linux环境下的行为逻辑。
所以,这篇文章不会是一个简单的命令罗列。我会带你走一遍在主流Linux发行版(以Ubuntu和CentOS为例)上安装Docker的完整流程,并深入到每一个步骤的背后,解释“为什么要这么做”。更重要的是,我会分享那些官方文档不会写,但实际生产中一定会遇到的“坑”和应对策略,比如国内镜像加速、用户组权限、存储驱动选择、以及如何排查“Virtualization support not detected”这类经典错误。目标很简单:让你不仅能把Docker装上去,更能装得明白、装得稳固,为后续所有容器化工作打下坚实的基础。
2. 安装前的深度准备:比选发行版更重要的事
在打开终端输入第一条命令之前,有几项准备工作的重要性,甚至超过了选择Ubuntu还是CentOS。这些准备决定了安装过程是否顺畅,以及安装后的Docker环境是否健康。
2.1 系统版本与内核检查:避开兼容性雷区
Docker对Linux内核有最低要求。例如,Docker CE(社区版)通常需要Linux内核版本在3.10以上。但这只是底线,一些新特性(如Overlay2存储驱动)需要更高版本的内核支持。
首先,检查你的内核版本和系统架构:
uname -r输出类似5.4.0-100-generic。对于绝大多数现代发行版(如Ubuntu 18.04+, CentOS 7.4+),内核版本都满足要求。但如果你使用的是较旧的系统,可能需要先升级内核。
其次,确认系统是64位:
uname -m输出应为x86_64。Docker官方已不再支持32位系统。
注意:这里有一个经典误解。很多人看到“virtualization support not detected”的错误,第一反应是去BIOS里开启VT-x/AMD-V(CPU虚拟化支持)。这对于在Windows/macOS上运行虚拟机或Docker Desktop是必要的,但对于在原生Linux上安装Docker Engine,通常不需要。Linux Docker Engine 利用的是内核的
cgroups和namespaces特性来实现容器化,这是一种操作系统级别的虚拟化,不依赖CPU的硬件虚拟化技术。这个错误提示更多出现在Docker Desktop for Windows/Mac的场景。所以,如果你的宿主机就是Linux,请先忽略这个方向。
2.2 彻底清理旧版本:避免冲突的黄金法则
如果你的系统上曾经安装过旧版本的Docker(或叫docker.io,docker-engine),必须彻底清理,否则会导致无法预测的依赖冲突和配置混乱。
执行以下清理命令(适用于基于APT的系统和基于YUM的系统):
# 对于 Ubuntu/Debian sudo apt-get remove docker docker-engine docker.io containerd runc # 清除残留数据和配置(谨慎操作,会删除所有容器、镜像、卷!) sudo rm -rf /var/lib/docker sudo rm -rf /var/lib/containerd # 对于 CentOS/RHEL/Fedora sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine sudo rm -rf /var/lib/docker sudo rm -rf /var/lib/containerd/var/lib/docker是Docker默认的数据根目录,删除它意味着所有本地镜像、容器、网络和卷都将被永久删除。请确保在执行前,任何重要的容器数据都已经通过docker save或卷备份等方式进行了迁移。
2.3 配置国内软件源:解决“下载慢”问题的根本
无论是安装Docker本身,还是后续拉取镜像,网络速度都是影响体验的关键。官方源位于国外,速度慢且不稳定。配置国内镜像源是必选项。
对于Ubuntu/Debian,我们需要为Docker单独配置APT源,而不是替换整个系统的源。
- 安装必要的工具包,允许APT通过HTTPS使用仓库:
这一步是基础,确保系统能安全地与Docker仓库通信。sudo apt-get update sudo apt-get install \ ca-certificates \ curl \ gnupg \ lsb-release - 添加Docker官方的GPG密钥,用于验证软件包的完整性:
sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg - 设置稳定的Docker仓库。这里我强烈建议使用国内镜像源,例如阿里云或中科大源。以下以阿里云为例:
关键点在于将echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/nullhttps://download.docker.com替换成了https://mirrors.aliyun.com/docker-ce。$(lsb_release -cs)会自动获取你的Ubuntu代号,如jammy。
对于CentOS/RHEL/Fedora,配置YUM/DNF源:
- 安装依赖:
sudo yum install -y yum-utils - 添加Docker仓库。同样,使用国内镜像:
# 官方源(不推荐,速度慢) # sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 阿里云镜像源(推荐) sudo yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo - 更新本地YUM缓存:
sudo yum makecache fast
完成这些准备工作后,你的系统已经为安装Docker扫清了障碍,并搭建了一条高速下载通道。接下来,我们进入正式的安装环节。
3. 分步安装与核心配置详解
安装过程本身并不复杂,但每一步的选择都值得推敲。我将以Ubuntu 22.04 LTS和CentOS 8 Stream为例,展示完整过程,并穿插讲解关键决策点。
3.1 Ubuntu/Debian 系安装流程
更新APT包索引:在添加了新仓库之后,这是必须的一步,让系统知道从哪里获取Docker包。
sudo apt-get update这个命令会读取
/etc/apt/sources.list和/etc/apt/sources.list.d/下的所有仓库信息,包括我们刚刚添加的Docker阿里云源。安装Docker引擎及相关组件:
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugindocker-ce: Docker社区版引擎,核心。docker-ce-cli: Docker命令行工具,我们用的docker命令就来自这里。containerd.io: 行业标准的容器运行时,Docker引擎底层依赖它来管理容器生命周期。这是从Docker中分离出来的核心组件。docker-compose-plugin: 这是新的Docker Compose V2,以插件形式安装,命令是docker compose(注意中间没有横线)。我推荐安装它,因为V1的docker-compose已不再积极开发。
安装过程中,你会看到一系列依赖包被自动安装。如果遇到依赖冲突(通常是因为没清理旧版本),安装会失败并给出提示。
验证安装:安装完成后,运行:
sudo docker version如果看到
Client和Server两部分都输出了版本信息,说明Docker客户端和守护进程都已成功安装并运行。Server部分显示Cannot connect to the Docker daemon则说明守护进程没启动。启动并设置开机自启:
sudo systemctl start docker sudo systemctl enable docker使用
systemctl管理Docker服务是现代Linux发行版的标准方式。enable命令会在系统启动时自动启动Docker守护进程。
3.2 RHEL/CentOS/Fedora 系安装流程
在CentOS 8/RHEL 8及更新版本上,默认的包管理器是dnf,但yum命令通常作为其别名存在,可以通用。
安装Docker引擎:
sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin命令与Ubuntu类似,包管理器会自动处理所有依赖。
启动并设置开机自启:
sudo systemctl start docker sudo systemctl enable docker验证安装:
sudo docker version
3.3 第一个非root用户:权限管理的最佳实践
安装完成后,如果你直接运行docker ps,很可能会看到权限拒绝的错误。这是因为Docker守护进程默认以root用户运行,而Docker CLI通过Unix socket (/var/run/docker.sock) 与守护进程通信,该socket默认只允许root用户和docker用户组的成员访问。
因此,最佳实践是将需要使用Docker的普通用户加入docker用户组:
sudo usermod -aG docker $USERusermod: 修改用户属性。-aG:-a表示追加(append),-G指定附加组。如果不加-a,用户会被从其他所有附加组中移除,只保留docker组,这很危险。$USER: 环境变量,代表当前登录的用户名。
执行此命令后,必须完全退出当前终端会话(关闭所有窗口或断开SSH连接),然后重新登录,组权限变更才会生效。这是一个非常容易忽略的步骤,很多人加了组后直接在当前终端测试,发现依然报错,误以为配置失败。
重新登录后,运行docker ps(不再需要sudo),应该能成功执行并返回一个空的容器列表。这意味着你的用户已经拥有了操作Docker的权限。
重要安全提示:将用户加入
docker组,本质上等同于赋予该用户root权限。因为通过Docker可以挂载宿主机目录、启动特权容器等。因此,这只应在你信任的单用户开发机或个人服务器上操作。在生产环境中,应严格限制docker组的成员,或考虑使用更细粒度的授权插件(如Docker的授权插件机制)。
4. 安装后的关键配置与优化
安装成功只是开始,合理的配置能让Docker用起来更顺手、更高效。这里有几个我认为必不可少的配置项。
4.1 配置镜像加速器:加速所有镜像拉取
即使安装时用了国内源,拉取Docker Hub上的镜像(如ubuntu:latest,nginx:alpine)依然可能很慢。我们需要配置Docker守护进程的镜像加速器。
编辑Docker的守护进程配置文件/etc/docker/daemon.json(如果不存在则创建):
sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": [ "https://registry.docker-cn.com", "https://hub-mirror.c.163.com", "https://mirror.baidubce.com" ] } EOF这里我添加了三个常用的国内镜像源。你可以选择一个延迟最低的,但配置多个也无妨,Docker会按顺序尝试。
然后,重新加载配置并重启Docker服务:
sudo systemctl daemon-reload sudo systemctl restart docker验证配置是否生效:
docker info在输出信息中,找到Registry Mirrors部分,应该能看到你刚刚配置的镜像地址。
4.2 修改默认数据目录:规避根分区爆满
Docker默认将所有数据(镜像、容器、卷)存储在/var/lib/docker。如果系统根分区(/)空间不大,这很容易导致磁盘被写满,引发系统问题。我们可以将其迁移到大容量的数据盘上。
假设我们想将数据目录迁移到/data/docker:
- 停止Docker服务:
sudo systemctl stop docker - 复制数据(如果已有数据):
使用sudo rsync -avz /var/lib/docker/ /data/docker/rsync比cp更安全,支持断点续传和校验。 - 备份并修改配置文件:
注意:如果sudo cp /etc/docker/daemon.json /etc/docker/daemon.json.bak sudo tee -a /etc/docker/daemon.json <<-'EOF' { "data-root": "/data/docker" } EOFdaemon.json已存在其他配置(如镜像加速器),需要将>sudo systemctl start docker docker info | grep "Docker Root Dir"输出应为Docker Root Dir: /data/docker。
4.3 调整日志驱动与大小:防止日志撑爆磁盘
容器默认的日志驱动是json-file,它会将容器的标准输出/错误日志以JSON格式存储在宿主机上。如果不加限制,一个持续运行且输出日志的容器,其日志文件可能会增长到GB级别。
我们可以在全局配置中限制单个日志文件的大小和数量:
{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }将这段配置同样放入/etc/docker/daemon.json的顶层对象中。这表示每个容器日志文件最大10MB,最多保留3个文件(即总共最多30MB日志)。超过后,旧文件会被自动删除。
修改配置后,同样需要重启Docker服务。
5. 运行第一个容器与基础命令验证
配置完成后,让我们通过运行一个最简单的容器来验证整个环境是否工作正常。
docker run --rm hello-world这条命令做了以下几件事:
docker run: 创建并启动一个新容器。--rm: 容器退出后自动删除其文件系统。这对于一次性测试容器非常有用,避免留下垃圾。hello-world: 一个极小的官方测试镜像。
如果一切正常,你会看到一段欢迎信息,最后以Hello from Docker!结尾。这证明:
- Docker客户端能正常通信。
- Docker守护进程在运行。
- 能够从Docker Hub(或你配置的镜像加速器)成功拉取镜像。
- 能够成功创建并运行容器。
接下来,可以尝试一些更实用的命令,感受一下Docker的日常工作流:
# 拉取一个Ubuntu镜像 docker pull ubuntu:22.04 # 以交互模式运行一个Ubuntu容器,并进入其bash shell docker run -it --name my-ubuntu ubuntu:22.04 bash # 在容器内执行命令后,输入 exit 退出容器。 # 查看所有容器(包括已停止的) docker ps -a # 启动一个停止的容器 docker start my-ubuntu # 再次进入一个运行中容器的shell(需要容器内已安装bash) docker exec -it my-ubuntu bash # 停止容器 docker stop my-ubuntu # 删除容器 docker rm my-ubuntu # 删除镜像 docker rmi ubuntu:22.046. 进阶:存储驱动选择与cgroup驱动配置
对于大多数新手和通用场景,安装后的默认配置已经足够。但当你需要更优的性能或计划部署Kubernetes时,了解这两个概念至关重要。
6.1 存储驱动:容器文件系统的基石
存储驱动决定了容器层叠文件系统(如镜像分层、写时复制)如何与宿主机文件系统交互。不同Linux发行版和内核版本有不同的推荐驱动。
- Ubuntu/Debian (内核 >= 4.0):默认且推荐使用
overlay2。它是性能最好、最稳定的现代存储驱动。 - RHEL/CentOS (旧版本):历史上默认使用
devicemapper,但现在较新的版本(CentOS 8/RHEL 8,内核>=3.10)也支持并推荐overlay2。
查看当前存储驱动:
docker info | grep "Storage Driver"overlay2要求内核版本和支持的文件系统(如ext4或xfs并启用d_type支持)。你可以通过以下命令检查d_type支持:
sudo tune2fs -l /dev/sda1 | grep features # 在输出中寻找 `has_dtype`。对于xfs,挂载时默认支持。如果你的系统满足条件但未使用overlay2,可以在/etc/docker/daemon.json中配置:
{ "storage-driver": "overlay2" }6.2 cgroup驱动:与系统初始化程序的协调
cgroups(控制组)是Linux内核功能,用于限制和隔离进程的资源使用。Docker和Kubernetes都使用它。Linux系统主要有两种初始化系统:systemd和cgroupfs。它们管理cgroups的方式不同。
systemd:现代主流发行版(Ubuntu 16.04+, CentOS 7+, RHEL 7+)默认使用。cgroupfs:较旧的系统或容器内常用。
Docker默认使用cgroupfs驱动,而Kubernetes(特别是kubelet)在systemd初始化系统中更推荐使用systemdcgroup驱动。如果两者不匹配,可能导致资源统计不准确或Kubernetes节点状态异常。
如果你计划在此主机上安装Kubernetes,建议将Docker的cgroup驱动也改为systemd:
{ "exec-opts": ["native.cgroupdriver=systemd"] }同样,将此配置加入/etc/docker/daemon.json并重启Docker。
验证更改:
docker info | grep -i cgroup输出应包含Cgroup Driver: systemd。
对于不涉及Kubernetes的纯Docker环境,使用默认的cgroupfs通常没有问题。
7. 故障排查:从安装失败到运行异常
即使按照步骤操作,你也可能遇到问题。这里汇总了几个最常见故障的排查思路。
7.1 安装失败:依赖冲突与网络问题
症状:apt-get install或yum install失败,提示依赖包冲突、找不到包或网络超时。
排查:
- 网络问题:首先
ping mirrors.aliyun.com检查网络连通性。如果超时,检查系统DNS配置 (/etc/resolv.conf) 或网络代理设置。 - 仓库配置错误:检查
/etc/apt/sources.list.d/docker.list或/etc/yum.repos.d/docker-ce.repo文件内容是否正确,发行版代号是否匹配。对于Ubuntu,$(lsb_release -cs)必须输出正确的版本代号。 - GPG密钥问题:Ubuntu下,确保
/etc/apt/keyrings/docker.gpg文件存在且可读。可以尝试重新下载密钥。 - 未更新缓存:在安装前,务必执行了
sudo apt-get update或sudo yum makecache。 - 旧版本冲突:这是最常见的原因。请严格按第2.2节执行旧版本的彻底清理。
7.2 Docker守护进程无法启动
症状:执行sudo systemctl start docker失败,或sudo docker version显示无法连接到守护进程。使用sudo systemctl status docker查看服务状态,通常会有红色错误信息。
排查:
- 查看详细日志:
这会输出Docker服务最新的50行日志,错误原因通常一目了然。sudo journalctl -u docker.service --no-pager -n 50 - 常见错误1: “iptables” 或 “firewalld” 冲突:某些系统防火墙规则可能与Docker创建的规则冲突。尝试暂时停止防火墙并重启Docker:
如果能启动,说明是防火墙问题。你需要配置防火墙允许Docker网络流量,而不是直接关闭它。Docker会动态管理sudo systemctl stop firewalld # 对于firewalld sudo systemctl stop iptables # 对于iptables(不常见) sudo systemctl start dockeriptables规则,与firewalld共存需要额外配置。 - 常见错误2: “bridge-nf-call-iptables is disabled”:在
sysctl中启用它:
为了使设置永久生效,将其写入sudo sysctl net.bridge.bridge-nf-call-iptables=1 sudo sysctl net.bridge.bridge-nf-call-ip6tables=1/etc/sysctl.conf或/etc/sysctl.d/99-docker.conf。 - 常见错误3: 配置文件语法错误:
/etc/docker/daemon.json必须是有效的JSON格式。一个多余的逗号或引号错误都会导致Docker启动失败。可以使用json_pp或在线JSON校验工具检查其语法。sudo python3 -m json.tool /etc/docker/daemon.json
7.3 用户权限问题(“Got permission denied”)
症状:不使用sudo运行docker ps等命令时,提示权限拒绝。
排查:
- 确认用户已加入
docker组:groups $USER,查看输出中是否包含docker。 - 最关键的一步:确认你是否在修改组权限后重新登录了会话。仅仅执行
usermod命令,当前已打开的终端会话不会生效。你必须退出SSH连接或关闭终端窗口,然后重新登录。 - 检查Docker socket的权限:
ls -l /var/run/docker.sock。其组所有者应为docker。 - 如果以上都正确,可以尝试手动切换组,但这只是临时测试:
newgrp docker。然后再次运行docker ps。
7.4 镜像拉取失败或极慢
症状:docker pull长时间卡在下载层,或最终失败报错net/http: TLS handshake timeout。
排查:
- 确认镜像加速器配置正确且生效:
docker info查看Registry Mirrors。 - 测试镜像加速器连通性:尝试拉取一个小镜像,如
alpine:latest,看速度是否正常。 - DNS问题:Docker守护进程可能使用与宿主机不同的DNS。在
/etc/docker/daemon.json中配置DNS服务器:{ "dns": ["114.114.114.114", "8.8.8.8"] } - 代理问题:如果你在公司网络或使用了代理,可能需要为Docker配置代理。这需要设置Docker守护进程的环境变量,具体方法因发行版而异(通常是在
/etc/systemd/system/docker.service.d/http-proxy.conf中配置)。
8. 生产环境考量与安全加固建议
在个人开发机上,我们可能怎么方便怎么来。但在生产服务器上,安全性和稳定性是首要考虑。
- 限制
docker组用户:如前所述,docker组权限等同于root。生产环境中,应严格控制该组的成员,最好只有专门的运维管理用户属于此组。应用程序运行用户绝不应加入docker组。 - 启用用户命名空间映射:这是Docker一项重要的安全特性,它能让容器内的
root用户映射到宿主机上的一个非root用户,从而即使容器被突破,对宿主机的破坏也有限。配置相对复杂,需要在/etc/docker/daemon.json中设置userns-remap。 - 使用非root用户运行容器:在Dockerfile中,使用
USER指令指定一个非root用户来运行进程。例如USER nobody。 - 定期更新Docker引擎:安全漏洞会定期被修复。关注Docker官方安全公告,并规划好升级窗口。升级前,务必在测试环境验证。
- 日志与监控:将Docker守护进程和容器的日志接入统一的日志系统(如ELK)。使用监控工具(如Prometheus + cAdvisor)监控容器资源使用情况。
- 备份
daemon.json和/etc/docker:你的所有自定义配置都在这里。在进行任何重大变更或系统迁移前,备份这些文件。 - 考虑使用容器运行时接口(CRI):如果你最终的目标是运行Kubernetes,可以考虑直接安装
containerd或cri-o作为容器运行时,而不是完整的Docker Engine。Kubernetes自1.24版本起已移除对Docker的直接支持(通过dockershim),但Docker Engine内置的containerd仍然可以被Kubelet通过CRI使用。不过,为了简化维护,生产集群更倾向于使用containerd或cri-o。
安装Docker只是一个起点。理解其背后的原理、掌握配置和排错的方法,才能让你在容器化的道路上走得更稳、更远。希望这篇超过5000字的详细指南,能帮你构建一个坚实可靠的Docker基础环境。