ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Ubuntu安装Docker与Docker Compose:镜像加速配置及排错完整指南

Ubuntu安装Docker与Docker Compose:镜像加速配置及排错完整指南 本来不算什么新鲜话题但这半个月我连续帮三台Ubuntu机器处理了Docker环境问题——一台是公司的开发机、一台是自己的笔记本、还有一台是朋友的云服务器。问题各不相同但根子都在同一个地方Docker装得不系统镜像加速也没配明白导致要么稳定跑不起来要么拉个镜像能等上十分钟。所以干脆把这条完整的安装链路重新捋一遍从Ubuntu的初始状态开始把Docker与Docker Compose装到能正常干活的程度再把镜像加速配到“真正拉得动镜像”而不是配完心里安慰。这篇文章写给第一次在Ubuntu上装Docker的新手也写给那些照着官方文档装完、docker pull却频繁超时的老用户。覆盖的系统版本以Ubuntu 20.04、22.04、24.04为主只要不是特别老的内核基本都能直接照着做。1. 装之前先做三件事版本确认、残留清理、依赖补齐很多教程打开就是直接拉源、安装我觉得这是不对的。Docker安装失败的大多数原因其实是环境没准备好系统里残留了旧版Docker、缺了HTTPS依赖、或者内核太老。与其装到一半报错再回头排查不如先把这三件事花两分钟做完。1.1 确认内核版本和系统架构Docker对内核版本有硬性要求3.10以上才能正常运行。Ubuntu 16.04之后的内核基本都满足条件但为了保险装之前建议还是看一眼uname -r uname -m第一条查内核版本第二条查CPU架构。x86_64对应的是amd64架构的安装包ARM服务器返回的是aarch64后面配置apt源时填的架构名就是靠这个决定的。这一步看似多余实际能避免你在源配置里写错架构名导致apt update时报404或者找不到包。1.2 检查系统里有没有残留的Docker旧包如果你这台Ubuntu之前用apt install docker.io装过Docker又或者从网上的教程复制过不知名的安装脚本那系统里很可能残留着旧的docker、docker-engine、containerd、runc等包。它们和官方源的docker-ce会互相冲突轻则apt装不上重则两个版本的dockerd同时在跑把容器状态搞乱。先查一下dpkg -l | grep -i docker有输出的话把旧包装干净sudo apt remove docker docker-engine docker.io containerd runc这条命令会卸载软件包但会保留/var/lib/docker下面的镜像、容器数据。如果你确定旧数据都不需要了可以顺手清掉给磁盘腾地方sudo rm -rf /var/lib/docker sudo rm -rf /var/lib/containerd注意这个清理是不可逆的执行前想清楚。我自己习惯在重装Docker环境时把数据目录清干净因为旧镜像和旧容器往往带着不兼容的配置留着只会干扰新版本的初始化。1.3 补齐HTTPS相关的依赖官方源是通过HTTPS协议提供安装包的同时添加源的时候需要ca-certificates证书和curl工具。Ubuntu 22.04的最小化安装里不一定带全这些东西先把它们装好sudo apt update sudo apt install -y ca-certificates curl gnupggnupg是用来处理GPG密钥的。有人会问网上很多教程还带一个lsb-release包用来读取Linux Standard Base版本信息。实际上Ubuntu 20.04之后/etc/os-release文件里的信息已经足够完整不需要额外装lsb-release也能拿到版本代号。所以我不建议再装这个包没必要。这三件事做完系统才算进入可以安装Docker的干净状态。2. 安装Docker引擎选对apt源比执行install更重要Ubuntu上安装Docker引擎的方式大致有三种从官方apt源安装、用官方脚本一键安装、下载二进制包手动部署。我推荐的是第一种原因后面细说。先看一个对比表格感受一下差别安装方式优点缺点适用场景官方apt源安装版本可控、升级方便、依赖自动处理需要手动添加GPG密钥和源绝大多数生产环境和开发机官方一键脚本命令短、速度快不能指定版本、脚本会自动改系统配置临时测试环境二进制包安装完全离线、不依赖网络仓库依赖手动装、升级成本高内网隔离环境2.1 为什么我坚持用官方apt源而不是脚本一把梭官方脚本确实方便一行curl -fsSL https://get.docker.com | sh就能装完。但问题是这个脚本默认从官方源拉取最新版本你不能精确控制版本。对于生产环境来说Docker引擎的版本一旦与开发环境不一致很容易出现新旧API兼容问题。而且脚本会以root身份执行自动修改系统的源配置、启动服务、设置开机自启整个流程黑盒化出问题不好排查。相比之下apt源这套流程每一步都是透明的GPG密钥放哪、源文件写成什么样、仓库更新是否成功全部看得见摸得着。所以我坚持用apt源的方式这也是Docker官方文档推荐的标准安装路径。2.2 添加Docker官方GPG密钥与apt源先建立存放GPG密钥的目录然后下载密钥文件放到这个目录里sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg sudo chmod ar /etc/apt/keyrings/docker.gpg这里有三点值得解释一下。第一install -m 0755 -d这个命令比mkdir -p更规范它会给目录设置0755权限让所有用户都能读和执行但只有root能写。目录权限如果不对后续apt update时可能会因为无法读取密钥文件而报错。第二gpg --dearmor的作用是把GPG公钥从ASCII文本格式转换为二进制的keyring格式。apt配置源时Signed-By指向的就是这个二进制文件。早期教程喜欢用apt-key add但apt-key从Ubuntu 22.04开始被标记为废弃官方不建议再用新环境一律用--dearmor这种方式。第三chmod ar确保所有用户都能读取这个密钥文件。这一步经常被遗漏但如果不执行非root用户执行apt update时可能会碰到Permission denied那个报错会让人摸不着头脑。然后添加apt源echo \ deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \ $(. /etc/os-release echo $VERSION_CODENAME) stable | \ sudo tee /etc/apt/sources.list.d/docker.list /dev/null这条命令里用了两个自动替换$(dpkg --print-architecture)自动输出当前系统架构名。x86_64机器会替换成amd64ARM机器会替换成arm64不用手动改。$(. /etc/os-release echo $VERSION_CODENAME)先加载/etc/os-release文件里的变量然后输出版本代号。Ubuntu 22.04会得到jammy24.04会得到noble。有人会问直接用lsb_release -cs不也行吗在标准的Ubuntu官方发行版上确实可以但如果你用的是Ubuntu衍生版或魔改版lsb_release -cs输出的可能是衍生版的代号在Docker官方源里根本找不到对应的仓库目录。用VERSION_CODENAME则始终是Ubuntu官方的版本代号兼容性更好。这个细节我踩过坑所以特别写一下。2.3 更新源并安装Docker引擎源配置好之后先更新apt索引sudo apt update如果输出里出现了http://download.docker.com/linux/ubuntu jammy/stable之类的条目说明源已经生效。可以先看一眼候选版本apt-cache policy docker-ce然后正式安装。我推荐的完整安装命令是sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin解释一下这几个包分别干什么docker-ceDocker引擎核心包含dockerd守护进程。docker-ce-clidocker命令行工具用来和守护进程交互。containerd.io容器运行时dockerd调用它来真正起容器。docker-buildx-pluginBuildKit构建插件新版推荐用它构建镜像。docker-compose-pluginCompose插件装了它就可以用docker compose命令。一次性装齐免得后面要用的时候发现缺这个缺那个。安装完成后验证一下sudo docker version sudo docker run hello-worldsudo docker run hello-world能正常输出一段Welcome信息说明引擎已经跑起来了。但如果你的网络环境对Docker Hub访问不稳定这一步可能会卡在拉取镜像上。别急这正是后面第4章要解决的问题。3. 补齐Docker Compose插件版与独立版的取舍Docker Compose负责用YAML文件定义和启动多个容器是Docker生态里绕不开的组成部分。但这里有个非常容易混淆的点docker compose和docker-compose是两个不同的命令。前者是Docker官方在2022年之后主推的插件版随Docker引擎一起发布后者是早期用Python写的独立二进制。两个命令的配置文件格式完全兼容但安装方式、调用方式不同。3.1 用Docker官方插件版装完引擎自带如果你在第2.3节使用了那行包含docker-compose-plugin的完整安装命令那么Compose插件已经装好了直接验证docker compose version输出类似Docker Compose version v2.24.7插件版的好处是它和Docker引擎一起由apt管理升级Docker时会自动升级Compose版本匹配不会出问题。新增项目、新写配置文件我建议一律用插件版。配置文件有两种后缀compose.yaml和docker-compose.yml插件版都支持。Docker官方文档目前推荐使用compose.yaml因为更直观但老项目里大量存在的docker-compose.yml依旧可以正常读取。3.2 独立二进制版它解决哪些问题有一部分工具和脚本里面写死了docker-compose这个命令比如某些CI流水线、开源项目的一键部署脚本。这种情况下你光装插件版不行脚本会报command not found。安装独立版的方法是去GitHub下载二进制文件放到系统PATH目录里。先确认架构然后执行uname -m sudo curl -L https://github.com/docker/compose/releases/download/v2.24.7/docker-compose-linux-x86_64 -o /usr/local/bin/docker-composex86_64机器用docker-compose-linux-x86_64ARM机器改成docker-compose-linux-aarch64。下载完成后加执行权限sudo chmod x /usr/local/bin/docker-compose docker-compose version官方GitHub仓库下载速度不理想的话可以找一些国内的镜像下载站点把那个release文件下载下来再上传到服务器。文件名保持docker-compose放在/usr/local/bin里就行。这里要注意一下PATH路径问题。部分Ubuntu用户的PATH里没有包含/usr/local/bin执行docker-compose version可能出现command not found。如果遇到这种情况改用/usr/bin/docker-compose路径或者在~/.bashrc里把/usr/local/bin加进PATH。3.3 同一台机器上能不能两个都装可以。插件版和独立版在当前版本下不会冲突因为插件版注册的是docker compose独立版注册的是docker-compose命令名不重叠。我在自己的机器上就是两个都装了平时自己写配置用插件版跑一些老项目需要docker-compose命令时直接用它互不干扰。安装完成后可以找一个现成的compose文件试一下语法docker compose config在项目目录下执行能解析出最终的配置内容说明Compose可用。4. daemon.json镜像加速配置与实测验证Docker默认从Docker Hub拉取镜像但Docker Hub的服务器在海外国内网络直连经常超时。遇到docker pull卡住、失败、进度条长时间不动大概率不是Docker本身装错了而是没有配置镜像加速器。这一步配置的其实是Docker守护进程的registry-mirrors参数。4.1 镜像加速的原理它到底怎么工作可以这样理解Docker Hub是镜像的“原厂仓库”镜像加速器是“就近的本地仓库”。你把加速器的地址告诉Docker守护进程它拉取镜像时会先去加速器里找找不到再回到原厂仓库。加速器通常和CDN服务商合作节点分布在国内网络延迟比直连海外低很多。这个机制从Docker 1.8之后就一直存在配置层面就是修改/etc/docker/daemon.json文件往registry-mirrors数组里填入加速器地址。4.2 修改daemon.json并重启Docker先创建配置目录如果不存在的话然后用tee命令写入配置sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json -EOF { registry-mirrors: [ https://docker.m.daocloud.io, https://docker.mirrors.ustc.edu.cn, https://hub-mirror.c.163.com, https://mirror.baidubce.com ] } EOF这里多说一句tee配合heredoc的方式比echo加重定向更安全因为tee会把写入过程完整打印出来方便你确认内容写对了。同时要注意daemon.json必须是合法的JSON格式逗号、大括号错一位Docker服务就会启动失败。如果不确定格式是不是合法写完之后用Python校验一下python3 -m json.tool /etc/docker/daemon.json没有报错说明JSON格式没有问题。配置写好后需要重启Docker守护进程让配置生效sudo systemctl daemon-reload sudo systemctl restart dockersystemctl daemon-reload这一步不能省。即使你已经修改了daemon.json不执行daemon-reloadDocker服务重启时可能还是加载旧配置。4.3 验证加速是否生效重启完成后执行docker info在输出里找Registry Mirrors字段应该能看到刚才写入的那几个地址Registry Mirrors: https://docker.m.daocloud.io/ https://docker.mirrors.ustc.edu.cn/ https://hub-mirror.c.163.com/ https://mirror.baidubce.com/看到这个列表说明加速器已经生效。接下来拉一个镜像实测一下速度time docker pull nginx:latest我这边实测没配加速时拉一个nginx镜像经常卡在等待连接阶段配了加速之后几十秒内就能拉完。如果拉取速度还是慢可能是个别加速器线路不稳定可以把registry-mirrors里的地址顺序换一换或者换成其他新的加速源。公共加速源存在运营不稳定的问题偶尔会停服或变更域名。如果某天发现docker pull又超时了不要怀疑人生先去curl -I测一下配置的加速器地址是否还能响应不行就换可用的源。你自己在阿里云、腾讯云等平台开通的制品仓库加速地址如果可以获取通常是更稳定的选择。5. 权限、自启与常见排错的完整排查链路装完Docker、配好加速整个安装流程已经走通八成了。但还有几个收尾配置不做的话后续使用过程中会反复踩坑。我自己在实际操作中几乎每次都绕不开这些问题所以单独拎出来写一节。5.1 让当前用户免sudo执行docker命令按前面步骤装好后每次执行docker命令都要加sudo用起来很不顺手。解决办法是把当前用户加入docker组。docker守护进程的socket文件/var/run/docker.sock权限默认只有root和docker组的成员可以使用加入docker组之后普通用户就能直接操作Docker。执行sudo groupadd docker sudo usermod -aG docker $USER第一条命令如果提示groupadd: group docker already exists说明docker组已经存在忽略即可。第二条命令把当前用户加入docker组。执行完后需要重新登录终端或者运行newgrp dockernewgrp命令会切换当前会话的有效用户组为docker组不需要退出终端就能立即生效。不过要注意这只对当前终端会话有效新开的终端窗口还是要重新登录一次才能识别docker组身份。5.2 设置Docker开机自启大多数使用场景希望Docker服务随系统一起启动。执行sudo systemctl enable docker sudo systemctl enable containerd验证自启配置是否生效systemctl is-enabled docker输出enabled就代表自启配置成功。如果你用的是WSL2环境情况会有差异。WSL2默认的init进程不是systemdsystemctl命令可能执行失败。需要先确认WSL2是否启用了systemd支持查看/etc/wsl.conf里是否包含systemdtrue。没有的话编辑这个文件添加[boot] systemdtrue然后在Windows终端里执行wsl --shutdown重新进入WSL2后systemd就会生效。如果你不想折腾systemdWSL2下也可以直接用sudo service docker start来启动Docker服务。5.3 排错链路一Docker服务起不来daemon.json大概率写错了这是配镜像加速时最常遇到的问题。执行systemctl status docker看到失败状态第一反应不要瞎猜直接看日志journalctl -u docker --no-pager | tail -50如果日志里出现failed to load docker config: unable to parse /etc/docker/daemon.json那就是daemon.json格式有问题。用python3 -m json.tool /etc/docker/daemon.json校验一下修正后重启服务。5.4 排错链路二docker pull超时先别急着怪加速器docker pull超时不能简单归结为加速器失效。我习惯走这样一条排查链路一次定位问题先测加速器地址能不能访问curl -I https://docker.m.daocloud.io/v2/看HTTP状态码是否正常。再看DNS解析是否正常nslookup docker.m.daocloud.io确认域名能解析出IP。然后用docker info确认daemon.json里的加速器确实已加载。最后拉一个小镜像测试docker pull alpine:latest如果成功再拉目标镜像。很多时候问题出在某个镜像体积太大网络波动导致断流。把镜像切小、或者多尝试几次基本能解决。5.5 排错链路三磁盘空间爆掉镜像拉不下来Docker的默认数据目录是/var/lib/docker系统盘小的话很容易被镜像和容器日志撑爆。用df -h看磁盘剩余空间再用docker system df看Docker占用了多少空间。清理空间最快的几个命令docker system prune -a docker image prune docker volume prunedocker system prune -a会清理所有未被使用中的容器关联的镜像和构建缓存空间回收效果最明显。如果清理完还是不够建议把Docker数据目录迁移到大分区方法是在daemon.json里加上>{ data-root: /data/docker, registry-mirrors: [ https://docker.m.daocloud.io ] }改完重启Docker服务注意已有镜像和容器不会自动迁移需要先把旧目录数据复制过去或者接受重新拉取镜像。最后分享一个我自己的习惯。装好Docker环境后不要急着跑容器先执行一遍docker info把里面的内核版本、存储驱动、Registry Mirrors、数据目录这几项扫一遍。花不了两分钟但后面一旦出问题你会发现自己定位起来比看任何文档都快。这套安装流程我前后用了很多次踩过的坑基本都写在这了照着一步步走下来至少不会卡在最基本的安装环节上。
返回列表