Linux装Docker这个话题看起来简单其实里面隐藏的坑比想象中多。拿到一台新服务器系统发行版不一样、内核版本有高低、软件源里有没有历史残留任何一个环节没处理干净装完之后容器要么起不来要么跑着跑着出各种幺蛾子。这篇就围绕Linux系统安装Docker这件事把从环境摸底、安装方式选型、实操落地到后期配置和问题排查的完整过程捋一遍。适合刚接触容器、准备在服务器上部署应用的同学也适合那些装完了但容器启动异常、想系统排查一遍的同行。全是实际操作层面的干货不说废话。1. 动手之前先把系统状况摸清楚很多人装Docker失败不是安装命令不对而是还没搞清楚自己机器上跑的是什么环境。我在不同发行版上装Docker装了无数次最大的感受是准备工作花十分钟后面能省一小时排错时间。1.1 内核版本和系统位数后面不少坑的源头Docker对Linux内核有硬性要求。以常见的运行模式来说只有64位架构的内核才支持完整的容器能力。国内很多老服务器还是32位系统或者内核版本停留在2.6时代这种环境装Docker要么直接报错要么装上了也无法正常创建容器。先执行下面这条命令把系统和内核信息看一遍uname -a cat /etc/os-release输出信息里重点看两处第一操作系统的发行版名称和版本号这决定了你后续用哪种软件源来安装第二内核版本号至少需要3.10以上否则overlay2存储驱动可能加载不了容器文件系统会出问题。我遇到过一台内网机器系统是某发行版的老版本内核只有3.8Docker装上了但一执行docker run就报kernel too old一类的错误后来只能升级内核才解决。所以内核版本检查这一步强烈建议不要跳过。1.2 清理历史残留先把旧版本和冲突软件请走如果是全新服务器这一步可以略过。但如果这台机器之前装过Docker或者系统里存在一些名称相近的包直接覆盖安装往往会导致服务启动异常。常见的冲突来源有三种。第一种是系统自带的旧版docker包比如某些发行版仓库里的docker、docker-engine、docker.io这类名字它们和官方仓库里的Docker二进制会抢占文件路径。第二种是snap方式安装的docker在某些环境下会和systemd服务单元冲突。第三种是之前手工解压过二进制文件留下了旧的docker、dockerd进程或者残留的配置目录。处理方式也简单先停掉可能存在的服务再卸载旧包sudo systemctl stop docker 2/dev/null sudo apt purge docker docker-engine docker.io containerd runc 2/dev/null sudo rm -rf /var/lib/docker这里多说一句很多人不敢执行rm -rf /var/lib/docker怕删掉重要数据。如果确定旧环境没有需要保留的镜像和容器数据这一步是可以做的。但要是有存量数据就别删目录只停服务和卸载旧包等新版本装好之后再做数据迁移。1.3 网络与软件源的提前确认安装Docker的多数操作本质上是从软件源拉取安装包。所以网络能不能通到软件源直接决定了安装成败。在配置官方源之前先检查一下目前的源是否可用sudo apt update如果这条命令本身就跑不动说明系统的软件源配置有问题得先修好源再谈安装Docker。如果update之后能正常拉取索引再继续下一步。部分内网环境会在软件源上做访问限制这种情况下需要提前准备好可用的源地址或者离线安装包不然安装到一半卡住来回折腾浪费时间。2. Docker安装方式三条路径怎么选Docker在主流Linux发行版上的安装路径大致可以分成三类。每一类都有自己适合的场景选错了也不是不能用但后面的维护成本会不一样。2.1 发行版自带软件源最省事但版本可能偏旧多数Linux发行版的软件源里都会收录Docker。比如在Ubuntu里直接执行sudo apt install docker.io在CentOS里执行yum install docker就能装上一个可用的Docker。这种方式的优点是简单依赖关系由发行版维护者统一处理装完基本就能用不需要额外配置什么。适合“我只想快速跑个容器不追求新功能”的场景。但缺点也很明显发行版收录的Docker版本往往落后官方不少。容器技术迭代快旧版本在镜像兼容性、网络策略、安全漏洞修复上都可能存在短板。我在生产环境遇到过发行版自带的Docker无法正常解析新版镜像manifest的情况后来换成官方仓库版本才解决。所以我的建议是新装系统、准备长期使用的机器不要偷懒用自带源版本太旧带来的隐性成本往往比配置官方源多花的十分钟高得多。2.2 官方安装脚本适合快速部署但可控性略弱Docker官方维护了一个一键安装脚本。执行一条命令就能完成软件源配置和软件安装因为它的逻辑是自动检测当前系统类型然后写入对应的官方源并安装。curl -fsSL 官方脚本入口 | sh这种方式的部署速度确实快适合临时环境、测试机、或者对安装过程不想过多研究的场景。但我个人在稍正式的环境里不太推荐直接用脚本有三个原因。第一脚本直接从网络拉取并执行虽然来源是官方但很多企业的安全审计会对这种方式有顾虑。第二脚本默认做的配置不一定符合你的预期比如它不会自动帮你设置镜像加速也不会帮你规划数据目录装完还是得手动调。第三一旦网络环境对脚本来源有限制整条命令就是废的反而不如手动配置仓库来得灵活。2.3 配置官方软件源再安装我推荐的主流方式对比前两种我更推荐的方式是手动将项目官方维护的软件源地址写入系统源列表然后通过系统包管理器安装。这样做的好处有三层。第一版本始终跟得上官方发布节奏安全补丁和功能更新都能及时拿到。第二安装过程走的是系统原生的包管理机制依赖关系和路径管理都由发行版自己处理不容易出现文件冲突。第三软件源是一次配置长期受益后续升级Docker时只需要执行普通的update和upgrade命令不需要重新安装。下面几节就基于这种方式把完整过程走一遍。3. 实操记录从零完成一次干净安装接下来以Ubuntu系发行版为例讲一遍完整的安装过程。同一套思路稍作调整也适用于其他主流发行版。3.1 第一步安装依赖与导入仓库签名在从官方仓库安装Docker之前需要先确保系统里安装了必要的依赖工具同时要把软件源的GPG密钥导入系统否则包管理器会拒绝使用该源。先装依赖sudo apt update sudo apt install apt-transport-https ca-certificates curl software-properties-common然后导入GPG密钥curl -fsSL 官方GPG密钥入口化到系统信任链这里的逻辑是包管理器需要验证软件包来源的合法性GPG密钥就是那把验证的钥匙。没有这把钥匙即便软件源可用apt也会因为无法验证签名而中断。导入之后执行下面的命令把官方仓库写入源配置sudo add-apt-repository deb [archamd64] 官方软件源地址注意架构参数如果机器是64位arch填amd64就好其他架构需要手动调整。这一步写错后面安装时会出现找不到软件包或者架构不匹配的报错。3.2 第二步更新索引并安装核心包仓库配置完成之后先update一次让包管理器识别到新的软件源sudo apt update此时可以顺手确认一下候选版本apt-cache policy docker-ce如果能够看到docker-ce的候选版本信息说明软件源配置成功。接着直接安装sudo apt install docker-ce这里只安装了docker核心包。官方仓库里的docker-ce默认会带出containerd和runc这些运行时依赖不需要单独手动处理。执行完毕之后安装阶段就基本结束了。3.3 第三步启动服务并验证安装结果安装完成不等于安装成功。先启动服务、设置开机自启然后做一次状态检查sudo systemctl start docker sudo systemctl enable docker sudo systemctl status docker看到状态输出为active (running)的时候说明守护进程已经正常起来了。再执行一次版本信息查询docker version这个命令的输出会分Client和Server两部分。如果Server部分内容也完整显示说明客户端到守护进程的链路是通的。常见的情况是Client正常、Server连接失败这种问题一般指向服务没启动或者socket权限不对放到后面排查部分细说。3.4 扩展RHEL系发行版的差异点如果目标机器是Red Hat系或者CentOS系的发行版安装逻辑类似但有几处操作不同。第一步同样是安装系统依赖但包管理器换成了yum或者dnfsudo yum install -y yum-utils然后配置仓库sudo yum-config-manager --add-repo 官方软件源地址安装命令对应改为sudo yum install -y docker-ce启动服务这条是通用的systemd的用法在所有主流发行版上都是一样的。RHEL系特有的一点是某些环境下SELinux策略会限制容器运行时的操作权限如果启动容器时遇到permission denied一类的问题需要优先检查SELinux的状态和布尔值配置而不是一上来就想着关SELinux。4. 安装后的必备配置不调这几次算白装Docker装完只是开始接下来这几项配置直接关系到日常使用的体感。每一件都是我在实际使用中验证过属于做完立刻见效的调整。4.1 把当前用户加入docker组默认情况下执行docker命令需要root权限或者sudo前缀。每一条命令都带sudo用起来极其别扭。更合理的做法是创建一个docker用户组把需要操作容器的用户加进去。sudo groupadd docker 2/dev/null sudo usermod -aG docker $USER执行完usermod之后需要注销系统或者重新登录一次用户组权限才会生效。很多人在这里踩坑执行完命令后直接运行docker ps发现依然报permission denied就以为命令没用其实是当前会话的权限还没有刷新。我不建议直接把普通用户加进sudo组那样权限放得太宽。docker组的权限本质上已经接近root只应该授权给确实需要管理容器的账号。4.2 配置镜像加速与守护进程参数容器镜像的拉取速度基本决定了一个容器能不能快速跑起来。国内网络环境下直接连接官方镜像仓库经常会出现超时或拉取缓慢的问题而配置好镜像加速器后拉取速度会得到明显好转。Docker守护进程的配置文件路径在/etc/docker/daemon.json正常情况下这个文件可能不存在需要自己创建。写入以下内容{ registry-mirrors: [加速器地址] }执行sudo systemctl restart docker重启服务后通过docker info命令可以在输出中看到Registry Mirrors一栏确认配置是否生效。这里有个细节使用的是某个公有云厂商提供的加速器地址这类地址通常需要以https://开头。如果填写错误Docker虽然能正常启动但拉镜像时仍然走的默认链路效果等于白配。4.3 迁移数据目录与日志轮转Docker默认把所有镜像、容器、卷的数据放在/var/lib/docker下面。这个目录和操作系统在同一块磁盘一旦镜像增多、日志膨胀系统盘很容易被撑满。我处理过好几起磁盘告警事件最后都定位到这个目录。如果机器上有独立的数据盘合理的做法是把这个目录迁移到数据盘上。有两种常见方式一种是直接把整个目录挂载为数据盘另一种是把数据目录做成软链接指向数据盘。结合维护习惯我更喜欢在fstab里设置开机挂载把数据盘挂到/var/lib/docker这样最直观。日志轮转也是值得顺手配置的项。Docker默认的记录方式会无限增长一个容器如果疯狂打日志几天时间就能把磁盘写爆。在daemon.json里加上日志限制{ log-driver: json-file, log-opts: { max-size: 20m, max-file: 5 } }这样单个容器日志文件达到20MB就会自动滚动最多保留5个文件。设置完记得重启Docker。4.4 开机自启与服务管理系统重启后Docker服务默认不会自动恢复需要设置开机自启。这个操作在3.3节里已经执行过但还是要单独拎出来强调一次enable和start是两件事start是现在就启动enable是以后开机也启动少了哪一个都不完整。容器层面的自启则不受这个配置影响。如果某个容器希望跟随Docker启动而自动运行创建容器时需要加上--restartalways参数。这个策略在生产环境里非常实用机器重启后容器能自动恢复到运行状态避免故障恢复时还要手动逐条启动容器。5. 验证安装与快速上手跑通第一个容器配置完成之后下一步就是验证整条链路是否真的通畅。这一步不仅能确认安装质量还能让第一次接触Docker的人建立起对命令模型的基本感觉。5.1 三个版本命令说明问题第一组验证命令是查看版本信息docker -v docker version docker infodocker -v只输出客户端版本号信息最少。docker version把客户端和服务端分开显示特别适合确认Server是否正常响应。docker info的信息浓度最高包含存储驱动、镜像加速、容器数量、运行中容器数量等关键状态排错时用得最多。我建议至少把docker version和docker info的执行结果完整看一眼而不是只看版本号就算完。因为docker info里如果有存储驱动不匹配、网络插件异常这类警告基本都会在后续使用中以奇怪的方式暴露出来。5.2 用hello-world验证端到端链路Docker官方提供了一个专门用于验证的最小镜像一般就叫hello-world。它是完整的端到端验证方式docker run hello-world执行之后如果镜像还没有本地缓存Docker会先去仓库拉取然后创建容器、运行、输出提示信息、退出。整个过程包含镜像拉取、容器创建、进程运行三个核心环节任何一步有问题都能立刻看出来。我第一次在全新的服务器上跑这个命令时拉镜像阶段因为网络问题卡了很久。配置完镜像加速之后几秒钟内就能跑完这种对比感受非常直观。所以如果这一步卡住先回头看镜像加速配置。5.3 常用命令初步体验跑完hello-world之后建议顺手执行几条基础命令建立对Docker命令行模型的初步认识。查看所有容器列表docker ps -a这里用-a是因为默认只显示运行中的容器而hello-world容器运行完后就退出了不加-a会看不到它的记录。查看本地已有的镜像列表docker images试着停止和删除一个容器理解命令的生命周期管理docker stop 容器ID docker rm 容器ID如果之前跑通了hello-world容器列表里会有它的记录可以用它的容器ID试一下。到这里安装验证和基础操作就已经全部跑通了。6. 常见坑与排查速查表安装环节真正让人头疼的往往不是安装本身而是装完之后各种看起来莫名其妙的报错。下面把我在现网最常遇到的几类问题整理成一个速查表按症状、排查思路和解决方案对照来看。6.1 排错方法论先看服务再看日志遇到Docker相关故障第一步永远不是改配置而是先确认服务状态。执行sudo systemctl status docker看服务是不是处于active状态。如果服务是failed用journalctl -u docker查看日志。日志里通常会有明确的错误信息包括存储驱动加载失败、端口被占用、配置文件语法错误等。配置文件语法错误是一个高发问题。daemon.json是严格的JSON格式一个多余逗号或者缺失的引号都会导致服务无法启动。我在手改配置时踩过几次这个坑后来习惯在重启服务前先把JSON内容做一次格式校验再小的改动也值得多花这一步。6.2 高频问题对照表下面这个表格是实操中总结出来的高频问题直接对照使用即可。症状常见原因排查与解决Got permission denied用户不在docker组执行usermod -aG docker并重新登录Cannot connect to the Docker daemondockerd未运行systemctl start docker并查看日志No space left on device/var/lib/docker所在分区已满清理无用镜像或迁移数据目录镜像拉取超时或极慢未配置镜像加速检查daemon.json中的registry-mirrors内核相关报错内核版本过低确认uname -r结果内核升级后重试容器端口映射不生效防火墙或网络驱动问题检查宿主防火墙规则和Docker网络策略配置了镜像加速但不生效地址格式错误或未重启校验JSON格式重启dockerd后用docker info确认容器日志无限增长log-opts未设置在daemon.json中设置max-size和max-file6.3 几个我从现场总结的经验最后分享几条笔记本里不会写、但实际部署时特别有用的经验。第一不要随便关防火墙来排查端口问题。容器端口映射不生效时很多人的第一反应是关掉防火墙测试这是饮鸩止渴的做法。正确做法是放行容器映射出来的端口而不是让整个机器的安全策略失效。排查时临时放行要比直接关闭安全得多。第二镜像加速对拉取速度的影响是肉眼可见的但加速器有时候也会抽风。如果配置了加速器之后某些镜像仍然拉不下来不妨把daemon.json里的加速器地址临时去掉走默认链路试一次反向排除加速器本身的问题。第三不要在容器里裸跑需要持久化的数据服务。容器重启后数据就没了这句话对新手来说是抽象概念只有真正丢过一次数据才会有刻骨铭心的体会。使用volume或者bind mount来持久化数据是容器化部署里最值得投入成本的认知之一。第四daemon.json的改动属于全局配置每次修改都要谨慎。改之前先备份原文件改完检查JSON格式再重启服务。这些看起来不起眼的动作能帮你避免在最需要稳定运行时突发配置事故。实际接管过的机器多了会发现安装Docker永远是容器化路上最简单的一环真正决定稳定性的是安装之后的每一次配置决策。先把基础装扎实后面跑容器、编排服务时才不会处处被动。