干运维这些年,几乎每个新环境交付的第一步动作都一样:不是写业务代码,不是部署应用,而是先装一套顺手的容器运行环境。Linux系统安装Docker这个事情,表面上一条命令就能搞定,可真到了生产服务器上,要考虑的东西比想象中多得多。今天就打算把这些年沉淀下来的实战经验系统整理一遍,覆盖主流的CentOS和Ubuntu两条技术线,从环境检查、在线安装、离线部署到装完之后的配置调优一次讲透。这篇文章既适合刚接触容器的开发者照着手动一遍,也适合准备批量初始化服务器环境的运维同学当操作手册参考。
Docker解决的核心问题其实是“环境一致性”。你在笔记本上跑得好好的服务,到了服务器上各种依赖缺失、版本冲突,这种问题我早些年几乎每周都要撞上一次。Docker把应用连同它的运行环境一起打包成镜像,启动成容器,相当于给每个服务都发了一台“带完整配置的迷你虚拟机”,但开销又比虚拟机小得多。装好Docker之后,你后续的部署、扩容、迁移都会轻松一个量级,这也是为什么只要涉及到Linux服务器,Docker都是基础设施层面的优先选择。
1. 安装前的准备思路
很多教程一上来就贴命令,但实际装到一半翻车的情况特别多。根据我的经验,安装之前花十分钟做几项检查,比装完之后排查一下午要划算得多。
1.1 环境检查要点
先确认操作系统版本和架构。Docker对系统版本有明确要求,CentOS 7的3.10内核开始才支持Docker的关键特性,Ubuntu这边则建议16.04以上的长期支持版本。架构上绝大多数服务器都是x86_64,但这两年ARM架构的服务器越来越多,下载安装包的时候一定要选对架构,否则装上之后跑不起来,报错还很难查。
内核版本检查用一条命令就行:
uname -r在CentOS 7上如果看到内核版本号是3.10.x,可以正常安装Docker,但建议后续关注内核升级的事情。Ubuntu 20.04和22.04自带的内核都是5.x版本,问题不大。除了内核,存储驱动也值得提前看一眼,Docker默认使用overlay2存储驱动,要求宿主机文件系统支持d_type特性,大部分默认分区格式化的ext4和xfs都没问题,但如果是从老系统升级上来或者用了特殊分区工具,这一步可能埋坑。
网络方面需要确认服务器能不能访问Docker官方软件仓库。如果服务器处于内网环境或者访问外网受限,就需要提前准备好离线安装包或者内网软件仓库源,这个后面专门讲。
1.2 为什么推荐装Docker Engine而不是其他版本
很多人第一次接触Docker时会困惑,官方网站上那么多安装包选项怎么选。Docker Engine是开源社区版的容器运行时,跑Linux服务器就装它,稳定成熟,没有任何附加限制。Docker Desktop是给macOS和Windows用户用的开发工具,带了一个Linux虚拟机,不适合装在Linux服务器上。
还有一个容易混淆的概念是docker.io和docker-ce的区分。Ubuntu自带仓库里那个docker.io包,版本普遍偏老,我建议直接用Docker官方发布的docker-ce版本。docker-ce版本迭代更快,bug修复和特性更新都跟得上,生产环境里少踩不少坑。
1.3 在线安装和离线安装怎么选
在线安装适用于服务器能正常访问外网的场景,步骤简单,后续升级用同样的源就行。离线安装适用于内网隔离环境,核心思路是在一台能联网的机器上下载好所有依赖包,再拷贝到目标服务器上安装。两种方式我都实际操作过多次,后文会分别给出完整的过程和注意事项。
2. 主流Linux发行版的安装流程
2.1 CentOS / RHEL系列安装细节
CentOS系是服务器市场占有率最高的发行版,安装Docker的流程也最成熟。第一步添加Docker软件仓库,而不要直接用系统自带的仓库,因为系统自带仓库里的Docker版本往往很旧。
安装必要的依赖工具:
sudo yum install -y yum-utils然后配置Docker的yum仓库:
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo这里有一个需要注意的地方:仓库配置完成后,建议手动确认一下仓库文件里的baseurl是否指向了正确的系统版本。把文件打开看一眼,确保没有因为操作系统标识不匹配导致后续安装失败。确认无误后,执行安装命令:
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin这组命令把核心组件都装齐了。docker-ce是守护进程和主要程序,docker-ce-cli是命令行工具,containerd.io是容器运行时,后面两个插件分别用于镜像构建和容器编排。如果只想最小化安装核心组件,最后两个插件可以省略,但我建议都装上,因为现在新版Docker Compose已经集成成插件了,以后编排多容器应用时基本上绕不开。
CentOS 8及后续版本如果使用yum报错,考虑使用dnf命令,用法几乎一模一样:
sudo dnf install -y docker-ce docker-ce-cli containerd.io安装完成后先不急着启动,后面统一说验证步骤。
2.2 Ubuntu / Debian系列安装细节
Debian系因为apt包管理器的设计不同,仓库配置稍微绕一点,但原理一致。先把基础依赖装上:
sudo apt-get update sudo apt-get install -y ca-certificates curl然后设置Docker的apt仓库信任证书和源列表。不同版本的Ubuntu需要对应不同版本的仓库地址,用如下命令自动适配:
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接着写入仓库列表,注意系统版本代号会从/etc/os-release中自动获取:
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更新索引后安装:
sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-pluginDebian系统只需把上面仓库地址里的ubuntu改成debian即可,其他流程完全一致。这里有一个极易踩的坑:切换系统版本代号时,仓库列表里的一串命令必须手动指定codename,不能想当然地copy网上老教程。比如新系统版本已经发布但Docker仓库还未更新对应代号,这时候安装就会报404。遇到这种状况,检查一下仓库地址里的版本代号和服务器实际代号是否对应即可。
2.3 快速验证安装结果
安装完Docker之后,第一件事不是急着拉镜像,而是先确认服务状态和CLI能否正常通信。启动服务并设置开机自启:
sudo systemctl start docker sudo systemctl enable docker验证运行状态:
sudo systemctl status docker看到active (running)只是第一步,接下来跑一个官方测试容器,顺便验证整个链路是否通畅:
sudo docker run hello-world如果一切正常,会输出一段文字说明Docker安装成功并能正常拉取和运行容器。有些内网环境拉取镜像会超时,这一步卡住不用慌,优先检查网络配置和镜像加速设置,后面也会提到。
3. 装完之后的必要配置
3.1 普通用户免sudo执行Docker命令
默认情况下,Docker守护进程绑定在/var/run/docker.sock这个Unix套接字上,只有root用户和docker用户组里面的用户有权限访问。如果每次执行docker命令都要加sudo,不仅麻烦,还可能因为sudo环境变量差异导致奇奇怪怪的问题。
把当前用户加入docker组:
sudo usermod -aG docker $USER执行完后需要注销重新登录,或者直接执行newgrp docker切换当前会话的组身份,否则权限不会立刻生效。有一个安全细节要提醒:docker组的权限等同于root权限,因为用户可以挂载宿主机目录到容器里,本质上能读取宿主机上的所有文件。所以给哪些用户加入docker组,一定要谨慎再谨慎。如果服务器上有多个业务方共用,建议用sudo权限管控,而不是人手一个docker组成员身份。
3.2 配置镜像加速
Docker默认从官方镜像仓库拉取镜像,但在部分地区拉取速度不稳定。配置镜像加速器是装完Docker之后比较关键的一步,能显著提升镜像拉取的成功率和速度。
编辑Docker的守护进程配置文件:
sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://docker.example.com"] } EOF注意将URL替换成你实际使用的镜像加速服务地址。填写多个加速地址时,Docker会按顺序尝试。配置修改后必须重启Docker才能生效:
sudo systemctl daemon-reload sudo systemctl restart docker验证加速器是否生效:
sudo docker info | grep -A 2 "Registry Mirrors"输出里能看到你配置的地址列表,就说明加速器配置成功。实际使用中我发现一个问题:不同加速服务的稳定性和镜像同步完整度差异很大,某些小众加速服务经常出现镜像标签不同步的情况。经验之谈,配置两个备用加速地址比只赌一个更稳。
3.3 存储目录调整
Docker默认把所有镜像、容器、卷的数据都存在/var/lib/docker目录下。很多服务器分区时根分区不会分太大,跑几个镜像很快就把磁盘填满。我踩过多次这样的坑:镜像拉取到一半报磁盘空间不足,清理半天日志才发现是根分区满了。
建议安装完立刻确认数据分区挂载情况,如果根分区空间充裕且服务器不是大规模生产环境,可以不动。如果根分区紧张或者容器数据量预期很大,最好把Docker数据目录迁移到独立的数据盘上。
修改daemon.json,增加data-root字段:
{ "data-root": "/data/docker", "registry-mirrors": ["https://docker.example.com"] }创建目录并重启:
sudo mkdir -p /data/docker sudo systemctl restart docker需要强调的是,数据目录迁移必须在容器还不多的时候做。如果已经跑了很多业务容器,迁移操作就复杂得多,需要考虑停机窗口、数据拷贝和路径映射。装好系统顺手把目录规划好,是最省心的做法。
3.4 日志清理开关
容器日志是另一个容易忽略的磁盘杀手。如果某个容器疯狂输出日志,而Docker默认的日志驱动不设上限,日志文件会一直增长直到撑满磁盘。生产环境里我一般会在daemon.json里加上日志轮转限制:
{ "log-driver": "json-file", "log-opts": { "max-size": "50m", "max-file": "5" } }这样每个容器日志文件超过50MB就会轮转,最多保留5个文件,再老的日志自动清理。这个配置对长期运行的容器非常关键,几十个容器跑半年不重启,有了日志轮转,磁盘占用基本可以保持在一个稳定水位。
4. 离线安装与内网部署方案
4.1 打包依赖与镜像传输
很多生产环境出于安全和合规考虑,服务器不允许连接外网。这种情况下在线安装流程完全走不通,需要提前在某台能联网的机器上准备好安装包,再拷贝到内网服务器上。这里分两种情况分别处理。
第一种情况是目标服务器可以访问内网软件源,就把Docker仓库配置成内网源,安装流程跟在线安装一样,只是把仓库地址换成内网地址即可。第二种情况是完全隔离的环境,需要用离线包方式安装。在联网机器上执行:
sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo yum makecache sudo yumdownloader docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin把下载下来的所有rpm包拷贝到目标服务器上,执行本地安装:
sudo rpm -ivh *.rpmUbuntu系的离线安装也类似,用apt下载所有.deb包,目标机器上执行dpkg安装。离线安装最大的坑是依赖缺失,安装到一半报依赖错误时不要慌,回联网机器上把缺失的依赖包补下即可。我的习惯是在联网机器上执行完整的安装模拟,确认所有依赖包都被正确拉到本地,再去内网执行安装。
4.2 内网镜像仓库的必要性
离线安装只是第一步,装完之后还需要拉取业务镜像。内网环境的镜像获取方式有两种,一种是提前在联网机器上docker pull需要的镜像,然后docker save导出成tar包:
docker save -o myapp.tar myapp:latest拷贝到内网服务器后导入:
docker load -i myapp.tar这种方式适合一次性部署,但每个节点都要手动导入一次。如果服务器数量多,镜像更新频繁,建议搭一套内网镜像仓库服务,把生产用的镜像全部推送到内网仓库里,所有服务器从内网仓库拉取。这是运维效率的分水岭,几台服务器可以靠手动搬运,几十台上百台就必须有仓库服务了。
4.3 Docker Compose插件的离线适配
新版Docker把Compose做成了插件形式,如果安装时漏掉了docker-compose-plugin这个包,执行docker compose会提示找不到命令。离线环境下补装倒不麻烦,但来回传包很耽误时间。建议离线安装时把buildx和compose两个插件包和核心包一起下载,避免后续到处找依赖。
5. 安装过程中的典型问题排查
5.1 守护进程无法启动
启动Docker时提示Job for docker.service failed,这类问题几乎天天有人在社区提问。排查顺序很重要:先看日志再动手改配置。
sudo journalctl -u docker.service --no-pager | tail -50最常见的原因之一是防火墙或iptables规则冲突。默认情况下Docker需要操作iptables来管理容器通信,如果宿主机上有其他网络管理工具占用了iptables链,Docker启动时就会报错。另一个常见原因是selinux安全上下文问题。CentOS上如果selinux开启且策略设置不当,Docker守护进程可能无法正常访问相关文件,临时关闭selinux验证:
sudo setenforce 0如果确认是selinux问题,可以调整策略而不是彻底关闭selinux,生产环境不建议把selinux直接关掉。日志里还会看到网桥创建失败的记录,这种情况多半是内核模块加载异常,检查br_netfilter模块:
sudo modprobe br_netfilter5.2 网络相关的报错
执行docker pull时卡住或报net/http: TLS handshake timeout,这个错误信息我看到过无数次。原因基本可以锁定在镜像拉取链路异常上。先检查DNS是否正常:
ping registry.example.com能ping通但拉取超时,大概率是到默认源网络质量不佳,优先配置镜像加速器。还有一种情况是服务器配置了代理,但Docker守护进程没有继承代理设置。需要在systemd服务文件里配置代理环境变量,或者通过daemon.json的proxy配置段设置,具体取决于Docker版本。
容器内部网络不通的问题需要区分两种场景:容器访问外网失败和容器之间互相不通。前者检查宿主机IP转发是否开启:
sudo sysctl -w net.ipv4.ip_forward=1后者检查docker0网桥和自定义网络的配置。排查网络问题时,有个实用思路是用docker run --rm -it临时起一个最小容器,在容器里执行ping和curl,快速定位是容器自身问题还是网络链路问题。
5.3 存储和权限类报错
failed to create task for container: failed to create shim task这类报错通常和文件系统属性或内核兼容性有关。如果宿主机文件系统不支持overlay2的d_type特性,Docker可能无法正常创建容器层。验证当前存储驱动:
sudo docker info | grep "Storage Driver"手动指定存储驱动为vfs可以绕过这个问题,但性能损失很大,不推荐长期使用。权限类报错最常见的就是访问docker.sock被拒绝,解决方法前文已经提到,加入docker用户组并且重新登录即可。有些同学执行完usermod后马上测试发现还是报权限错误,原因就是当前shell会话还没刷新组身份,执行newgrp docker或者注销重登就能解决。
5.4 常见问题速查表
| 问题现象 | 排查方向 | 参考处理 |
|---|---|---|
| service启动失败 | 查看journalctl日志 | 检查iptables/selinux/内核模块 |
| docker pull超时 | 网络链路、镜像源 | 配置加速器、检查代理设置 |
| 容器启动报shim错误 | 存储驱动、内核兼容 | 查看storage driver、升级内核 |
| 磁盘空间增长过快 | 容器日志、镜像残留 | 配置日志轮转、定期清理 |
| 权限被拒绝 | docker组身份未生效 | usermod后重新登录会话 |
| 端口映射不生效 | 防火墙规则冲突 | 检查firewalld/ufw策略 |
6. 生产环境安装后的检查清单
6.1 系统服务加固建议
Docker装好、验证能用,这只是开始。生产环境里我习惯按一套固定清单逐项确认,每一项背后都是真实环境里踩过的坑换来的经验。
防火墙端口策略:Docker会修改iptables规则,如果宿主机开启了firewalld或ufw,需要注意规则顺序。很多人在宿主机防火墙里开放了某个端口,但从外部访问容器映射端口仍然不通,就是因为Docker的iptables规则优先生效,外部流量先进Docker链被拦截了。
文件描述符限制:容器数量多了之后,Docker守护进程和容器进程会消耗大量文件描述符。检查系统的ulimit设置:
ulimit -n如果返回的数字比较小,建议调整到65535以上,特别是在跑大量容器或者数据库类容器的服务器上。
时间同步:容器日志、编排调度和证书验证都依赖准确的时间。如果服务器时间漂移严重,镜像签名校验会失败,容器日志时间也是错乱的。确认chronyd或ntpd正常运行后,大部分时间相关的问题都能规避。
6.2 资源监控与告警设置
生产环境的Docker不装监控就等于裸奔。至少要做到磁盘和水位的可视化和告警。监控面板可以不止看宿主机指标,容器的CPU、内存、网络IO同样需要纳入监控范围。我的经验是,容器监控的告警阈值和宿主机监控差异很大,因为多个容器共享同一份宿主机资源,单个容器内存超标就可能引发整机雪崩。建议对容器的内存使用率和磁盘占用单独配置告警,避免出现单个容器日志把磁盘写满的极端情况。
6.3 常用运维命令备份
最后分享几个我自己日常高频使用的Docker问题排查命令,都是从实践中整理出来的:
# 查看所有容器的资源占用 docker stats --no-stream # 清理所有停止的容器和悬空镜像 docker system prune -f # 查看某个容器的详细配置 docker inspect <container_name> # 实时查看容器日志,定位容器启动后立刻退出的问题 docker logs -f --tail 100 <container_name>特别是docker logs这条命令,容器启动后立刻退出这个经典问题,百分之八十靠它直接看到应用自身的报错信息。排查很多Docker问题的时候,应该牢记一个原则:先看日志再查配置,不要上来就重启服务,否则日志刷掉了更没法定位。
装过的Docker环境少说也有几百套了,每次新装一台服务器,流程已经变成肌肉记忆。但即使熟练到这个程度,我依然坚持按清单逐项验证,因为这个工具太底层了,底层工具的隐患往往会在最不经意的时候爆发出来。Docker的安装其实只是一个开端,真正决定你后续使用体验的,是装完之后怎么配置、怎么加固、怎么让它健康稳定地一直在后台运行。希望这篇梳理能帮你少走一些弯路,把精力留在那些更有价值的业务挑战上。