1. 安装前的核心思路:别急着敲命令,先想清楚这三件事
最早我在服务器上装Docker的时候,也是上来就 curl -sSL https://get.docker.com/ | sh,一条龙跑完,看着终端刷屏觉得特爽。后来踩过几次坑才意识到,Docker安装本身并不难,真正影响后续使用体验的,是安装前的几个决策。这篇内容就围绕“给Linux主机安装Docker服务”这条主线,把我在不同发行版、不同网络环境、不同使用场景下积累的安装经验完整拆开讲,帮你少走弯路。
先聊三个必须在装之前想清楚的问题。
第一,你的Linux发行版是哪个系?Debian系(Ubuntu、Debian本身、Deepin等)和RHEL系(CentOS、Rocky、AlmaLinux、Fedora)在安装命令、软件包管理器和内核模块加载方式上都有差异,虽然Docker官方提供了统一的便捷脚本,但生产环境我建议还是用发行版对应的仓库来装,便于后续维护和版本锁定。如果你用的是一些国内国产系统(比如统信UOS、麒麟),底层通常也是Debian系或RHEL系的变种,可以先通过 /etc/os-release 确认。
第二,你的服务器能不能直接访问外网?Docker安装的过程需要拉取APT/YUM仓库元数据和GPG密钥,如果机器只有内网IP,或者带宽受限,那就需要提前准备离线安装包或者内网镜像源。这一块很多人装到一半失败,报错信息五花八门,归根到底都是网络问题。
第三,你打算拿Docker干什么?如果只是本地开发环境跑个MySQL、Redis,那普通安装就够了。如果是要跑生产服务、搭Kubernetes集群,或者跑一些对性能有要求的应用,那还需要额外处理存储驱动、cgroup驱动、iptables配置这些细节。我用表格把常见场景和对应要求列出来,方便你对号入座:
| 使用场景 | 安装复杂度 | 需要额外关注的配置 |
|---|---|---|
| 本地开发/学习 | 低 | 无,默认配置即可 |
| 个人服务器跑应用 | 中 | 镜像加速、日志清理策略 |
| 生产环境单机部署 | 中高 | 存储驱动、资源限制、开机自启 |
| Kubernetes集群节点 | 高 | cgroup驱动、iptables/ipvs、内核参数调整 |
我自己在安装前会顺手做一件事:检查系统是否已经装过老版本的Docker或Podman,避免端口和cgroup配置冲突。命令是 docker version 和 podman --version,如果发现残留,先卸载干净再开始。这一步很多人忽略,后面出问题的时候才回头排查,浪费大量时间。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 全流程实操:从系统准备到Docker跑起来
2.1 系统基础环境准备
安装Docker前,先把系统基础环境准备好。我习惯先更新索引包,再安装依赖。这里说的依赖包括 apt-transport-https、ca-certificates、curl、gnupg、lsb-release。其中 ca-certificates 是HTTPS证书信任链要用到的,没有它你等下添加GPG密钥和仓库的时候会报证书错误。
Debian系执行:
bash复制sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release
RHEL系执行:
bash复制sudo yum install -y yum-utils
这里有个细节:RHEL系需要 yum-utils 来提供 yum-config-manager 命令,后面添加仓库要用。如果你用的是CentOS 8以上的版本,有些发行版默认源里没有 yum-utils,可以改用 dnf config-manager,这一点我在踩坑记录里还会提到。
另外建议顺手关闭防火墙对Docker端口的干扰,或者提前规划好放行策略。默认情况下Docker会用iptables操纵主机防火墙规则,如果你自己装了firewalld或ufw,可能会和Docker的规则冲突。最省事的办法是安装阶段先不纠结,等Docker跑起来再统一调整防火墙,避免安装过程被复杂化。
2.2 添加Docker官方仓库(Debian系)
获取GPG密钥并写入 /usr/share/keyrings/docker-archive-keyring.gpg。这里建议大家用 --write-out 或者 --output 指定路径,不要直接把公钥输出到屏幕,否则后面添加仓库的时候会提示key无法读取。
bash复制curl -fsSL https://download.docker.com/linux/$(. /etc/os-release && echo "$ID")/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
然后添加仓库。这里有一个关键点:官方文档里用的是变量 $(. /etc/os-release && echo "$VERSION_CODENAME"),这个变量在某些发行版上可能为空,导致仓库地址不对。我一般更推荐手动指定版本代号,比如Ubuntu 22.04的代号是jammy,Debian 12是bookworm,直接写死更靠谱。
bash复制echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu jammy stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
注意上面是我以Ubuntu 22.04为例的写法,如果你用的版本不一样,把 jammy 换成你的版本代号就行。查看代号可以用 lsb_release -cs 或者读取 /etc/os-release 里的 VERSION_CODENAME。
2.3 添加Docker官方仓库(RHEL系)
RHEL系的仓库配置相对简单,用 yum-config-manager 直接添加就行:
bash复制sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
如果你的发行版是Rocky或AlmaLinux,这个仓库文件依然可以用,因为它们的系统基线兼容CentOS。但有个坑:CentOS 9 Stream之类的版本可能在安装时会报缺少 container-selinux 依赖,解决办法是先启用CRB(CodeReady Builder)仓库,再安装Docker:
bash复制sudo dnf install -y epel-release
sudo dnf config-manager --set-enabled crb
2.4 安装Docker引擎及相关组件
现在到了核心安装环节。Docker的软件包分为几个部分,我用表格说明一下各自的角色:
| 软件包名称 | 作用 |
|---|---|
| docker-ce | Docker引擎本体(社区版核心) |
| docker-ce-cli | Docker命令行工具,负责和引擎通信 |
| containerd.io | 容器运行时管理组件,实际执行容器生命周期 |
Debian系安装:
bash复制sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
RHEL系安装:
bash复制sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
这里把 docker-buildx-plugin 和 docker-compose-plugin 一起装了,是因为新版Docker把构建扩展和Compose V2都插件化了,早装早省心。你要是只装 docker-ce,后面要用 docker compose 的时候还得再补。
安装完成后启动服务:
bash复制sudo systemctl start docker
sudo systemctl enable docker
enable 这步是为了让Docker随系统开机自启,生产环境必备。检查状态用 sudo systemctl status docker,看到 active (running) 就说明引擎已经跑起来了。
2.5 验证安装:跑第一个测试容器
验证Docker是否正常工作,最经典的方式是运行hello-world镜像:
bash复制sudo docker run hello-world
这一步会先从Docker Hub拉取镜像,如果网络不通的话会卡住或者报 Unable to find image 'hello-world:latest' locally 之后超时失败。解决办法见后面第4章的镜像加速配置。
跑完看到 Hello from Docker! 的输出,说明整个引擎链路没问题。此时用 sudo docker version 可以看到Client和Server两部分的版本信息,Server那一栏正常输出版本号而不是报错,就说明服务端也是好的。
3. 核心细节拆解:为什么这样装、装完还要做什么
3.1 为什么推荐用官方仓库而不是一键脚本
网上大量教程会用 curl -fsSL get.docker.com -o get-docker.sh && sh get-docker.sh 这种方式安装,我早期也是这么干的。一键脚本的好处是省事,它会自动识别系统发行版、自动配置仓库、自动安装依赖。但它的弊端也很明显:不可控、无法指定版本、在特殊网络环境下经常中途失守。
用官方仓库手动安装的好处在于,你能够精确控制Docker的版本,这在生产环境里非常重要。比如你的应用依赖于某个特定的Docker版本特性,或者你想防止 apt upgrade 时把Docker悄悄升到不兼容的版本,手动安装加版本固定是最稳的。
版本固定的方式:
bash复制apt-cache madison docker-ce
然后指定版本安装:
bash复制sudo apt install docker-ce=5:26.0.1-1~ubuntu.22.04~jammy docker-ce-cli=5:26.0.1-1~ubuntu.22.04~jammy containerd.io
RHEL系用:
bash复制yum list docker-ce --showduplicates
sudo yum install docker-ce-26.0.1
3.2 新版本Docker的组件变化:不再只有docker-ce
如果你看的教程比较老,会发现当时只提到 docker-ce 和 docker-ce-cli,现在多出了 docker-buildx-plugin 和 docker-compose-plugin。这是因为Docker在近两年的版本迭代中,将原来独立的 docker-compose 二进制和BuildKit构建引擎都整合进了官方插件体系。
我一开始不理解为什么这样设计,后来用久了发现这其实是个好事。以Compose为例,再也不用维护 docker-compose 和 docker compose 两种命令习惯,插件化的管理方式也更干净,卸载某个插件不会影响引擎本身。但代价是,如果你在安装时忽略了插件,后面执行 docker compose up 会直接提示:
code复制docker: 'compose' is not a docker command.
所以大家在安装时务必加上这两个插件包。另外 docker buildx 还能用来构建多平台镜像,比如在x86机器上构建ARM镜像,这些高级用法后面有机会单独写一篇,先不展开。
3.3 配置非root用户使用Docker
每次都用 sudo docker 很烦,而且部分工具(比如IDEA的Docker插件、Portainer的agent)以普通用户的身份连接Docker时会遇到权限问题。解决方案是把用户加入 docker 用户组:
bash复制sudo usermod -aG docker $USER
newgrp docker
之后执行 docker ps 就不需要加sudo了。但这里有一个重要的安全提示:加入docker组等于赋予了该用户相当于root的权限。因为Docker守护进程本身以root运行,能够访问docker组就意味着可以挂载主机的任意目录、修改iptables、读写宿主文件系统,所以不要把不信任的用户随便加进docker组。有些安全指南甚至建议不要给普通用户docker组权限,而在生产环境可以选择给用户配置受限的SSH登录或使用Rootless模式。这个取舍没有标准答案,按自己的环境安全要求来。
3.4 配置系统服务与资源限制
Docker安装完成后,默认会创建很多iptables规则,也会修改内核参数。有一些参数建议提前设置好,尤其是生产环境。打开 /etc/sysctl.conf,添加以下几项:
bash复制net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
vm.max_map_count = 262144
第一项是为了让Kubernetes等场景下的容器网络正常,第二项是让容器能访问外部网络,第三项是某些应用(比如Elasticsearch)需要的,按需添加。改完执行 sudo sysctl -p 让配置生效。这些参数不是Docker本身的必须项,但属于“装了Docker之后迟早会用到”的高频配置。
同时建议给Docker的日志加上上限,防止容器疯狂打日志把磁盘塞满。Docker默认会保留容器的全部日志,长期跑下来你会发现 /var/lib/docker/containers/ 下的JSON日志文件动辄几个GB。我一般在 /etc/docker/daemon.json 里加上日志轮转配置(这个文件后面还会涉及镜像加速配置)。
4. 镜像加速与Compose:装完Docker后必做的两件事
4.1 配置镜像加速源解决拉取慢
对这个点我感触太深了,Docker最痛苦的体验不是安装,而是拉镜像。尤其是国内网络环境下,从Docker Hub直接拉一个ubuntu镜像都要等半天。解决方式就是配置Registry Mirror。
创建或编辑 /etc/docker/daemon.json:
json复制{
"registry-mirrors": [
"https://docker.1ms.run",
"https://docker.xuanyuan.me"
],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
}
}
上面的镜像地址是我实测过可用的公共镜像加速地址,你也可以用云厂商提供的加速器,但有些云服务商的加速地址现在只对内部用户开放。每次改完 daemon.json 之后记得重启Docker:
bash复制sudo systemctl daemon-reload
sudo systemctl restart docker
重启后可以用 docker info 查看 Registry Mirrors 一栏,看看加速配置是否生效。
这里说个容易踩的坑:Docker的镜像加速只对从Docker Hub拉取镜像时生效,如果你需要拉取的是其他私有仓库或者某些特殊镜像,加速器不一定管用。另外有些人会把加速地址配成HTTP而不是HTTPS,此时必须在 daemon.json 里显式声明 "insecure-registries",否则Docker默认拒绝非HTTPS的仓库。
4.2 安装Docker Compose并快速上手
前面安装阶段已经把 docker-compose-plugin 装好了,现在可以直接验证:
bash复制docker compose version
如果显示版本号,就说明Compose V2已经就绪。Compose的价值在于把多个容器的配置组织在一个YAML文件里,一键启动、停止、重建。举个例子,这是我在开发环境经常用的一套MySQL 8.0配置:
yaml复制version: '3.8'
services:
mysql:
image: mysql:8.0
container_name: mysql8
restart: always
environment:
MYSQL_ROOT_PASSWORD: root123
TZ: Asia/Shanghai
ports:
- "3306:3306"
volumes:
- ./mysql_data:/var/lib/mysql
- ./my.cnf:/etc/mysql/conf.d/my.cnf
执行:
bash复制docker compose up -d
启动完成后,用客户端工具连接宿主机的3306端口就能访问MySQL了。如果项目需要依赖多个服务,比如Nginx加PHP加Redis加MySQL,用Compose管理起来优势非常明显。
4.3 测试镜像加速与Compose结合的完整流程
我建议你安装完Docker之后不要急着关终端,顺手做一套组合测试。依次执行以下命令:
bash复制docker pull nginx:alpine
docker run -d --name test-nginx -p 8080:80 nginx:alpine
curl http://localhost:8080
docker rm -f test-nginx
这套操作能覆盖镜像拉取、容器创建、端口映射、网络连通性几个核心链路,能快速发现潜在问题。如果 curl 返回了Nginx的默认欢迎页,说明网络链路是通的,端口映射正常。再把 docker info 的输出里 Registry Mirrors 和 Docker Root Dir 确认一下,安装阶段对核心配置的验证就全部完成了。
提示:这一步不要省略,尤其是从零开始装的机器,这套自测能帮你区分后续问题到底是镜像问题、网络问题还是Docker引擎的问题。
5. 常见问题与排查技巧:装Docker路上的经典坑都在这
5.1 内核太老或缺少模块导致的启动失败
如果你用的是比较老的Linux内核(比如CentOS 7自带的3.10内核),Docker引擎启动时可能报以下错误:
code复制Error starting daemon: Error initializing network controller: Error creating default "bridge" network: iptables failed
这种多半是iptables版本与内核兼容性问题。一个可用的处理方案是升级内核,或者尝试安装 iptables-services 并调整Docker的iptables开关。不过在CentOS 7上最稳妥的做法其实是使用 docker-ce 的兼容版本,并确认开启了内核模块:
bash复制sudo modprobe overlay
sudo modprobe br_netfilter
lsmod | grep br_netfilter
如果 br_netfilter 模块加载失败,内核对网络过滤的支持就有问题,Docker创建bridge网络时就会出岔子。
5.2 添加仓库时报错No such file or directory
Debian系常见的是GPG密钥路径不对。很多教程会写 apt-key add -,但这个方式在新版系统中已经被标记为废弃,推荐的做法是写到 /usr/share/keyrings/ 下,然后在仓库配置里用 signed-by 显式声明。如果你完全按照我说的步骤来,这个错一般不会遇到。
还有一个容易忽略的点:Ubuntu某些非LTS版本(比如21.10、22.10)停止支持后,官方仓库路径会失效。这时候要么换下一版系统,要么手动指定code name到仍然支持的仓库地址(但可能拿不到新版本),不推荐长期使用。
5.3 运行命令时报权限错误
docker ps 提示 permission denied while trying to connect to the Docker daemon socket,说明当前用户不在 docker 用户组里。按3.3节的操作加入组就行。但注意,如果你是在SSH会话里修改的用户组,需要重新登录或者用 newgrp docker 切换活动组才生效。
5.4 镜像拉取卡住或超时的排查思路
镜像拉取超时,大部分都跟网络出口有关。第一步先确认网络基本连通性:ping -c 4 114.114.114.114。如果网络通则进一步测试到镜像仓库的连通性:
bash复制curl -I https://registry-1.docker.io/v2/
如果这个请求超时,基本可以确定是到Docker Hub的链路有问题,而你的加速器配置又没生效。看看 docker info 里的 Registry Mirrors 是否为空,空的话就是配置文件路径或格式有问题。注意 daemon.json 是严格的JSON格式,任何多余的逗号或者语法错误都会导致整个文件被忽略,Docker甚至不会报配置文件错误,而是用默认配置启动。
5.5 Docker服务启动与开机自启的完整核对单
当所有步骤做完之后,我建议按下面的清单核对一遍状态:
| 检查项 | 命令/方法 | 期望结果 |
|---|---|---|
| 引擎运行状态 | systemctl status docker |
active (running) |
| 开机自启 | systemctl is-enabled docker |
enabled |
| 版本信息 | docker version |
Server栏正常显示 |
| 加速器生效 | docker info | grep -A 1 Registry |
显示镜像地址 |
| 普通用户免sudo | docker ps |
能正常返回列表 |
| Compose可用 | docker compose version |
显示版本号 |
这个清单覆盖了从引擎、网络、权限到扩展功能的各个维度,全部通过的话,Docker安装这件事基本就画上句号了。
6. 延伸场景简述:装完Docker之后还能怎么用
Docker装好只是起点,它能做的事情远不止跑几个镜像。这里简单提两个常见方向。
一是部署Docker UI管理面板,比如Portainer。用Compose一条命令就能起来,之后通过浏览器可视化管理容器、镜像、网络和数据卷,对不习惯频繁敲命令行的人非常友好。我个人的习惯是生产环境尽量用命令行,但在测试环境或给同事用的团队机器上装一个Portainer,能大大降低协作门槛。
二是搭建私有镜像仓库,比如Harbor或者轻量级的Registry。团队内部交付镜像时,推到私有仓库比到处传tar包高效得多。这个方向涉及HTTPS证书、认证、存储规划等更多细节,等有需要时再单独展开。
Docker之后还会涉及数据卷管理、网络模式选择、镜像瘦身、CI/CD集成、Kubernetes编排等大量内容,每一步都有不少讲究。但地基要先打牢,一台配置正确、环境干净、参数合理的Docker主机,值得你在安装阶段多花半小时认真对待。
