1. 项目概述与核心场景解析
在服务器运维、工业控制、安全隔离网络或出海部署等场景下,我们常常会面对一个非常现实的问题:目标Linux服务器无法连接互联网。可能是出于安全策略的硬性规定,可能是部署在物理隔离的专网中,也可能是身处网络环境极不稳定的偏远地区。此时,当我们需要部署一套现代化的应用环境,Docker几乎总是首选方案,因为它能解决环境一致性和依赖隔离的世纪难题。然而,apt-get install docker.io或yum install docker-ce这类简单的在线安装命令在此刻完全失效。
“Linux环境离线安装Docker”这个需求,本质上是一场精密的“后勤补给”行动。它考验的不是你对Docker命令有多熟悉,而是你对Linux软件依赖管理、系统架构差异和离线包分发的全局掌控能力。我经历过多次从零开始的离线部署,从金融行业的保密机房到野外移动的集装箱数据中心,每一次成功部署的背后,都是一套经过验证的、可复现的离线安装方法论。这篇文章,我将为你彻底拆解这个过程,不仅告诉你每一步怎么做,更会解释为什么这么做,以及那些只有踩过坑才知道的“潜规则”。
2. 离线安装的核心思路与准备工作
离线安装的核心思路可以概括为:在一台网络通畅的、与目标服务器系统环境尽可能一致的“制备机”上,完成所有在线操作,然后将生成的离线安装包完整地搬运到目标“离线机”上进行部署。这个过程环环相扣,任何一个环节的疏漏都可能导致最终失败。
2.1 环境侦察与一致性保障
在开始任何操作之前,充分的侦察是成功的一半。你需要明确以下信息,这远比盲目下载一个Docker安装包重要得多。
目标服务器(离线机)的系统信息:
- 发行版与版本: 是CentOS 7.9还是Ubuntu 20.04?是ARM架构的银河麒麟还是x86_64的RHEL?使用
cat /etc/os-release和uname -m命令确认。不同发行版的包管理器和依赖库天差地别。 - 内核版本: Docker对内核有最低要求(通常3.10以上),且某些存储驱动(如overlay2)需要更高版本的内核支持。使用
uname -r查看。 - 系统架构:
x86_64(amd64),aarch64(arm64),ppc64le等。这直接决定了你需要下载哪个架构的Docker二进制包和依赖包。
- 发行版与版本: 是CentOS 7.9还是Ubuntu 20.04?是ARM架构的银河麒麟还是x86_64的RHEL?使用
制备机的选择:
- 理想情况: 使用一台与目标服务器发行版、主版本号、系统架构完全一致的虚拟机或临时云主机作为制备机。这是避免依赖地狱的最优解。
- 次优情况: 如果无法做到完全一致,至少保证发行版家族和架构相同(例如,同为CentOS 7系列的x86_64机器)。此时需要更仔细地处理依赖关系。
安装路径规划:
- 在制备机上,你需要规划一个用于存放所有离线文件的目录,例如
/opt/docker-offline。这个目录最终会被完整地打包,传输到离线机。 - 在离线机上,也需要规划一个对应的解压目录,并确保有足够的磁盘空间(通常1-2GB足够)。
- 在制备机上,你需要规划一个用于存放所有离线文件的目录,例如
注意:千万不要尝试在Ubuntu制备机上为CentOS目标机准备离线包,反之亦然。它们的依赖包命名、系统服务管理方式(systemd vs. sysvinit)完全不同,强行混用几乎百分百失败。
2.2 工具选型与方案对比
离线安装Docker主要有三种主流方案,每种方案适用于不同的场景和需求层次。
| 方案 | 核心原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 方案一:使用官方离线二进制包 | 直接下载Docker引擎(dockerd)和客户端(docker)的静态编译二进制文件,以及containerd、runc等组件。 | 1.最干净、依赖最少,几乎与系统发行版无关。 2. 版本控制灵活,可以安装任意指定版本。 3. 官方推荐方式,升级和降级方便。 | 1. 需要手动配置系统服务(systemd unit文件)。 2. 需要自行处理命令行补全、用户组等周边配置。 | 首选方案,尤其适用于对系统纯净度要求高、或发行版较老/较特殊(如某些国产化OS)的环境。 |
| 方案二:下载全量RPM/DEB包 | 利用yum downloadonly或apt download命令,将Docker及其所有依赖包下载到本地。 | 1. 符合系统原生包管理习惯,安装后可以用yum或apt查询。2. 自动处理依赖关系和系统服务配置。 | 1.依赖包可能非常多,特别是首次安装,可能涉及上百个包。 2. 对制备机和目标机的环境一致性要求极高,稍有不符就可能安装失败。 | 适用于目标机环境标准、且与制备机高度一致的场景。对运维人员更友好。 |
| 方案三:搭建本地镜像仓库 | 在离线环境中搭建一个私有的Docker镜像仓库(如Harbor)和软件包仓库(如本地Yum/Deb源)。 | 1.一劳永逸,一次搭建,后续所有机器安装、所有镜像拉取都走内网。 2. 便于统一管理和安全审计。 | 1.初始搭建复杂,成本高。 2. 需要额外的服务器资源来运行仓库服务。 | 适用于大型离线集群、需要持续进行软件分发和镜像管理的生产环境。 |
对于大多数初次进行离线安装的工程师,我强烈推荐从方案一(官方二进制包)开始。它逻辑清晰,受系统环境影响最小,是理解Docker离线部署本质的最佳路径。本文将重点详解方案一,并在最后简要说明方案二的关键步骤和避坑点。
3. 方案一详解:使用官方二进制包离线安装
这是最通用、最可靠的离线安装方法。我们将遵循“下载 -> 传输 -> 安装 -> 配置”的流程。
3.1 在制备机上下载所需文件
首先,在你的联网制备机上,创建一个工作目录并进入。
mkdir -p /opt/docker-offline && cd /opt/docker-offline第一步:下载Docker二进制压缩包访问Docker官方GitHub的Release页面:https://github.com/moby/moby/releases。但更推荐使用Docker官方提供的静态二进制包下载链接,它包含了所有必需组件。
你可以使用curl或wget下载。这里以当前较稳定的版本24.0.9为例,注意替换成你需要的版本和架构(这里用x86_64)。
# 下载 Docker 二进制包 DOCKER_VERSION="24.0.9" ARCH="x86_64" # 根据目标机架构调整:x86_64, aarch64, armhf等 wget https://download.docker.com/linux/static/stable/${ARCH}/docker-${DOCKER_VERSION}.tgz # 验证文件(可选但推荐) wget https://download.docker.com/linux/static/stable/${ARCH}/docker-${DOCKER_VERSION}.tgz.sha256sum sha256sum -c docker-${DOCKER_VERSION}.tgz.sha256sum第二步:下载容器运行时containerdDocker引擎依赖于containerd作为其容器运行时。同样需要下载对应版本。
# 去 containerd 的 GitHub Release 页面查找版本,确保与Docker版本兼容。 # 例如 containerd-1.6.28 CONTAINERD_VERSION="1.6.28" wget https://github.com/containerd/containerd/releases/download/v${CONTAINERD_VERSION}/containerd-${CONTAINERD_VERSION}-linux-${ARCH}.tar.gz第三步:准备系统服务配置文件Docker需要以系统服务(systemd)的形式运行。我们需要准备两个关键的service文件。
containerd.service: containerd的服务文件。docker.service: Docker引擎的服务文件。
你可以从Docker官方安装脚本或已安装的系统中获取这些文件。这里提供一个快速生成的方法(在制备机上,如果你有docker-ce的repo,可以安装后提取):
# 方法A:如果你能在制备机上临时安装docker-ce(用于提取文件) # sudo yum install -y yum-utils # sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # sudo yum install -y docker-ce docker-ce-cli containerd.io # 然后从 /usr/lib/systemd/system/ 拷贝 docker.service 和 containerd.service # 方法B:手动创建(更通用) cat > docker.service << 'EOF' [Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com After=network-online.target firewalld.service containerd.service Wants=network-online.target Requires=containerd.service [Service] Type=notify ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock ExecReload=/bin/kill -s HUP $MAINPID TimeoutSec=0 RestartSec=2 Restart=always StartLimitBurst=3 StartLimitInterval=60s LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity TasksMax=infinity Delegate=yes KillMode=process OOMScoreAdjust=-500 [Install] WantedBy=multi-user.target EOF cat > containerd.service << 'EOF' [Unit] Description=containerd container runtime Documentation=https://containerd.io After=network.target local-fs.target [Service] ExecStartPre=-/sbin/modprobe overlay ExecStart=/usr/local/bin/containerd Type=notify Delegate=yes KillMode=process Restart=always RestartSec=5 LimitNPROC=infinity LimitCORE=infinity LimitNOFILE=infinity TasksMax=infinity OOMScoreAdjust=-999 [Install] WantedBy=multi-user.target EOF第四步:准备安装脚本和依赖检查脚本为了让离线机上的操作自动化,我们编写一个安装脚本install.sh和一个环境检查脚本check_env.sh。
check_env.sh用于在安装前验证系统环境:
cat > check_env.sh << 'EOF' #!/bin/bash echo "=== 开始 Docker 离线安装环境检查 ===" # 1. 检查内核版本 KERNEL_VERSION=$(uname -r | cut -d- -f1) KERNEL_MAJOR=$(echo $KERNEL_VERSION | cut -d. -f1) KERNEL_MINOR=$(echo $KERNEL_VERSION | cut -d. -f2) echo "内核版本: $KERNEL_VERSION" if [[ $KERNEL_MAJOR -lt 3 ]] || ([[ $KERNEL_MAJOR -eq 3 ]] && [[ $KERNEL_MINOR -lt 10 ]]); then echo "警告:内核版本低于3.10,Docker可能无法正常工作。" fi # 2. 检查是否支持 overlay2 存储驱动 grep -q overlay /proc/filesystems if [ $? -ne 0 ]; then echo "警告:内核可能不支持 overlay 文件系统,建议升级内核或使用 devicemapper 驱动。" fi # 3. 检查 cgroups 和命名空间支持 echo "检查 cgroup 挂载..." if mount | grep -q cgroup; then echo "cgroup 已挂载。" else echo "错误:未找到 cgroup 挂载,请确保系统已启用cgroup支持。" exit 1 fi # 4. 检查架构 ARCH=$(uname -m) echo "系统架构: $ARCH" if [[ $ARCH != "x86_64" ]] && [[ $ARCH != "aarch64" ]]; then echo "警告:当前架构 $ARCH 可能不是官方主要支持架构,请确认二进制包兼容性。" fi echo "=== 环境检查完成 ===" EOF chmod +x check_env.shinstall.sh是主安装脚本:
cat > install.sh << 'EOF' #!/bin/bash set -e OFFLINE_DIR=$(cd "$(dirname "$0")"; pwd) DOCKER_VERSION="24.0.9" # 需要与下载的包版本一致 ARCH="x86_64" echo "=== 开始离线安装 Docker $DOCKER_VERSION ===" # 1. 解压 Docker 二进制包 echo "解压 Docker 二进制包..." sudo tar -xzf ${OFFLINE_DIR}/docker-${DOCKER_VERSION}.tgz -C /usr/local/bin/ --strip-components=1 # 2. 解压 containerd echo "解压 containerd..." sudo tar -xzf ${OFFLINE_DIR}/containerd-*-linux-${ARCH}.tar.gz -C /usr/local/bin/ # 3. 创建 systemd 服务配置文件 echo "配置 systemd 服务..." sudo cp ${OFFLINE_DIR}/docker.service /etc/systemd/system/ sudo cp ${OFFLINE_DIR}/containerd.service /etc/systemd/system/ # 4. 创建 docker 用户组(如果不存在) echo "配置用户组..." sudo groupadd docker 2>/dev/null || true # 5. 重新加载 systemd 并启用服务 echo "加载 systemd 配置..." sudo systemctl daemon-reload sudo systemctl enable containerd.service sudo systemctl enable docker.service # 6. 启动服务 echo "启动 containerd 和 docker 服务..." sudo systemctl start containerd sudo systemctl start docker # 7. 验证安装 echo "验证 Docker 安装..." sudo docker version --format 'Client: {{.Client.Version}}\nServer: {{.Server.Version}}' if [ $? -eq 0 ]; then echo "=== Docker 离线安装成功! ===" echo "提示:将需要使用docker的用户加入'docker'用户组,例如:sudo usermod -aG docker $USER" echo " 然后退出当前终端重新登录即可生效。" else echo "=== Docker 启动验证失败,请检查日志:journalctl -u docker.service ===" exit 1 fi EOF chmod +x install.sh现在,你的/opt/docker-offline目录下应该包含:
docker-24.0.9.tgzcontainerd-1.6.28-linux-x86_64.tar.gzdocker.servicecontainerd.serviceinstall.shcheck_env.sh
使用tar命令将这个目录打包,准备传输。
cd /opt tar -czf docker-offline-pkg.tar.gz docker-offline/3.2 在目标离线机上的安装操作
将打包好的docker-offline-pkg.tar.gz文件通过U盘、内网SFTP或其他离线方式,传输到目标服务器上。假设你将其放在了目标服务器的/tmp目录。
# 1. 将传输过来的包解压到合适位置,例如 /opt sudo mkdir -p /opt sudo tar -xzf /tmp/docker-offline-pkg.tar.gz -C /opt/ # 2. 进入解压后的目录 cd /opt/docker-offline # 3. (强烈建议)运行环境检查脚本 sudo ./check_env.sh # 4. 执行安装脚本 sudo ./install.sh安装脚本会自动完成二进制文件拷贝、服务配置和启动。如果一切顺利,运行docker version和sudo systemctl status docker应该能看到成功的信息。
3.3 安装后的关键配置与优化
安装成功只是第一步,要让Docker在离线环境下好用,还需要进行一些关键配置。
1. 配置用户组:为了避免每次使用docker命令都要加sudo,需要将当前用户加入docker用户组。
sudo usermod -aG docker $USER重要:执行此命令后,必须退出当前终端会话并重新登录,组权限变更才会生效。你可以通过newgrp docker命令在当前会话临时生效,但重新登录是更彻底的方式。
2. 配置镜像加速器与私有仓库(针对离线环境):在离线环境中,无法从Docker Hub拉取镜像。你需要提前在有网环境将所需的基础镜像(如ubuntu:20.04,nginx:alpine,redis:latest等)拉取下来,保存为tar包,然后导入到离线机。
在制备机上拉取并保存镜像:
docker pull nginx:alpine docker save -o nginx-alpine.tar nginx:alpine # 将生成的 .tar 文件随离线包一起传输在离线机上加载镜像:
docker load -i nginx-alpine.tar配置Docker Daemon(可选,为未来连接私有仓库准备):如果内网有私有镜像仓库(如Harbor),需要修改Docker Daemon配置。编辑
/etc/docker/daemon.json(如果不存在则创建):{ "insecure-registries": ["your.private.registry:5000"], "registry-mirrors": [] }然后重启Docker服务:
sudo systemctl restart docker。
3. 配置日志与存储驱动:对于生产环境,建议配置日志轮转和存储驱动。编辑/etc/docker/daemon.json:
{ "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" }, "storage-driver": "overlay2" }overlay2是现代Linux内核的推荐存储驱动。如果环境检查时提示不支持,可能需要回退到devicemapper(需安装device-mapper-persistent-data和lvm2),但这在离线环境下会更复杂。
4. 方案二关键步骤与避坑指南
如果你决定使用方案二(全量RPM/DEB包),其核心命令如下:
对于CentOS/RHEL/Fedora(使用yum/dnf):
# 在制备机上 sudo yum install -y yum-utils # 添加Docker官方Yum源(如果尚未添加) sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo # 下载所有依赖包到指定目录,不安装 sudo yum install --downloadonly --downloaddir=/opt/docker-offline-rpms docker-ce docker-ce-cli containerd.io对于Ubuntu/Debian(使用apt):
# 在制备机上 sudo apt-get update sudo apt-get install -y dpkg-dev # 添加Docker官方Apt源(如果尚未添加) # ... 添加源的操作 ... sudo apt-get update # 下载所有依赖包 sudo apt-get download $(apt-cache depends --recurse --no-recommends --no-suggests --no-conflicts --no-breaks --no-replaces --no-enhances docker-ce docker-ce-cli containerd.io | grep "^\w" | sort -u) # 将所有.deb文件移动到 /opt/docker-offline-debs关键避坑点:
- 依赖爆炸: Docker的依赖链可能非常长,特别是首次安装。
yum downloadonly下载的包可能包含系统已有但版本不同的包,导致离线安装时冲突。一个更稳妥的方法是,在制备机上先安装一遍Docker,然后使用yum reinstall --downloadonly来下载,这样能确保下载的包版本与已安装的完全一致。 - 环境锁死: 制备机和目标机的小版本号必须尽可能一致。比如,制备机是CentOS 7.9.2009,目标机也必须是7.9.x。否则,即使大版本相同,某些底层库(如
glibc)的微小版本差异也可能导致依赖解析失败。 - 安装顺序: 将下载的包传输到离线机后,安装时不能简单地使用
yum localinstall *.rpm。因为这会绕过Yum的依赖解析,可能因安装顺序错误而失败。正确做法是,在离线机上创建一个本地Yum源,然后用yum install命令安装。这需要额外配置createrepo工具和本地repo文件,步骤更复杂,但能完美解决依赖问题。 - 签名校验: 离线安装RPM包时,可能会遇到GPG密钥校验失败。你需要将Docker官方的GPG密钥也一并下载并导入到离线机。
由于方案二的复杂性和对环境一致性的苛刻要求,在不确定环境完全一致的情况下,方案一的二进制包方式成功率要高得多。
5. 常见问题排查与实战心得
即使按照步骤操作,在真实的离线环境中仍可能遇到各种问题。以下是我总结的常见问题及排查思路。
5.1 服务启动失败:Failed to start Docker Application Container Engine.
这是最常见的问题。首先使用sudo journalctl -u docker.service -xe --no-pager查看详细的启动日志。错误通常集中在以下几点:
overlay2驱动不支持: 日志中可能出现\"overlay2\" is not supported over overlayfs或类似信息。这通常是因为根文件系统本身就是overlayfs(例如某些云主机或容器内)。解决方案是修改/etc/docker/daemon.json,将storage-driver改为vfs(性能差,仅作测试)或devicemapper(需额外配置)。cgroup挂载问题: 日志提示cgroup相关错误。检查/proc/filesystems是否包含cgroup和cgroup2。对于较老的系统,可能需要手动挂载或在内核启动参数中启用cgroup。iptables/firewalld冲突: Docker会操作iptables规则。如果系统防火墙(firewalld)正在运行且规则严格,可能会冲突。可以尝试暂时停止firewalld (sudo systemctl stop firewalld) 再启动Docker,以确认是否是防火墙问题。长期方案是配置firewalld放行Docker网络。/var/run/docker.sock权限问题: 确保/var/run/docker.sock的所属组是docker,并且相应用户已加入docker组。
5.2 命令执行报错:Got permission denied while trying to connect to the Docker daemon socket
这个问题几乎总是因为用户没有加入docker组。请确认:
- 已执行
sudo usermod -aG docker $USER。 - 已重新登录终端或开启新的会话。仅仅
newgrp docker可能在某些环境下不彻底。 - 检查
/var/run/docker.sock的权限:ls -l /var/run/docker.sock,应显示类似srw-rw---- 1 root docker ...。
5.3 离线环境下如何管理镜像?
这是离线部署后的核心运维问题。你需要建立一套离线镜像管理流程:
- 镜像导出与导入: 如前所述,使用
docker save和docker load。对于多个镜像,可以保存为单个文件:docker save -o all-images.tar image1:tag1 image2:tag2。 - 使用私有仓库: 对于长期、多节点的离线环境,强烈建议在离线网络内部搭建一个私有镜像仓库(如Harbor)。这样,所有机器都可以从内网仓库拉取镜像,管理效率和体验与有网环境无异。Harbor本身也支持离线安装。
- 制作自定义基础镜像: 在有网环境,基于官方镜像安装好所有常用工具(如
vim,curl,net-tools),然后提交为新的基础镜像并导出。这样可以避免在离线环境下每个容器都重复安装基础工具。
5.4 内核版本过低怎么办?
如果目标服务器内核版本低于3.10,官方Docker可能无法运行或功能受限。你有几个选择:
- 升级内核: 这是最根本的解决方案。离线升级内核同样需要准备对应版本的内核RPM/DEB包及其依赖,风险较高,需充分测试。
- 使用旧版Docker: Docker早期版本(如18.06)对内核要求稍低。但旧版本存在已知漏洞,不推荐用于生产。
- 考虑替代方案: 如果环境实在无法升级,可以考虑使用其他容器技术,如Podman(在某些配置下对内核要求可能不同),但这需要重新评估生态和兼容性。
5.5 实战心得:清单与验证
每次进行离线部署前,我习惯列一个清单,并在每个步骤后打勾验证:
- [ ]制备机与目标机系统信息核对(发行版、版本、架构)
- [ ]二进制包版本确认(Docker, containerd版本兼容性)
- [ ]依赖文件齐全(二进制包、service文件、安装脚本)
- [ ]传输过程文件完整性校验(使用
md5sum或sha256sum) - [ ]目标机环境预检查(内核、存储驱动、cgroup)
- [ ]安装脚本执行权限与路径确认
- [ ]安装后服务状态与日志检查
- [ ]基础功能测试(
docker run hello-world或运行一个简单的busybox容器) - [ ]用户组与权限配置验证
- [ ]镜像导入与运行测试
这份清单能极大减少因粗心导致的返工。离线安装没有重试的机会,一次做对是最有效率的方式。最后,记住在一切就绪后,给这个精心准备的离线安装包目录做一个备份归档,并附上详细的版本说明文档。当下一次需要在类似环境中部署时,你会感谢自己今天的这份细致。