Docker 离线安装
大约 11 分钟约 3283 字
Docker 离线安装
工作准备
# 准备一台正常访问外网的CentOS7虚拟机,用于官方镜像下载导出
# 访问https://download.docker.com/linux/static/stable/x86_64/站点下载需要的docker版本二进制文件
# 以下用docker-20.10.9.tgz作为示例
# 上传docker-20.10.9.tgz至需要安装的虚拟机工作准备详解
# ====== 版本选择 ======
# Docker 二进制包下载地址
# https://download.docker.com/linux/static/stable/x86_64/
# https://download.docker.com/linux/static/test/x86_64/
# 常用版本
# docker-20.10.9.tgz - Docker 20.10 (稳定版)
# docker-20.10.24.tgz - Docker 20.10 (最新补丁)
# docker-24.0.7.tgz - Docker 24.0
# docker-25.0.3.tgz - Docker 25.0
# ====== 下载方法 ======
# 方法 1:直接下载(有网环境)
wget https://download.docker.com/linux/static/stable/x86_64/docker-20.10.9.tgz
# 方法 2:使用 curl
curl -O https://download.docker.com/linux/static/stable/x86_64/docker-20.10.9.tgz
# 方法 3:国内镜像加速
wget https://mirrors.aliyun.com/docker-ce/linux/static/stable/x86_64/docker-20.10.9.tgz
# ====== 校验文件完整性 ======
md5sum docker-20.10.9.tgz
sha256sum docker-20.10.9.tgz
# ====== 传输到离线服务器 ======
# 方法 1:scp
scp docker-20.10.9.tgz root@offline-server:/tmp/
# 方法 2:U盘/移动硬盘拷贝
# 方法 3:内部文件服务器下载
# ====== 离线环境检查 ======
# 确认目标机器的系统版本
cat /etc/redhat-release
uname -r
# 确认内核版本(Docker 要求 3.10+)
uname -r
# 确认架构
uname -m
# x86_64 或 aarch64开始离线安装Docker
解压docker软件压缩包
tar -zxvf docker-20.10.9.tgz把docker文件里面的内容复制到bin目录下
cp docker/* /usr/bin
#输入y确认 ,如出现文件列表,进入命令模式重新执行一下安装步骤详解
# ====== 完整离线安装步骤 ======
# 1. 解压 Docker 二进制包
mkdir -p /tmp/docker-install
tar -zxf docker-20.10.9.tgz -C /tmp/docker-install
# 2. 复制二进制文件到系统路径
cp /tmp/docker-install/docker/* /usr/bin/
# 验证文件是否复制成功
ls -la /usr/bin/docker*
docker version
# 3. 创建 Docker 组
groupadd docker
# 4. 将当前用户加入 docker 组(可选)
usermod -aG docker root
# 5. 创建必要目录
mkdir -p /etc/docker
mkdir -p /var/lib/docker
mkdir -p /var/run/docker
# 6. 配置内核参数
modprobe overlay
modprobe br_netfilter
cat > /etc/sysctl.d/docker.conf << 'EOF'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl -p /etc/sysctl.d/docker.conf在/etc/systemd/system目录下创建文件 docker.socket和docker.service以及containerd.service
cd /etc/systemd/system
vi docker.socke
# ====================内容=============================
[Unit]
Description=Docker Socket for the API
PartOf=docker.service
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
# ====================内容=============================
#保存退出
vi docker.service
# ====================内容=============================
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network.target
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
#ExecStart=/usr/bin/dockerd
#ExecStart=/usr/bin/docker daemon --tlsverify --tlscacert=/root/openssl/ca.pem --tlscert=/root/openssl/server-cert.pem --tlskey=/root/openssl/server-key.pem --registry-mirror=http://3cda3ca9.m.daocloud.io -H tcp://0.0.0.0:2376
#ExecStart=/usr/bin/docker daemon --registry-mirror=http://3cda3ca9.m.daocloud.io -H fd:// -H tcp://0.0.0.0:2375
#ExecStart=/usr/bin/dockerd --registry-mirror=http://3cda3ca9.m.daocloud.io
ExecStart=/usr/bin/dockerd --registry-mirror=http://3cda3ca9.m.daocloud.io -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375
ExecReload=/bin/kill -s HUP $MAINPID
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
# Uncomment TasksMax if your systemd version supports it.
# Only systemd 226 and above support this version.
#TasksMax=infinity
TimeoutStartSec=0
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process
[Install]
WantedBy=multi-user.target
# ====================内容=============================
#保存退出
vi containerd.service
# ====================内容=============================
# Copyright The containerd Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[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
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity
LimitNOFILE=infinity
# Comment TasksMax if your systemd version does not supports it.
# Only systemd 226 and above support this version.
TasksMax=infinity
OOMScoreAdjust=-999
[Install]
WantedBy=multi-user.target
# ====================内容=============================
#保存退出重新加载配置文件
systemctl daemon-reload创建组
groupadd docker启动docker
systemctl start docker设置开机自启动
# 执行此命令初次会展示创建links,如不放心执行两遍
systemctl enable docker.service检查是否报错
docker ps完整的服务管理命令
# ====== 服务管理 ======
systemctl daemon-reload # 重新加载 systemd 配置
systemctl start docker # 启动 Docker
systemctl stop docker # 停止 Docker
systemctl restart docker # 重启 Docker
systemctl status docker # 查看 Docker 状态
systemctl enable docker # 设置开机自启
systemctl disable docker # 取消开机自启
# ====== 验证安装 ======
docker version # 查看版本
docker info # 查看系统信息
docker ps # 查看运行中的容器
docker run --rm hello-world # 运行测试容器
# ====== 配置 Docker ======
# 创建 Docker 配置文件
cat > /etc/docker/daemon.json << 'EOF'
{
"storage-driver": "overlay2",
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
},
"registry-mirrors": [],
"insecure-registries": [],
"data-root": "/var/lib/docker",
"exec-opts": ["native.cgroupdriver=systemd"],
"live-restore": true
}
EOF
# 如果有内网镜像仓库,配置 insecure-registries
# "insecure-registries": ["192.168.1.100:5000"]
# 重启 Docker 使配置生效
systemctl restart docker
# 验证配置
docker info | grep -A5 "Storage Driver"
docker info | grep -A5 "Registry Mirrors"离线安装一键脚本
#!/bin/bash
# docker_offline_install.sh
# Docker 离线安装脚本
set -euo pipefail
DOCKER_PKG="docker-20.10.9.tgz"
INSTALL_DIR="/tmp/docker-install"
echo "=== Docker 离线安装开始 ==="
# 1. 解压
echo "[1/6] 解压 Docker 二进制包..."
mkdir -p "$INSTALL_DIR"
tar -zxf "$DOCKER_PKG" -C "$INSTALL_DIR"
# 2. 复制二进制文件
echo "[2/6] 复制二进制文件到 /usr/bin..."
cp "$INSTALL_DIR"/docker/* /usr/bin/
# 3. 创建 Docker 组
echo "[3/6] 创建 docker 组..."
grep -q docker /etc/group || groupadd docker
# 4. 配置内核参数
echo "[4/6] 配置内核参数..."
modprobe overlay 2>/dev/null || true
modprobe br_netfilter 2>/dev/null || true
cat > /etc/sysctl.d/docker.conf << 'SYSCTL'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
SYSCTL
sysctl -p /etc/sysctl.d/docker.conf 2>/dev/null || true
# 5. 创建 Docker 配置
echo "[5/6] 创建 Docker 配置..."
mkdir -p /etc/docker
mkdir -p /var/lib/docker
mkdir -p /var/run/docker
cat > /etc/docker/daemon.json << 'DAEMON'
{
"storage-driver": "overlay2",
"log-driver": "json-file",
"log-opts": {"max-size": "100m", "max-file": "3"}
}
DAEMON
# 6. 创建 systemd 服务
echo "[6/6] 创建 systemd 服务..."
cat > /etc/systemd/system/docker.socket << 'SOCKET'
[Unit]
Description=Docker Socket for the API
PartOf=docker.service
[Socket]
ListenStream=/var/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker
[Install]
WantedBy=sockets.target
SOCKET
cat > /etc/systemd/system/docker.service << 'SERVICE'
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network.target
[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
SERVICE
# 启动服务
systemctl daemon-reload
systemctl enable docker
systemctl start docker
# 验证
echo ""
echo "=== 安装验证 ==="
docker version
docker info 2>/dev/null | head -20
docker run --rm hello-world 2>/dev/null || echo "hello-world 镜像不可用(离线环境正常)"
echo ""
echo "=== Docker 离线安装完成 ==="
echo "Docker 版本: $(docker version --format '{{.Server.Version}}')"
echo "数据目录: /var/lib/docker"
echo "配置文件: /etc/docker/daemon.json"准备离线镜像包
提示
以下操作,离线环境下无法拉取镜像包通用
使用有网环境下载镜像文件并上传启动运行
# 以rabbitmq 为参照示例
#拉取镜像
docker pull rabbitmq:management
# 导出镜像
#-o 可指定存放路径,此命令示范为当前文件夹
docker save -o rabbitmq.tar rabbitmq:management
#下载rabbitmq.tar转移至离线虚拟机镜像管理详解
# ====== 在有网环境准备镜像 ======
# 方法 1:docker save 导出单个镜像
docker pull nginx:1.27-alpine
docker save -o nginx.tar nginx:1.27-alpine
# 方法 2:docker save 导出多个镜像到一个文件
docker pull mysql:5.7
docker pull redis:7-alpine
docker save -o middleware.tar mysql:5.7 redis:7-alpine
# 方法 3:使用 docker export(不推荐,会丢失历史层)
docker export my-container > my-container.tar
# ====== 压缩镜像(节省传输空间) ======
gzip nginx.tar
# 生成 nginx.tar.gz
# ====== 镜像版本管理 ======
# 建议使用明确的版本标签,不使用 latest
docker pull nginx:1.27-alpine # 推荐
docker pull mysql:5.7.44 # 推荐
docker pull redis:7.2.4-alpine # 推荐
docker pull rabbitmq:3.12-management # 推荐
# ====== 批量导出脚本 ======
#!/bin/bash
# save_images.sh - 批量保存镜像
IMAGES=(
"nginx:1.27-alpine"
"mysql:5.7.44"
"redis:7.2.4-alpine"
"rabbitmq:3.12-management"
"python:3.11-slim"
"node:20-alpine"
"openjdk:17-jdk-slim"
)
for img in "${IMAGES[@]}"; do
echo "Pulling $img..."
docker pull "$img"
done
echo "Saving all images..."
docker save -o all-images.tar "${IMAGES[@]}"
echo "Compressing..."
gzip all-images.tar
echo "Done: all-images.tar.gz ($(du -h all-images.tar.gz | cut -f1))"上传后导入镜像并运行
#上传后cd至上传目录执行以下命令导入镜像
docker load < ./rabbitmq.tar
#运行docker images查看是否存在镜像
docker images
#运行rabbitmq
# 创建本地目录
mkdir -p /usr/local/docker/rabbitmq/1/lib
mkdir -p /usr/local/docker/rabbitmq/1/log
chmod -R 777 /usr/local/docker/rabbitmq/1/log
#运行容器 RABBITMQ_DEFAULT_PASS 自定定义密码 111111只是示范
sudo docker run -d \
--restart=always \
--hostname rabbitmq \
--name rabbitmq \
-p 15672:15672 \
-p 5672:5672 \
-e RABBITMQ_DEFAULT_USER=admin \
-e RABBITMQ_DEFAULT_PASS=111111 \
-e RABBITMQ_ERLANG_COOKIE='rabbitmq_cookie' \
--privileged=true \
-v /usr/local/docker/rabbitmq/1/lib:/var/lib/rabbitmq \
-v /usr/local/docker/rabbitmq/1/log:/var/log/rabbitmq \
rabbitmq:management
#运行docker ps 查看是否运行成功
docker ps镜像导入详解
# ====== 导入镜像 ======
# 方法 1:docker load(推荐)
docker load < rabbitmq.tar
docker load -i rabbitmq.tar
# 如果镜像文件是 gzip 压缩的
docker load < rabbitmq.tar.gz
gunzip -c rabbitmq.tar.gz | docker load
# 方法 2:从压缩包直接导入
gunzip rabbitmq.tar.gz
docker load -i rabbitmq.tar
# ====== 验证镜像 ======
docker images
docker inspect rabbitmq:management
# ====== 批量导入脚本 ======
#!/bin/bash
# load_images.sh - 批量导入镜像
IMAGE_DIR="/path/to/images"
for f in "$IMAGE_DIR"/*.tar; do
echo "Loading $f..."
docker load -i "$f"
done
for f in "$IMAGE_DIR"/*.tar.gz; do
echo "Loading $f..."
gunzip -c "$f" | docker load
done
echo "All images loaded."
docker images如有防火墙,开放相关端口
#查看防火墙目前的放行端口列表
firewall-cmd --list-ports
#添加防火墙放行端口(permanent代表永久生效)
firewall-cmd --add-port=15672/tcp --permanent
firewall-cmd --add-port=5672/tcp --permanent
#重新加载防火墙(添加完放行端口一定要重新加载防火墙)
firewall-cmd --reload浏览器访问检查是否正常
# 地址
http://ip:port
# 输入账户,密码进入控制面板离线安装排障
# ====== 常见问题 ======
# 1. docker: command not found
# 检查二进制文件是否复制成功
ls -la /usr/bin/docker*
# 检查 PATH
echo $PATH
# 2. Cannot connect to the Docker daemon
# 检查 Docker 服务是否启动
systemctl status docker
journalctl -u docker -n 50
# 3. permission denied
# 检查用户是否在 docker 组中
groups
usermod -aG docker $USER
# 重新登录生效
# 4. overlay2 not supported
# 检查内核是否支持 overlay
grep overlay /proc/filesystems
# 如果不支持,修改 daemon.json 使用其他存储驱动
# "storage-driver": "vfs"
# 5. bridge-nf-call-iptables 报错
modprobe br_netfilter
sysctl -p /etc/sysctl.d/docker.conf
# 6. docker save/load 速度慢
# 使用 gzip 压缩镜像文件
# 使用内网文件传输工具
# 7. 镜像导入后 tag 不对
# docker load 保留原始 tag
# 如果需要重命名,使用 docker tag
docker tag old-image:tag new-image:tag关键知识点
- 部署类主题的核心不是"装成功",而是"稳定运行、可排障、可回滚"。
- 同一个服务通常至少要关注版本、目录、端口、权限、数据、日志和备份。
- Linux 问题经常跨越系统层、网络层、服务层和应用层。
- 部署主题通常要同时看镜像、容器、卷、网络和宿主机资源。
- 离线安装核心步骤:解压 -> 复制二进制 -> 配置内核 -> 创建服务 -> 启动。
- docker save/load 是离线环境镜像迁移的标准方式。
- 二进制安装方式不自动管理依赖,需要手动配置。
项目落地视角
- 把安装步骤补成可重复执行的清单,必要时写成脚本或配置文件。
- 把配置目录、数据目录、日志目录和挂载点明确拆开。
- 上线前检查防火墙、SELinux、时区、磁盘、系统服务和健康检查。
- 固定镜像标签,记录端口、挂载目录、环境变量和自启动策略。
- 建立内部镜像仓库(如 Harbor)统一管理离线镜像。
常见误区
- 使用 latest 或未固定版本,导致环境不可复现。
- 只验证启动成功,不验证持久化、开机自启和故障恢复。
- 遇到问题先改配置而不是先看日志和依赖链路。
- 使用 latest 导致结果不可复现。
- 不配置内核参数导致网络功能异常。
- 不创建 systemd 服务导致无法开机自启。
进阶路线
- 继续补齐 systemd、性能监控、安全加固和备份恢复。
- 把单机操作升级成 Docker、Kubernetes 或 IaC 方案。
- 建立标准化运维手册,包括巡检、扩容、回滚和灾备演练。
- 继续补齐 Compose 编排、镜像瘦身、安全扫描和镜像仓库治理。
- 搭建内网 Harbor 镜像仓库统一管理离线镜像。
适用场景
- 当你准备把《Docker 离线安装》真正落到项目里时,最适合先在一个独立模块或最小样例里验证关键路径。
- 适合单机环境初始化、中间件快速搭建、测试环境验证和生产部署前准备。
- 当服务稳定性依赖端口、权限、目录、网络和系统参数时,这类主题会直接影响成败。
落地建议
- 固定版本号与镜像标签,避免"latest"带来的不可预期变化。
- 把配置、数据、日志目录拆开管理,并记录恢复步骤。
- 上线前确认端口、防火墙、SELinux、时区和磁盘空间。
- 将离线安装步骤编写为一键安装脚本。
排错清单
- 先查 systemctl、容器日志和应用日志,确认失败发生在哪一层。
- 检查端口占用、目录权限、挂载路径和网络连通性。
- 如果是新环境问题,优先对比与已知正常环境的差异。
- 检查二进制文件是否完整复制到 /usr/bin。
- 使用 journalctl -u docker 查看详细错误日志。
复盘问题
- 如果把《Docker 离线安装》放进你的当前项目,最先要验证的输入、输出和失败路径分别是什么?
- 《Docker 离线安装》最容易在什么规模、什么边界条件下暴露问题?你会用什么指标或日志去确认?
- 相比默认实现或替代方案,采用《Docker 离线安装》最大的收益和代价分别是什么?
