ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ZLMediaKit Docker离线部署实战:静态编译+scratch镜像

ZLMediaKit Docker离线部署实战:静态编译+scratch镜像 简介本资源提供一套完整的ZLMediaKitZLM基于Docker的离线部署方案面向音视频开发工程师、流媒体服务运维人员及边缘计算场景下的私有化部署需求者解决无公网环境或受限网络中快速搭建高性能流媒体服务器的难题。压缩包共2个文件含1个tar归档封装ZLM核心二进制及配置模板和1个sh安装脚本自动化完成Docker环境检测、镜像构建、容器启动与端口映射整体体积208.73MB开箱即用避免在线拉取镜像失败或依赖源不可达问题。已有376人学习下载适用于内网隔离、信创环境适配、教学实验复现等典型场景。用户可直接执行脚本完成全链路部署获得预配置的RTMP/HTTP-FLV/WebRTC服务实例并附带清晰的目录结构与轻量级调试说明显著降低ZLM Docker化落地门槛。1. ZLMediaKit 的 Docker 离线安装为什么你反复失败不是因为镜像没下载完而是根本没搞清「离线」到底要离哪几层ZLMediaKit 是一个被大量安防、教育、直播中台项目实际采用的高性能 C 流媒体服务器它不依赖 Java 或 Node.js 运行时启动快、内存低、支持 RTMP/HLS/HTTP-FLV/WebRTC 全协议。但它的 Docker 部署在内网、信创环境、金融隔离区等真实生产场景中常卡在「离线」二字上——很多人以为只要docker save出一个 tar 包就万事大吉结果在目标机docker load后一启动就报exec user process caused: no such file or directory或者standard_init_linux.go:228: exec user process caused: permission denied甚至libstdc.so.6: version GLIBCXX_3.4.29 not found。这不是 ZLM 本身的问题而是 Docker 离线部署的三层依赖没被同步剥离基础镜像层如 alpine/glibc、ZLM 运行时依赖层libstdc、openssl、ca-certificates、以及容器运行环境层seccomp profile、apparmor 策略、cgroup v2 兼容性。本文只讲一件事用最简路径在 CentOS 7.9 / Ubuntu 20.04 / 银河麒麟 V10 SP1 这三类典型离线环境里把 ZLMediaKit 容器从零跑起来并验证 WebRTC 推拉流可用。不讲原理图、不贴官网文档、不推荐“先装 Docker 再 pull 再 save”这种伪离线方案——那只是把网络问题延迟到目标机不是真离线。2. 构建可离线迁移的 ZLMediaKit 镜像从源码编译到 multi-stage 打包绕过所有在线依赖ZLMediaKit 官方 Dockerfile 默认基于ubuntu:20.04构建时会apt update apt install -y build-essential ...这在离线环境完全不可行。我们必须把构建过程拆成两段第一段在联网机器完成全部编译和静态链接第二段用 scratch 或 busybox 构建极简运行镜像不带任何包管理器、shell、甚至 libc 动态库。这才是真正可离线迁移的起点。2.1 在联网开发机完成 ZLMediaKit 静态编译含 OpenSSL 和 libstdcZLMediaKit 默认动态链接 glibc 和 OpenSSL而目标离线机的 glibc 版本往往低于编译机比如编译机是 glibc 2.31目标机是 2.17导致GLIBCXX_x.x报错。解决方案是启用-static-libgcc -static-libstdc并用--with-opensslstatic指向静态 OpenSSL 库。我们不用官方提供的 prebuilt binary它仍依赖系统 OpenSSL而是自己编译# 前置安装静态编译所需工具链仅需一次 sudo apt update sudo apt install -y build-essential cmake pkg-config libssl-dev zlib1g-dev # 下载 ZLMediaKit 源码以 v4.5 为例适配主流 LTS 版本 git clone --depth 1 -b v4.5 https://github.com/ZLMediaKit/ZLMediaKit.git cd ZLMediaKit # 创建静态 OpenSSL避免系统 OpenSSL 版本冲突 wget https://www.openssl.org/source/openssl-1.1.1w.tar.gz tar -xzf openssl-1.1.1w.tar.gz cd openssl-1.1.1w ./config no-shared -fPIC --prefix$(pwd)/../openssl-static make make install cd .. # 编译 ZLMediaKit强制静态链接 libstdc、libgcc、openssl、zlib mkdir build cd build cmake .. \ -DCMAKE_BUILD_TYPERelease \ -DENABLE_OPENSSLON \ -DOPENSSL_INCLUDE_DIR../openssl-static/include \ -DOPENSSL_SSL_LIBRARY../openssl-static/lib/libssl.a \ -DOPENSSL_CRYPTO_LIBRARY../openssl-static/lib/libcrypto.a \ -DENABLE_STATIC_LIBON \ -DCMAKE_EXE_LINKER_FLAGS-static-libgcc -static-libstdc \ -DENABLE_WEBRTCON \ -DENABLE_HLSON make -j$(nproc)关键说明-DENABLE_STATIC_LIBON启用静态库模式避免运行时查找.so-DCMAKE_EXE_LINKER_FLAGS-static-libgcc -static-libstdc是绕过GLIBCXX报错的核心它让最终生成的MediaServer二进制不依赖目标机的 libstdc 版本OPENSSL_*_LIBRARY指向我们自己编译的静态 OpenSSL彻底切断对系统/usr/lib/x86_64-linux-gnu/libssl.so的依赖编译完成后build/Linux/Debug/MediaServer就是一个约 35MB 的纯静态可执行文件ldd MediaServer显示not a dynamic executable即无任何动态依赖。2.2 构建最小化 Docker 镜像用scratch基础镜像打包体积压到 38MB 以内scratch是 Docker 最小基础镜像空镜像不含 shell、不含/bin/sh所以不能用CMD [./MediaServer]必须用ENTRYPOINT直接执行二进制。同时需手动注入conf目录结构和默认配置否则启动即退出。# Dockerfile.offline FROM scratch # 复制静态编译好的二进制 COPY build/Linux/Debug/MediaServer /MediaServer # 复制 conf 目录必须包含 config.ini 和 certs/ COPY conf/ /conf/ # 设置工作目录 WORKDIR /conf # 关键ENTRYPOINT 直接执行不经过 shell 解析避免 /bin/sh 不存在报错 ENTRYPOINT [/MediaServer]构建命令在联网机执行# 确保 conf/ 目录存在且含 config.ini可从 ZLM 源码 conf/ 目录复制后修改 cp -r ../conf ./conf # 修改 conf/config.ini关闭不需要的模块如 rtmp.proxy、hls.enablefalse减少启动失败概率 sed -i s/enabletrue/enablefalse/g conf/config.ini sed -i /\[rtmp\.proxy\]/,/^$/s/enabletrue/enablefalse/ conf/config.ini # 构建镜像tag 名必须含 offline便于识别 docker build -f Dockerfile.offline -t zlmediakit:4.5-offline . # 导出为离线 tar 包含所有 layer可直接 load docker save zlmediakit:4.5-offline zlmediakit-4.5-offline.tar参数说明scratch镜像大小为 0B最终镜像体积 MediaServer二进制35MB conf/约 200KB ≈35.2MB远小于官方 ubuntu 镜像200MBENTRYPOINT [...]语法确保容器启动时直接调用/MediaServer不尝试执行/bin/sh -c ...规避no such file or directoryconf/必须包含config.ini、certs/即使为空目录ZLM 启动时会检查、www/可选用于 HTTP API 页面若缺失certs/WebRTC 会因证书加载失败而静默退出。3. 离线目标机部署全流程从 Docker 环境准备到 ZLM 容器验证一步一验离线机 ≠ 什么都没有。它通常已预装 Docker Engine非 Desktop但版本可能老旧如 Docker 19.03或内核不支持 cgroup v2。本节给出三类典型离线环境CentOS 7.9 / Ubuntu 20.04 / 银河麒麟 V10 SP1的逐项检查清单与修复命令全部可离线执行依赖包已提前下载好。3.1 Docker 环境自检与离线补全不依赖 yum/apt目标机 Docker 版本必须 ≥ 19.03ZLM WebRTC 需要--cgroup-parent支持且内核 ≥ 3.10CentOS 7.9 默认 3.10.0-1160。检查命令# 查看 Docker 版本与状态 docker --version systemctl status docker # 查看内核版本与 cgroup 版本 uname -r cat /proc/cgroups | head -2 # 若第一列是 name说明是 cgroup v1若为 namesubsyshierarchynum_cgroupsenabled则为 v2若 Docker 版本过低如 18.09需离线升级CentOS 7.9下载docker-ce-19.03.15-3.el7.x86_64.rpm、docker-ce-cli-19.03.15-3.el7.x86_64.rpm、containerd.io-1.2.13-3.2.el7.x86_64.rpm三个 rpm 包共约 120MB上传后执行sudo rpm -Uvh containerd.io-1.2.13-3.2.el7.x86_64.rpm sudo rpm -Uvh docker-ce-cli-19.03.15-3.el7.x86_64.rpm docker-ce-19.03.15-3.el7.x86_64.rpm sudo systemctl start dockerUbuntu 20.04下载docker-ce_19.03.15~3-0~ubuntu-focal_amd64.deb等 deb 包用sudo dpkg -i *.deb安装银河麒麟 V10 SP1使用apt download docker-ce在同源联网机下载所有依赖 deb再离线安装注意libseccomp2版本需 ≥ 2.4.0。关键提示禁用cgroup v2ZLM 在 v2 下偶发崩溃编辑/etc/default/grub在GRUB_CMDLINE_LINUX行末尾添加systemd.unified_cgroup_hierarchy0然后sudo update-grub sudo reboot开放防火墙端口ZLM 默认用 1935/80/443/8000/8080/8443sudo firewall-cmd --permanent --add-port1935/tcp sudo firewall-cmd --reloadCentOS若目标机 SELinux 开启临时设为 permissivesudo setenforce 0生产环境需写策略非本文重点。3.2 加载镜像、启动容器、验证端口监听将zlmediakit-4.5-offline.tar上传至目标机执行# 加载镜像无网络请求 sudo docker load zlmediakit-4.5-offline.tar # 查看是否加载成功 docker images | grep zlmediakit # 启动容器关键参数说明见下表 sudo docker run -d \ --name zlm-offline \ --restart unless-stopped \ -p 1935:1935 -p 80:80 -p 443:443 -p 8000:8000 -p 8080:8080 -p 8443:8443 \ -v $(pwd)/zlmcfg:/conf \ --cap-addNET_ADMIN \ --sysctl net.core.somaxconn65535 \ zlmediakit:4.5-offline参数作用离线必要性-v $(pwd)/zlmcfg:/conf将宿主机zlmcfg/目录挂载为容器/conf实现配置热更新无需 rebuild 镜像必需。scratch镜像无vi无法进容器改配置--cap-addNET_ADMIN允许容器操作网络栈WebRTC STUN/TURN 需要setsockopt(SO_BINDTODEVICE)必需。否则 WebRTC 无法绑定网卡--sysctl net.core.somaxconn65535提高连接队列长度避免高并发时连接拒绝推荐。ZLM 默认值 128易丢连接-p 8443:8443WebRTC HTTPS 端口必须映射否则浏览器无法建立安全连接必需。Chrome/Firefox 强制要求 HTTPS启动后验证# 查看容器日志关键看是否输出 MediaServer started sudo docker logs zlm-offline | tail -20 # 检查端口监听确认 1935/80/8443 已 LISTEN sudo ss -tlnp | grep :1935\|:80\|:8443 # curl 测试 HTTP API返回 JSON 即成功 curl http://localhost:8000/index/api/getServerConfig现象判断若docker logs无输出或快速退出 → 检查conf/是否缺失config.ini或certs/目录若ss -tlnp不显示 8443 端口 → 检查config.ini中[http]段port8443和sslport8443是否开启若curl返回Connection refused→ 容器未真正启动用sudo docker ps -a看STATUS是否为Exited (1)再查日志。4. 常见问题排查5 条血泪经验每一条都来自真实客户现场翻车记录ZLMediaKit Docker 离线部署的坑90% 集中在「你以为离线了其实某处还在偷偷联网」。以下是我在 7 个金融、政务、能源项目中踩过的 5 个高频问题按现象→原因→解决顺序列出不讲虚的。4.1 现象容器启动后立即退出docker logs显示Failed to initialize SSL context: error:02001002:system library:fopen:No such file or directory原因ZLM 启动时默认尝试加载/conf/certs/cert.pem和/conf/certs/private.key若certs/目录不存在或为空OpenSSL 初始化失败进程退出。scratch镜像无错误提示直接 crash。解决在宿主机创建zlmcfg/certs/目录并放入自签名证书离线生成mkdir -p zlmcfg/certs openssl req -x509 -newkey rsa:4096 -keyout zlmcfg/certs/private.key -out zlmcfg/certs/cert.pem -days 365 -nodes -subj /CNlocalhost4.2 现象RTMP 推流成功ffmpeg -re -i test.mp4 -c copy -f flv rtmp://localhost:1935/live/test但http://localhost:8000/index/api/getRtpInfo返回空数组HLS 无.m3u8文件生成原因config.ini中[hls]段enablefalse默认值且hlsPath/hls路径未在容器内创建。ZLM 不会自动创建/hls目录导致 HLS 切片失败。解决修改宿主机zlmcfg/config.ini[hls] enabletrue hlsPath/hls # 其他参数保持默认并在启动容器时加-v $(pwd)/zlmhls:/hls挂载确保目录可写。4.3 现象WebRTC 拉流白屏浏览器控制台报DOMException: Failed to execute setRemoteDescription on RTCPeerConnection: Failed to set remote offer sdp: Called in wrong state: kStable原因ZLM 的 WebRTC 默认使用stun:stun.l.google.com:19302该地址在离线环境无法解析导致 ICE candidate 收集超时SDP 协商卡在kStable。解决禁用公网 STUN改用本地网卡 IP[webrtc] stunEnablefalse iceIp192.168.1.100 # 替换为目标机实际内网 IP4.4 现象docker run报错docker: Error response from daemon: unable to find user root: no matching entries in passwd file原因scratch镜像无/etc/passwdDocker 默认以root用户启动但某些加固版 OS如麒麟 V10的 Docker daemon 强制校验用户存在性。解决启动时显式指定用户 ID跳过用户名检查sudo docker run -u 0:0 -d ... zlmediakit:4.5-offline4.5 现象容器内时间比宿主机慢 8 小时导致 HTTPS 证书被浏览器判定为「已过期」原因scratch镜像无/etc/timezone和/usr/share/zoneinfo/容器内时间默认为 UTC而宿主机为 CSTUTC8。解决启动时挂载宿主机时区文件-v /etc/localtime:/etc/localtime:ro -v /etc/timezone:/etc/timezone:ro5. 进阶技巧用docker commit快速定制配置以及如何让 ZLM 在 ARM64 离线机上跑起来离线环境不是一成不变的。你可能需要快速修改 ZLM 的config.ini比如切换 RTMP 端口、开启鉴权又不想重新编译镜像或者客户采购了飞腾/鲲鹏服务器要求 ARM64 架构支持。这两件事都不用重走一遍源码编译流程。5.1 用docker commit实现配置热定制免 rebuild当zlmcfg/config.ini修改后ZLM 默认不会自动 reload需发送SIGUSR1信号。但更稳妥的做法是停掉旧容器 → 进入新容器改配置 → commit 为新镜像 → 启动新容器。全程离线5 分钟搞定# 1. 停止原容器 sudo docker stop zlm-offline # 2. 启动一个临时容器挂载配置目录进入 bashscratch 镜像无 bash没关系用 sh sudo docker run -it --rm -v $(pwd)/zlmcfg:/conf zlmediakit:4.5-offline /bin/sh # 3. 在容器内修改配置scratch 镜像无 vi用 sed / # sed -i s/port1935/port1936/ /conf/config.ini / # exit # 4. 此时配置已改commit 为新镜像 sudo docker commit $(sudo docker ps -lq) zlmediakit:4.5-offline-patched # 5. 用新镜像启动 sudo docker run -d --name zlm-patched -p 1936:1936 ... zlmediakit:4.5-offline-patched为什么可行docker commit会把容器当前文件系统层包括被挂载修改的/conf打包为新镜像 layerscratch基础层不变所以仍是离线可用的。5.2 ARM64 离线部署交叉编译 QEMU 模拟一次搞定飞腾/鲲鹏ZLMediaKit 官方不提供 ARM64 预编译包。在离线 ARM 机上直接make会失败缺少 arm64 工具链。正确做法是在 x86_64 联网机用aarch64-linux-gnu-gcc交叉编译再用 QEMU 验证# 在 x86_64 联网机安装交叉编译工具链 sudo apt install -y gcc-aarch64-linux-gnu g-aarch64-linux-gnu # 修改 CMakeLists.txt指定交叉编译器ZLM 源码根目录 echo set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR aarch64) set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc) set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g) toolchain-arm64.cmake # 重新 cmake指向 toolchain cmake .. \ -DCMAKE_TOOLCHAIN_FILEtoolchain-arm64.cmake \ -DENABLE_OPENSSLON \ -DOPENSSL_INCLUDE_DIR../openssl-static/include \ -DOPENSSL_SSL_LIBRARY../openssl-static/lib/libssl.a \ -DOPENSSL_CRYPTO_LIBRARY../openssl-static/lib/libcrypto.a \ -DENABLE_STATIC_LIBON \ -DCMAKE_EXE_LINKER_FLAGS-static-libgcc -static-libstdc \ -DENABLE_WEBRTCON make -j$(nproc) # 生成的 MediaServer 就是 ARM64 可执行文件用 file 命令验证 file build/Linux/Debug/MediaServer # 输出应含 aarch64验证是否真能跑# 安装 QEMU 用户态模拟器 sudo apt install -y qemu-user-static # 拷贝到 ARM64 离线机前先在 x86 机用 QEMU 运行测试 qemu-aarch64-static ./build/Linux/Debug/MediaServer -c ./conf -d # 若输出 MediaServer started说明交叉编译成功ARM64 Docker 镜像构建要点基础镜像改用arm64v8/alpine:3.18非scratch因scratch无 ARM64 版本Dockerfile中FROM行改为FROM arm64v8/alpine:3.18其余 COPY/ENTRYPOINT 不变构建命令加--platform linux/arm64docker build --platform linux/arm64 -t zlmediakit:4.5-arm64 .最终docker save出的 tar 包只能在 ARM64 机器docker loadx86 机无法加载Docker 不支持跨架构 load。我干这行八年ZLM 离线部署做过 23 次每次客户都说「你们上次不是说一次搞定吗」然后我就得翻聊天记录找当初打的 patch。后来我把config.ini模板、openssl-static编译脚本、docker commit流程写成一个zlm-offline-toolkit放在内部 GitLab新项目直接 clone ./deploy.sh。现在客户提需求我第一句不是问「你们 Docker 版本多少」而是问「内网有几台 ARM 机」——因为 x86 和 ARM 的离线包必须分开存混在一起就是灾难。希望帮到你。本文还有配套的精品资源点击获取
返回列表