简介:面向需要在离线或内网环境部署ZLMediaKit流媒体服务的运维人员与开发者,这份资源提供了一套完整的Docker离线安装方案。资源包包含2个文件,分别为Docker镜像压缩包与一键安装脚本,镜像tar包用于导入本地Docker环境,脚本则自动完成镜像加载与容器启动等操作,整体大小约为208.73MB,可有效避开外网拉取镜像的不便。目前已有375人学习下载。借助该资源,读者可减少手动配置环节,快速获得可运行的ZLMediaKit服务,尤其适合生产环境中无外网、需批量交付或快速验证的场景。相比在线安装,离线包方式速度更稳、依赖可控,配套脚本也便于二次定制,是一份实用性与可操作性兼备的部署工具。
1. zlm docker 离线安装:把镜像和运行时分开搬,内网就能跑
现场服务器连不了外网,领导又只给半天时间,要你把手上的流媒体服务部署上,这时候最怕的就是去源码编译 ZLMediaKit。zlm docker 离线安装的思路其实很简单:在能联网的机器上把 zlm 镜像导出成 tar,再把 tar 运到内网机器上 load,同时给内网机器准备一个离线可用的 Docker 运行时。这里最反直觉的一点是,离线安装的难点不在 zlm 本身,而在镜像怎么选、Docker 运行时怎么补。你不需要 yum 源,也不需要外网,只需要遵循一条原则:镜像从在线机带进去,运行时从安装包带进去。适合的场景包括机房隔离环境、客户现场、以及任何没有 Docker Hub 访问权限的产线。
2. 联网机准备 zlm 镜像:从 pull 到 save,选对 tag 和架构
离线部署的第一步不是在目标机上装 Docker,而是先在联网机上把镜像准备好。这里说的联网机可以是你的笔记本电脑,也可以是一台临时跳板机。目标只有一个:生成一个完整、可传输、能直接 load 的镜像 tar 文件。大多数人在这步翻车,不是因为不会用 docker,而是随手docker pull zlmediakit/zlmediakit:latest就完事,没考虑目标机的 CPU 架构,也没确认 tag 是否适合生产环境。
2.1 选镜像 tag:稳定版优先,不要迷信 latest
ZLMediaKit 官方镜像在 Docker Hub 上的仓库名常见写法是zlmediakit/zlmediakit,tag 有 latest、master 和若干 release 版本。对于离线部署,我的建议是选带版本号的 release 标签,而不是 latest。latest 通常指向开发分支,可能包含尚未充分验证的改动;离线环境没有外网去临时拉修复镜像,一旦踩坑,你要重新走一遍下载、导出、传输的完整流程,代价非常高。
选 tag 之前,先确认内网服务器的 CPU 架构。在目标机上执行uname -m,输出 x86_64 对应 amd64 镜像,输出 aarch64 对应 arm64 镜像。如果你是 Intel 下载机配 ARM 目标机,就需要在拉取时显式指定平台。这里有个容易被忽略的细节:docker pull默认拉取当前机器的架构,不会自动帮你选择目标机的架构。离线部署里真正要回答的“哪个版本最兼容”,第一步就是先定架构,再定版本,而不是先拉 latest 再说。
2.2 拉取镜像:受 Docker Hub 速度影响,先查空间再动手
下载机上执行下面的命令,实际 tag 以你在 Docker Hub 上确认到的 release 标签为准。
docker pull zlmediakit/zlmediakit:release这个命令会拉取指定 tag 的镜像,并在本地按层存储。pull 过程中会显示 Pulling fs layer、Downloading、Extracting 等状态。一个完整的 zlm 镜像通常有大几百兆,取决于是否包含 ffmpeg、x264 等运行库。下载前建议先用df -h /var/lib/docker确认空间充足,否则可能到一半报磁盘满。
Docker Hub 在网络环境不稳定时下载速度很慢,这是常态。有的团队会在这台下载机上配置 registry-mirror 做加速,但请记住:这是在线加速手段,不是离线部署方案。离线安装的核心是“只在联网机上拉一次,把结果带走”,只要最终 tar 文件完整,中途慢一点不影响目标机。
2.3 导出镜像:docker save 是把镜像完整打包的唯一正路
导出镜像用docker save,不是docker export。两者的区别是:save保留镜像的分层、tag 和构建历史,load 回去后仍然是完整镜像;export导出的是容器的文件系统,不包含镜像元数据,load 后无法按原 tag 直接运行。生产环境离线传输,一律用 save。
docker save -o zlm-release.tar zlmediakit/zlmediakit:release-o指定输出文件名,后面接仓库名和 tag。如果想减小传输体积,最常用的做法是导出后立即 gzip 压缩:
docker save zlmediakit/zlmediakit:release | gzip > zlm-release.tar.gzload 时 Docker 会自动识别 gzip 压缩包,不需要手动解压。压缩后的文件通常比原始 tar 小一半,适合用 U 盘或内网 scp 拷贝。镜像 tar 内部已经包含所有依赖层,目标机 load 时不需要访问任何仓库,这就是离线安装能成立的原理。
2.4 多个 tag 或镜像一并导出
生产环境里你可能会同时保留两个 tag,或者在镜像基础上追加了调试工具、改过配置,需要打包多个镜像。逐个 save 太啰嗦,可以一条命令解决:
docker save -o all-zlm.tar \ zlmediakit/zlmediakit:release \ zlmediakit/zlmediakit:latest也可以借助 docker images 过滤出所有相关仓库:
docker images --format '{{.Repository}}:{{.Tag}}' | grep zlmediakit | \ xargs docker save -o all-zlm.tar--format让输出只保留仓库和 tag,再通过管道交给 docker save,避免手敲漏 tag。导出完成后,建议用压缩包完整校验代替肉眼确认:
tar -tzf zlm-release.tar.gz > /dev/null && echo "tar OK"如果 tar 损坏,会立即报错。另外可以用docker image inspect确认镜像架构,避免后面在 ARM 机器上跑 x86 镜像。
3. 无网服务器装 Docker:CentOS 7 的静态二进制包与 rpm 两条路
目标机没有外网,就不能简单执行yum install docker,因为 yum 源默认指向公网。这里需要先明确你要装的 Docker 运行时包含哪几部分:docker daemon、docker CLI、containerd、runc。官方提供的离线安装路径有两条:静态二进制包和 rpm 离线源。我的建议是能拿到官方 tgz 就用静态包,依赖最少;如果你公司已经有离线软件仓库,rpm 包路线更贴合既有运维流程。
3.1 静态二进制包:免依赖、可控性最高
静态包是一个 tgz,解压后包含 docker、dockerd、containerd、runc、docker-init 等文件。下载时注意版本号要和目标机内核兼容,CentOS 7 使用 20.10.x 是稳妥选择。
tar -xzf docker-20.10.24.tgz cp docker/* /usr/bin/解压后的docker/目录内容直接放到/usr/bin,这样 systemd 服务文件里的 ExecStart 路径可以保持一致。接下来创建 docker.service 文件:
cat > /etc/systemd/system/docker.service <<'EOF' [Unit] Description=Docker Daemon After=network-online.target Wants=network-online.target [Service] Type=notify ExecStart=/usr/bin/dockerd ExecReload=/bin/kill -s HUP $MAINPID Restart=always RestartSec=5 LimitNOFILE=1048576 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable --now docker说明:Type=notify是 dockerd 的标准通知机制,systemd 会等 daemon 真正 ready 再继续;Restart=always保证进程被意外 kill 后自动拉起。静态包方式不依赖 rpm,也不存在依赖包缺失的连锁问题。但你仍然要保证/usr/bin在 PATH 中,第二步的 cp 命令不会自动赋予执行权限,检查一下文件权限即可。
装完后立刻验证:
docker version --format '{{.Server.Version}}'如果输出了 Server 版本,daemon 正常。如果只有 Client 版本,说明 dockerd 没起来,需要看 journalctl 或 /var/log/messages。这一步一定要做,很多离线部署翻车都发生在 Docker 还没起来就急着 load 镜像。
3.2 rpm 包离线源:在联网机用 yumdownloader 抓全依赖
如果公司的离线仓库已经管理了 rpm 包,rpm 方式更符合现有流程。先在联网 CentOS 7 机器上准备一个临时目录:
mkdir ~/docker-rpm && cd ~/docker-rpm yum install -y yum-utils yumdownloader --resolve docker-ce docker-ce-cli containerd.ioyumdownloader --resolve会把主包和所有依赖包一起下载,包括 container-selinux、iptables 等。这一步可能会下载几十个 rpm,需要全部拷到内网机器。
在内网机器上创建本地仓库:
mkdir -p /opt/docker-rpm cp *.rpm /opt/docker-rpm/ yum install -y createrepo createrepo /opt/docker-rpm cat > /etc/yum.repos.d/docker-local.repo <<'EOF' [docker-local] name=docker-local baseurl=file:///opt/docker-rpm enabled=1 gpgcheck=0 EOF yum clean all yum install -y docker-ce docker-ce-cli containerd.io systemctl enable --now dockerrpm 方式的优点是安装路径和 systemd 服务统一由包管理处理,卸载也干净。缺点是依赖解析比较烦,如果 yumdownloader 阶段换过源,或者目标机内核版本较老,container-selinux 可能装不上。遇到依赖冲突,优先看 yum 输出的Needed项,把对应的 rpm 补进目录后重新 createrepo。
3.3 离线环境里 daemon.json 要留意的三个参数
Docker daemon 启动后,即使不联网也能正常运行,但离线环境里默认配置有一些点值得提前调整。比如默认>mkdir -p /data/docker cat > /etc/docker/daemon.json <<'EOF' { "data-root": "/data/docker", "storage-driver": "overlay2", "log-level": "warn" } EOF systemctl restart docker
storage-driver用 overlay2,CentOS 7 内核一般原生支持;log-level设成 warn 可以减少日志占用。注意,改>docker load -i zlm-release.tar.gz docker images | grep zlmediakit
-i后面既可以接未压缩的.tar,也可以接 gzip 压缩包。load 会逐层解压写入 Docker 的>docker tag <IMAGE ID> zlmediakit/zlmediakit:release
load 的时间受磁盘速度影响,一个 1G 镜像通常需要一两分钟。如果 tar 文件在复制过程中损坏,load 会报layer does not exist或mount has been changed,这不是 tar 格式错误,而是数据不完整,重新拷贝一次再 load 即可。
4.2 启动最小容器:默认配置可以直接跑
ZLMediaKit 默认监听三个主要端口:RTSP 的 554,RTMP 的 1935,HTTP/HTTP-FLV 的 8080。不修改配置的情况下,可以这样启动:
docker run -d --name zlm --restart unless-stopped \ -p 1935:1935 -p 554:554 -p 8080:8080 \ zlmediakit/zlmediakit:release-d后台运行,--name zlm便于后续 logs 查看,--restart unless-stopped让容器在机器重启后自动拉起,这个参数在无人值守的离线环境里几乎是必备项。-p 外部端口:容器端口把宿主机端口映射进容器。如果不想占用 554 这种特权端口,可以改成-p 8554:554,播放时访问 8554 即可。
启动后立刻确认端口在监听:
ss -lnt | grep -E '1935|554|8080'如果没有宿主机侧监听,说明映射失败,多半是端口被占或 docker-proxy 没起来,可以进入第 5 章排查。
4.3 需要改配置时:先 find 定位配置文件,再挂载出来
默认配置适合测试,生产环境一般要改 HTTP 端口、secret、流媒体鉴权。zlm 的配置是一个 config.ini,不要凭记忆猜容器内路径,先查真实路径:
docker exec zlm sh -c 'find / -name "config.ini" 2>/dev/null'这一步会输出实际路径,不同镜像版本可能不同,常见位置在 /opt/media/conf 下。确认后把它拷贝到宿主机:
mkdir -p /opt/zlmediakit/conf docker cp zlm:/opt/media/conf/config.ini /opt/zlmediakit/conf/config.ini vim /opt/zlmediakit/conf/config.ini改完后删掉旧容器,用挂载方式重新启动:
docker stop zlm && docker rm zlm docker run -d --name zlm --restart unless-stopped \ -v /opt/zlmediakit/conf:/opt/media/conf \ -p 1935:1935 -p 554:554 -p 8080:8080 \ zlmediakit/zlmediakit:release注意-v右边的路径必须与 find 出来的真实路径一致。如果挂载后配置文件没生效,先看 docker logs 里有没有 permission denied,这通常是宿主目录权限问题。
4.4 用 docker compose 固定整套启动参数
离线环境里手敲 docker run 容易漏参数。如果你已经装了 docker compose 插件,可以用一个 compose 文件固定整套配置:
services: zlm: image: zlmediakit/zlmediakit:release container_name: zlm restart: unless-stopped ports: - "1935:1935" - "554:554" - "8080:8080" volumes: - /opt/zlmediakit/conf:/opt/media/conf在 compose 文件所在目录执行:
docker compose up -dcompose 会优先使用本地镜像,离线环境不会主动去仓库拉取。如果本地没有镜像,它会报拉取失败,这正好提醒你回头做 load。compose 的好处是把启动参数写成代码,团队维护时不容易各写一套 docker run。没有 compose 插件时,docker run 方案完全够用。
5. 离线部署 zlm 的常见问题排查:五条真实踩坑记录
离线安装和在线安装最大的区别是:出问题时往往没有外网去搜答案,只能靠日志和系统状态逆推。下面五条是我在 CentOS 7 离线环境里实际见过的坑,每一条按现象、原因、解决三步写。
5.1 镜像架构不匹配:Exec format error
现象:docker load 一切正常,docker run 后容器秒退,docker logs zlm只有一句exec user process caused: exec format error。
原因:下载机是 x86_64,目标服务器是 aarch64,而你 pull 到的镜像是 amd64 架构。docker pull 默认拉取当前机器的架构,不会自动跨平台选择目标机架构。
解决:在下载机拉镜像前明确指定平台:
docker manifest inspect zlmediakit/zlmediakit:release docker pull --platform linux/arm64 zlmediakit/zlmediakit:releasedocker manifest inspect会列出该镜像支持的架构。导出前再用docker image inspect确认 Architecture 字段。如果镜像本身没有 arm64 版本,那就只能换源码编译,或找适配目标架构的镜像。这个问题的本质是:离线镜像必须与目标机架构强绑定。
5.2 docker load 报 no space left on device
现象:内网机器执行docker load -i zlm.tar.gz,解压到一半报no space left on device,而 tar 文件本身只有几百 MB。
原因:load 会把镜像分层解压到 Docker 的>docker system df docker system prune -a
清理后仍然不足,就把>firewall-cmd --permanent --add-port=1935/tcp firewall-cmd --permanent --add-port=554/tcp firewall-cmd --permanent --add-port=8080/tcp firewall-cmd --reload
如果用云主机,还要到云控制台的安全组里放通这些入方向端口。这个坑最容易在最后验证阶段暴露,所以我会在部署完成后,坚持做一次端到端推流验证,而不是只看 docker ps。
5.5 端口冲突:旧容器没删干净,新容器起不来
现象:docker run启动 zlm 时提示bind: address already in use,但ss -lntp看到的占用者是一个 docker-proxy 进程,而不是应用进程。
原因:上一次部署留下的旧容器还处于运行或退出状态,它的端口映射没有释放;或者另一个服务占用了 8080 / 1935。
解决:先查所有容器和端口占用:
docker ps -a ss -lntp | grep 1935确认占用者是无用容器后,删除再启动:
docker stop zlm && docker rm zlm docker run -d --name zlm --restart unless-stopped \ -p 1935:1935 -p 554:554 -p 8080:8080 \ zlmediakit/zlmediakit:release如果端口被其他系统进程占用,比如 Apache 占了 8080,就直接换宿主机侧映射-p 8081:8080,不必改容器内配置。这个坑看似低级,但在离线现场最容易遇到,因为往往多个服务挤在同一台机器上。
6. 验证 zlm 容器能出流:ffmpeg 推流一分钟够用
部署完成不等于交付。我见过不止一次docker ps显示运行中,结果实际拉流时才发现流地址配错了。离线环境没有在线检测服务可依赖,最可靠的方式是自己推一路流,再亲自拉回来。
在能访问 zlm 服务器的机器上准备一个 mp4 测试文件,执行推流:
ffmpeg -re -stream_loop -1 -i test.mp4 -c copy -f flv rtmp://<zlm-ip>:1935/live/test-re按文件真实时间率推流,-stream_loop -1让视频循环,避免推流几秒就结束。然后另开终端用 ffprobe 验证:
ffprobe -v error -show_entries stream=codec_name,width,height -of json rtmp://<zlm-ip>:1935/live/test如果输出了编码、宽高,说明 zlm 的 RTMP 接入和转发链路正常。想验证 HTTP-FLV,把播放地址改成:
ffplay http://<zlm-ip>:8080/live/test.flv同时观察 zlm 日志:
docker logs -f zlm | grep -E 'play|publish'看到 publish 和 play 两条日志,一次完整的推拉流闭环就通了。如果 ffprobe 没输出,按第 5 章的端口排查从头过一遍,不要急着改配置。
我自己的习惯是部署完后不急着交工,先推流一分钟再离开。有一次我跳过这步,结果客户现场拉流时才发现生产环境安全组没放行 RTSP 端口,远程折腾了半小时。从那以后,离线部署 zlm 的验证命令就固定成了三条:推流、拉流、看日志。这套流程也适用于以后升级镜像版本,至少能确认新镜像没有把端口或协议弄丢。希望帮到你。
本文还有配套的精品资源,点击获取