首页 / 资讯中心 / 文章详情

Docker Engine 安装实战:从 apt 源到离线部署与排错

Docker Engine 安装实战:从 apt 源到离线部署与排错 ★ FEATURED ARTICLE
上一篇文章把 Docker 的版本和发行渠道讲完了这篇直接进入动手环节。目标很纯粹在一台干净的 Linux 机器上把 Docker Engine 装好、跑起来并且以后升级、回滚、卸载都不会翻车。我这些年装过几十台机器Ubuntu、Debian、CentOS、还有一些国产 Linux 发行版都碰过最大的感受是安装命令本身不难真正让人栽跟头的往往在装之前的选型、装之后的生效逻辑以及网络环境带来的各种意外。所以这篇不打算只甩一串apt install给你而是把每一步为什么这么写讲清楚顺带把离线安装和排错经验也一起放了进来。1. 先分清你要装的到底是谁家的 Docker很多人打开搜索框直接敲“Docker 安装”结果跟着一篇老教程装了发行版自带的docker.io等后面要用新特性时才发现版本落后一大截。这里有个背景知识要说清楚Docker 官方提供的核心组件叫 Docker Engine它才是真正干活的守护进程加客户端dockerd、containerd、runc、dockerCLI。而市面上常见的安装来源大概有三类差别非常大。1.1 Docker Engine、Docker Desktop、发行版自带 docker 包三者到底差在哪第一类是 Docker Engine 本身也就是官方download.docker.com仓库里发布的docker-ce社区版系列包。它面向 Linux 服务器不依赖图形界面直接以 systemd 服务运行是生产环境的默认选择。第二类是 Docker Desktop主要给 macOS 和 Windows 开发机用内部跑着一个轻量虚拟机适合日常开发调试但不适合放进服务器。如果你只需要在开发机上跑容器装 Desktop 确实省事但如果你要打理一台 Linux 服务器别从这里入手。第三类是发行版自带的软件包。Debian/Ubuntu 里叫docker.ioFedora 里叫docker它们本质上是 Docker 开源版的再打包只是版本通常滞后有时还混用早期命名习惯依赖关系也未必跟 Docker 官方新组件对上。用它做临时演示可以长期维护不推荐。1.2 我为什么坚持用官方 docker-ce 仓库装 Docker Engine我基本只走官方docker-ce这条路径理由主要有三个版本新安全补丁及时。容器运行时这个东西直接暴露在公网的风险不小CVE 修复靠的是及时升级官方仓库在这方面明显快于发行版自带包。依赖由 apt 统一管理。用 apt 安装升级、卸载、回滚都有干净的记录不会出现“文件明明删了但 systemd 服务还在”这种野路子问题。和生态组件兼容最好。现在的 compose v2、buildx 插件都是 Docker 官方在推进官方仓库会一起更新你用docker compose子命令时不会有“找不到命令”的尴尬。什么情况下我会破例用发行版自带包大概只有两种一是机器完全没法访问外网只能从系统 ISO 或本地软件源里装二是某些安全合规要求指定只能用系统厂商维护的软件分支。这两类场景属于“没得选”的例外。2. 安装前的环境预检三条命令和一条铁律装 Docker 之前我建议你先花三分钟确认三件事系统发行版是什么、内核版本够不够新、机器架构是什么。这三条直接决定你后面用哪份 apt 源、下载哪个 arch 的包。2.1 三条命令快速摸清系统底细cat /etc/os-release uname -r uname -m依次看三块os-release告诉你发行版名称和代号比如 Ubuntu 24.04 的代号是nobleDebian 12 是bookworm后面配 apt 源的时候要拼这个代号uname -r看内核版本Docker Engine 在 Linux 上要求内核不低于 3.10当然现在还在用 3.10 内核的机器已经很少了但 CentOS 7.x 的 3.10 内核确实能跑旧版 Docker只是跑新特性容易出问题uname -m看架构绝大多数服务器是x86_64也有 ARM 机器输出aarch64下载包的时候绝不能下错。另外一个容易被忽略的点是确认系统里是否装了老版本的 Docker 相关包。可以先扫一遍dpkg -l | grep -E docker|containerd || true如果输出为空恭喜干净环境如果列出了一堆docker.io、docker-engine、docker-compose之类的旧包我强烈建议你先把它们卸载掉再走下面的流程。原因是apt 安装时如果发现已有软件包占用了/usr/bin/docker等路径或者 containerd 版本冲突会直接报错后续排查起来很费劲。2.2 磁盘和文件系统比“空间够不够”更隐蔽的前提很多人只关心磁盘剩余空间够不够却忘了 Docker 默认存储驱动是overlay2这个驱动要求底层文件系统支持 d_type 元数据。ext4 一般没问题但如果你把/var/lib/docker放在 XFS 分区上而这个 XFS 分区创建时没有开启ftype1Docker 启动时会打印警告严重时数据完整性都受影响。我建议执行一下df -hT /var/lib/docker看到Type是 ext4 或 xfs且 ftype1就可以放心走。另外/var/lib/docker所在分区要避免使用 NFS、CIFS 这类网络文件系统Docker 在官方文档里也不推荐原因很简单容器层的大量随机读写对网络盘不友好锁和原子性也容易出问题。3. 官方 apt 仓库安装 Docker Engine每一条命令背后的逻辑这一节是全文的重点。我会以 Ubuntu 为例把从加仓库到跑通hello-world的完整过程拆开讲每一行命令都会解释为什么这么写。3.1 基础依赖为什么是这几个先安装前置工具sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg这三个东西各有用途ca-certificates提供 CA 证书链下载 Docker 官方 GPG 密钥和后续走 HTTPS 都得靠它否则会报证书错误curl用来拉取密钥文件gnupg用来验证和转换 GPG 密钥。没有它们后面两步完全走不下去。有些老教程会让你直接装apt-transport-https说没有它 apt 无法走 HTTPS 源。我明确说一下新版 apt 本身已内置 HTTPS 支持不用额外装这个包它已经是过渡期产物了。3.2 添加 GPG 密钥与 apt 源为什么用 keyrings 目录而不是 apt-key接下来执行这段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.gpginstall -m 0755 -d是创建目录并设好权限比mkdir -p更严谨gpg --dearmor把 ASCII 格式的密钥转成二进制格式apt 只认这种最后的chmod ar确保所有用户都能读否则后续 apt update 可能因为权限问题报错。然后是写入源文件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这里有两处细节值得注意。第一signed-by参数显式指定了密钥文件路径这意味着 apt 只会信任这个文件里的密钥来验证 Docker 仓库而不是盲目信任系统里所有已导入的密钥。老教程让你用apt-key add那个方式已经被官方废弃了——它会把密钥导入全局信任区一旦密钥泄露攻击者能伪装任意仓库的包风险太大。第二VERSION_CODENAME会自动取当前系统的发行版代号保证源路径正确。Debian 用户注意如果你的系统是 bookworm、bullseye 等版本命令里ubuntu要换成debian。配好源之后刷新索引sudo apt-get update这一步如果报错十有八九是 GPG 密钥没对、源地址拼错、或者机器连不上download.docker.com。先别急着换源我用第 7 节会专门讲排查思路。3.3 安装 docker-ce 系列包它们各自的分工是什么刷新完成后执行sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin一次性装五个包很多人第一次看会觉得“怎么这么多”。其实它们各有明确职责docker-ce守护进程本体包括dockerd和配套的 systemd 服务文件docker-ce-cli命令行工具也就是你平时敲的docker命令containerd.io容器运行时负责镜像下载、容器生命周期管理等底层工作Docker 是把 containerd 作为底层实现来用的docker-buildx-plugin新版多架构镜像构建插件提供docker buildx子命令docker-compose-plugincompose v2 插件让你能直接敲docker compose而不是去装那个老旧的 Python 版docker-compose。如果你只需要最基础的运行能力前三个就够了但既然都装了建议一次性配齐省得后面用到的时候再补。装完后执行sudo systemctl enable --now dockerenable是设置开机自启--now是立刻启动服务。看到 Active 状态为 active (running)安装环节基本就算过了。3.4 验证安装hello-world 背后到底发生了什么运行官方经典验证命令sudo docker run hello-world如果一切正常会看到一段说明文字。很多人以为这只是“下载个小镜像跑一下”实际上这条命令背后发生了一串事情Docker CLI 通过 unix socket 请求 containerd 启动容器 → 检测到本地没有hello-world镜像 → 从 Docker Hub 拉取 manifest → 下载各层文件 → 解压到/var/lib/docker/overlay2→ 创建容器写层 → 通过 runc 启动进程 → 容器内程序打印信息后退出。整个链路如果某一环断了报错位置各不相同这也是后面排错时要先搞清“卡在哪一步”的原因。如果这一步卡住不动或者直接提示拉取镜像超时别急着怀疑 Docker先想一下这台机器到 Docker Hub 的网络状况。国内网络环境下直连官方镜像仓库经常不稳定我在第 5 节会讲怎么配置镜像加速。4. 连不上官方仓库时离线安装的两种思路很多生产网段是隔离的机器根本没有外网或者只能访问内网软件源。这时候没法直接走apt-get install但 Docker Engine 依然能装上去关键是选对离线方案。4.1 思路一下载 deb 安装包后在目标机器上批量安装这是最接近在线安装的做法。在一台有外网的、同发行版同架构的机器上先用apt-get download或直接去 Docker 官方仓库网页把需要的.deb包下载下来然后拷贝到内网机器用dpkg -i按顺序安装。实际操作时建议在下载机上也添加官方源然后执行cd /tmp apt-get download docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin下载出来的文件名形如containerd.io_1.7.x_amd64.deb、docker-ce_27.x_amd64.deb。把这些文件拷到目标机器后按依赖顺序安装sudo dpkg -i containerd.io_*.deb sudo dpkg -i docker-ce-cli_*.deb sudo dpkg -i docker-ce_*.deb sudo dpkg -i docker-buildx-plugin_*.deb docker-compose-plugin_*.deb顺序很关键containerd.io比docker-ce优先因为后者依赖前者插件包放最后是因为它们依赖主包。如果dpkg -i报缺依赖再补一句sudo apt-get -f install把缺失依赖一并拉进来。离线环境下如果 apt 源里没有这些依赖那就得提前把所有依赖包也一并用apt-get download拉全。4.2 思路二静态二进制 tar.gz 方案如果想要一个极简安装不走任何包管理器可以用 Docker 官方发布的静态二进制包。到download.docker.com/linux/static/stable/下载对应架构的docker-xx.tgz解压后把里面的二进制文件拷贝到/usr/local/bin即可tar xzvf docker-27.x.tgz sudo cp docker/* /usr/local/bin/但注意这个方案只给了可执行文件没有 systemd 服务文件。你需要自己写一个/etc/systemd/system/docker.service里面至少包括dockerd的启动参数和数据目录设置再手动创建 containerd 配置。这条路适合对 Docker 内部结构很熟的人优点是干净、不依赖 apt缺点也明显升级时没有包管理器跟踪文件清单卸载时要自己清理全部二进制和配置容易漏。我把两者放在一起比较对比项deb 包安装静态二进制安装升级方式apt 统一管理可固定版本手动覆盖文件卸载方式apt purge 干净移除手动清理容易残留systemd 服务自带需自己写适合场景内网服务器、生产环境极简容器化系统、临时环境如果你只是要在内网服务器上跑稳定服务别嫌麻烦用 deb 包方案长期维护会省心得多。5. 装好不等于能用镜像加速、非 root 运行和自启动这三件事Docker 装好后我一般会立刻做三件事缺一件后面都会出幺蛾子。5.1 配置镜像加速国内网络环境几乎必做不管你是个人开发机还是公司服务器直连 Docker Hub 拉镜像都很容易被网络问题卡住。Docker 官方提供了一种机制叫 registry mirror镜像加速它只作用于 Docker Hub 镜像的拉取通过编辑/etc/docker/daemon.json来指定加速地址{ registry-mirrors: [ https://your-mirror.example.com ] }把文件中换成你所在网络环境能稳定访问的镜像加速服务地址即可。改完之后必须重启 dockerd 才会生效因为daemon.json只在守护进程启动时读取sudo systemctl daemon-reload sudo systemctl restart docker这个“改完不重启”的坑我踩过不止一次配置文件拷进去了docker pull依然超时后来才发现 dockerd 压根没重新加载配置。你可以用docker info查看 Registry Mirrors 一栏确认加速是否生效。5.2 让普通用户直接敲 docker 命令方便但要清楚风险默认情况下只有 root 或docker组成员才能访问 Docker 的 unix socket。如果你不想每次都在命令前加sudo执行sudo usermod -aG docker $USER然后重新登录当前用户再执行docker ps验证。这里我必须把风险讲透docker组在系统里的权限约等于 root。原因很简单——你只要能控制 Docker 守护进程就能让它挂载宿主机根目录、读取任意文件、甚至执行特权容器。所以这台机器如果有多人登录或者存在不信任的本地用户把他们都塞进 docker 组等于直接给了他们 root 权限。生产环境我建议要么保持 root 操作要么交给 sudo 权限审计不要把组权限当普通用户权限随便发。如果你确实想让普通用户安全地跑容器还有一条路是 Docker Rootless 模式。它需要安装uidmap包然后用dockerd-rootless-setuptool.sh install初始化核心思路是通过用户命名空间把 dockerd 映射到非特权用户空间。代价是部分特性受限比如需要宿主内核开启特定配置而它对网络和 overlay2 的处理也会多一层 NAT 配置。个人开发机可以试试生产环境我一般还是用 root 模式加严格权限管控。5.3 开机自启与防火墙两个最容易被忽略的环节安装完成后默认服务是停止的必须手动启用sudo systemctl enable docker.service containerd.service不执行这条机器重启后 Docker 不会自动起来你会在某个凌晨收到“服务挂了”的告警。防火墙这块是重灾区。Docker 会直接操作宿主机的 iptables 规则给容器网络做 NAT 和端口转发。如果你用了 ufw 或者云安全组默认策略又是 DROP容器内部访问外网会失败。表现就是docker run能启动但进去之后 ping 不通外网。我遇到过一个场景宿主机安全加固脚本把 iptables 的 FORWARD 策略改成 DROP结果所有容器网络全部瘫痪。这个问题在防火墙规则被外部脚本重置后特别常见排查时优先检查iptables -L FORWARD -n的默认策略。6. 升级和卸载干净才能走得远容器的好处是升级方便但前提是你知道怎么不弄脏环境。6.1 升级 Docker Engine 的正确姿势日常升级很简单sudo apt-get update sudo apt-get install --only-upgrade docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin这条命令只升级 Docker 相关包不会顺手动到系统其它包。升级期间 dockerd 会重启正在运行的容器通常不会丢因为容器进程本身由 containerd 管理但宿主机重启或 daemon 升级时策略不同还是建议在低峰期操作。升级完用docker version确认客户端和服务端版本一致避免 CLI 和 daemon 版本差距过大导致的兼容问题。6.2 回滚场景固定版本号的小技巧有些新版本出来后个别环境会出现兼容问题这时候需要回退到旧版本。先用apt-cache madison docker-ce列出可用版本然后指定版本安装sudo apt-get install docker-ce27.0.0-1~ubuntu.24.04~noble回滚时建议把 containerd 和 cli 也固定到对应版本避免混合版本引发诡异行为。我一般会在确认某个版本稳定的机器上把版本号写进部署脚本防止下次apt-get upgrade顺手升级上去。6.3 完整卸载 Docker Engine 的正确顺序清理不干净是卸载 Doker 最常见的坑。如果只是删除软件包/var/lib/docker里的镜像、容器、卷数据会全部残留下次重装还会看到旧数据。完整卸载步骤sudo systemctl stop docker.socket docker.service containerd.service sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo rm -rf /var/lib/docker /var/lib/containerd sudo groupdel dockersystemctl stop先停服务purge删除软件包和配置文件rm -rf清掉镜像层、容器层、卷和日志。如果你确定不再需要这些数据执行rm -rf /var/lib/docker一定要想清楚——这等于把机器上所有容器和镜像全部销毁不可恢复。另外卸载后 iptables 里 Docker 创建的规则通常会被服务停止脚本清掉但偶尔有残留如果发现端口转发规则不干净重启一下 iptables/ufw 服务即可。7. 我实际安装过程中踩过的几个坑完整排查记录最后分享几个我亲测踩过的坑按“现象 → 原因 → 排查 → 解决”的顺序写方便你对号入座。7.1 Docker pull 一直超时卡在等待状态现象docker run hello-world一直卡住或者提示dial tcp ... i/o timeout。原因分两层第一层是网络问题机器到 Docker Hub 的路由不通第二层是配置问题daemon.json里的加速地址写错或没重启 dockerd。我的排查顺序是docker info | grep -A 2 Registry Mirrors curl -I https://registry-1.docker.io/v2/ systemctl cat docker.service | grep ExecStart第一步看加速地址是否生效第二步测网络连通性第三步看 dockerd 启动参数里有没有覆盖配置文件的字段。如果加速地址生效但依然超时那就是加速服务本身不稳定换个镜像源再试。记住所有对daemon.json的改动都要靠systemctl restart docker来激活。7.2 容器能启动但容器内访问外网不通现象docker run -it alpine sh进去后 ping 外网 IP 不通但宿主机正常。原因宿主机 iptables FORWARD 链默认策略变成了 DROPDocker 的转发规则被外部脚本或安全加固覆盖了。排查步骤iptables -L FORWARD -n iptables -P FORWARD ACCEPT systemctl restart docker把 FORWARD 策略恢复为 ACCEPT 后重启 Docker 让它重新生成自己的规则。如果这一步解决了说明是策略问题如果重启后又被改回去去检查宿主机上有没有安全脚本周期性重设规则比如某些云平台的安全组插件这时候要么调白名单要么在脚本里跳过 Docker 的接口段。7.3 报错 no space left on device但 df 一看磁盘还有几十 GB现象拉镜像或构建镜像时突然报no space left on device但你df -h看磁盘还有很多余量。原因这个报错不一定指磁盘满了也可能是/var/lib/docker所在分区的 inode 用光了或者 overlay2 在构建镜像时临时层空间不足。df 的-h显示的是块使用率要看df -i才知道 inode 使用率。排查df -i /var/lib/docker df -hT /var/lib/dockerinode 满了的常见原因是大量小文件堆积比如无数次构建产生的临时层。解决思路是清理悬空镜像和构建缓存docker system prune -af docker builder prune -af如果是在长期运行的服务器上我建议给/var/lib/docker单独分一个分区并且保留 20% 到 30% 的空余尤其是经常构建镜像的机器临时层空间需求远比预想的大。7.4 WSL2 环境下 systemd 相关命令报错现象在 Windows 的 WSL2 里安装了 Docker Engine执行systemctl enable docker报错提示 systemd 没有运行。原因默认 WSL2 镜像不跑 systemd服务管理命令自然无效。新版 WSL20.67.8 以后支持在/etc/wsl.conf里开启 systemd[boot] systemdtrue改完在 Windows 侧执行wsl --shutdown重启 WSL再进入 Linux 里systemctl status docker服务就能正常管理了。如果不想开 systemd也可以用sudo service docker start手动启动但这样容器的开机自启和日志管理都会受限制所以我还是推荐把 systemd 打开。最后再说一点切身体会装 Docker Engine 这件事难度从来不在“执行几条命令”而在于装之前想清楚选哪个安装源装之后弄明白配置何时生效、网络规则如何被影响。我刚开始用 Docker 时也踩过不少坑最贵的一次是在一台重要服务器上直接用了发行版自带的旧 docker 包导致后来部署新项目时功能对不上。从那以后我养成了一个习惯每台新机器动手前先跑一遍第 2 节那三条预检命令。这套流程看起来麻烦实际上五分钟就能做完但它能帮你省下后面无数排查时间。希望这篇能让你少走点弯路。
阅读完成 · 觉得有帮助?
咨询建站