--- title: 离线部署 description: 服务器无法访问镜像仓库时的部署方式 outline: deep --- # 离线部署 服务器无法访问外部镜像仓库时使用。核心思路:**在有网机器上导出镜像 → 传到目标机 → 导入**。 ## 适用场景 - 生产服务器在内网,不能访问外网 - 镜像仓库在内网不可达,或需要走审批才能拉取 - 需要把某一批镜像固化下来,保证多台机器部署一致 ## 一、确定镜像清单 ```bash docker compose config --images | sort -u ``` 输出示例(含可选 profile 时用 `--profile` 指定): ```text registry.example.com/iotlcm/iotlcm:iotlcm-admin-svr-v1.0.4 registry.example.com/iotlcm/iotlcm:iotlcm-admin-ui-v1.0.4 registry.example.com/iotlcm/iotlcm:iotlcm-app-server-v1.0.2 ... registry.example.com/iotlcm/iotlcm:mysql-8.0 registry.example.com/iotlcm/iotlcm:redis-7.2 ``` 把清单保存下来,作为这次部署的镜像基线: ```bash docker compose config --images | sort -u > images.txt ``` ## 二、在有网机器导出 ```bash # 拉取全部镜像 docker compose pull # 导出为单个压缩包 docker save $(cat images.txt) | gzip > iotlcm-images-$(date +%Y%m%d).tar.gz ``` 单包体积参考:全部 14 个服务约 **1.5~2 GB**(压缩后)。 若目标机磁盘紧张,可按服务分包: ```bash for img in $(cat images.txt); do name=$(echo "$img" | tr '/:' '__') docker save "$img" | gzip > "img-${name}.tar.gz" done ``` ## 三、传输 ```bash scp iotlcm-images-*.tar.gz user@target-host:/opt/iotlcm/ ``` 无网络直连时用移动介质拷入,注意校验完整性: ```bash # 源端生成校验值 sha256sum iotlcm-images-*.tar.gz > images.sha256 # 目标端校验 sha256sum -c images.sha256 ``` ## 四、在目标机导入 ```bash gunzip -c iotlcm-images-*.tar.gz | docker load ``` 分包的逐个导入: ```bash for f in img-*.tar.gz; do gunzip -c "$f" | docker load; done ``` 验证: ```bash docker images | grep iotlcm ``` ## 五、部署 导入后镜像已在本机,compose 不会再尝试拉取: ```bash # 把 docker-compose.yml 里的镜像地址与 TAG 改成与导入的镜像一致 cp -r config.example config vi config/*/config.yaml docker compose up -d ``` ::: warning REGISTRY 与 TAG 必须与导入的镜像名一致 `docker load` 只恢复镜像名,不会改标签。若 `docker-compose.yml` 里写 `TAG=latest` 而导入的是 `1.0.3`,compose 会认为镜像不存在并尝试拉取,离线环境直接失败。 用这条命令核对: ```bash docker compose config --images | sort -u > expected.txt docker images --format '{{.Repository}}:{{.Tag}}' | sort -u > actual.txt comm -23 expected.txt actual.txt # 输出为空才说明镜像齐全 ``` ::: ## 六、长期方案:内网镜像仓库 如果需要经常部署或多机部署,建议搭内网镜像仓库,而不是每次传 tar 包。 ### 同步镜像 ```bash # 在能访问外网的机器 for img in $(cat images.txt); do docker pull "$img" newimg="${img/registry.example.com/harbor.internal.example.com}" docker tag "$img" "$newimg" docker push "$newimg" done ``` 然后目标机的 `docker-compose.yml` 改为: ```bash REGISTRY=harbor.internal.example.com ``` ### 差异更新 版本升级时只需推送变化的镜像: ```bash docker compose pull # 对比 images.txt 找出新增/变更的标签,只同步这些 ``` ## 七、常见问题 | 现象 | 原因 | 处理 | | --- | --- | --- | | `docker compose up` 卡在 `Pulling` | 镜像标签不匹配,compose 尝试联网拉取 | 按上文核对 `expected.txt` 与 `actual.txt` | | `no space left on device` | 镜像包 + 解压后镜像双份占盘 | 导入后删除 tar 包,或换挂载点 | | `load` 后 `docker images` 为空 | 压缩包损坏 | 用 `sha256sum -c` 校验 | | 容器启动报 `exec format error` | 架构不匹配(x86 镜像跑在 ARM) | 在目标架构上重新导出 | | 导出包过大 | 包含多个无用层 | 用 `docker save` 只导出必要标签 | ## 八、离线环境的其他准备 镜像只是第一步,以下也需提前准备: | 资源 | 说明 | | --- | --- | | 部署仓代码 | `git clone` 或直接打包 `iotlcm-deploy/` 目录带过去 | | 配置模板 | 已包含在部署仓 `config/` | | 数据库脚本 | 已包含在部署仓 `schema/` | | Docker 与 Compose | 目标机需预先安装,离线安装包需单独准备 | | 时区数据 | 若使用 `Asia/Shanghai`,确认容器内 tzdata 完整(官方镜像已内置) |