存在一个小问题,没有图标文件,官方 QDK 文档上用的图标格式是 gif,官网的图标文件是 png。影响不大,懒得折腾了,有好事者有处理的话,欢迎评论区交流。
本文档提供一套可复现、可对外分享的工程化构建方案,用于在 Debian/Ubuntu 环境中,通过 Docker Compose 一键构建适用于 QNAP x86_64 设备的 zerotier_1.16.2_x86_64.qpkg。
该方案采用 多阶段构建:
- Alpine 3.20:负责编译 ZeroTier One(静态链接,适配 QNAP 老设备)
- Ubuntu 22.04:负责离线安装 QDK 并执行打包
一、目录结构
zerotier-qpkg/
├── build.sh # 一键构建脚本
├── docker-compose.yml # Docker Compose 编排文件
├── Dockerfile.builder # Ubuntu 构建镜像(QDK 与打包环境)
├── Dockerfile.alpine # Alpine 构建镜像(编译 ZeroTier)
├── qpkg-template/
│ ├── build/ # qbuild 生成目录(最终产物在此)
│ ├── package_routines # QPKG 生命周期脚本
│ ├── qpkg.cfg # QPKG 元数据配置
│ ├── shared/
│ │ └── zerotier.sh # 服务启停脚本
│ └── x86_64/ # 二进制文件存放目录
│ ├── zerotier-one
│ ├── zerotier-cli
│ └── zerotier-idtool
├── qdk.deb # QDK 离线安装包
└── ZeroTierOne-src/ # ZeroTier 1.16.2 源码
二、一键构建脚本
该脚本负责自动下载源码、生成 Dockerfile 与 Compose 文件(使用 cat EOF),并执行 Docker Compose 构建。增加了 curl 失败处理 和 --download-only 参数支持。
#!/bin/bash
set -e
PROJECT_DIR="."
QDK_URL="https://github.com/qnap-dev/QDK/releases/download/v2.5.0/qdk_2.5.0_amd64.deb"
ZT_SRC_URL="https://github.com/zerotier/ZeroTierOne/archive/refs/heads/1.16.2.zip"
# 新增:三级控制
DOWNLOAD_ONLY=false
CONFIG_ONLY=false
# 参数解析(支持多参数)
for arg in "$@"; do
case "$arg" in
--download-only)
DOWNLOAD_ONLY=true
;;
--config-only)
CONFIG_ONLY=true
;;
esac
done
echo "==> 创建项目目录结构..."
mkdir -p ${PROJECT_DIR}/qpkg-template/{build,shared,x86_64}
mkdir -p ${PROJECT_DIR}/output
# ===== 仅在非 config-only 模式下执行下载 =====
if [ "$CONFIG_ONLY" = false ]; then
echo "==> 下载 QDK 2.5.0..."
if ! curl -L -o ${PROJECT_DIR}/qdk.deb ${QDK_URL}; then
echo "ERROR: 下载 QDK 失败,请检查网络连接或 URL 有效性。"
exit 1
fi
echo "==> 下载 ZeroTier One 1.16.2 源码..."
if ! curl -L -o /tmp/zt.zip ${ZT_SRC_URL}; then
echo "ERROR: 下载 ZeroTier 源码失败,请检查网络连接或 URL 有效性。"
exit 1
fi
unzip -q /tmp/zt.zip -d ${PROJECT_DIR}/
rm -rf ${PROJECT_DIR}/ZeroTierOne-src
mv ${PROJECT_DIR}/ZeroTierOne-1.16.2 ${PROJECT_DIR}/ZeroTierOne-src
rm -f /tmp/zt.zip
fi
echo "==> 生成 Dockerfile.alpine..."
cat > ${PROJECT_DIR}/Dockerfile.alpine <<'EOF'
FROM alpine:3.20
RUN apk update && apk add --no-cache \
make gcc g++ linux-headers musl-dev \
openssl-dev openssl-libs-static curl
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
WORKDIR /tmp/ZeroTierOne
COPY ZeroTierOne-src /tmp/ZeroTierOne
RUN make ZT_STATIC=1 -j${nproc}
RUN strip zerotier-one
CMD ["sh", "-c", "cp /tmp/ZeroTierOne/zerotier-one /build/qpkg-template/x86_64/ && cp /tmp/ZeroTierOne/zerotier-cli /build/qpkg-template/x86_64/ && cp /tmp/ZeroTierOne/zerotier-idtool /build/qpkg-template/x86_64/"]
EOF
echo "==> 生成 Dockerfile.builder..."
cat > ${PROJECT_DIR}/Dockerfile.builder <<'EOF'
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y \
pv xz-utils rsync gnupg2 curl openssl bsdextrautils
COPY qdk.deb /tmp/qdk.deb
RUN dpkg -i /tmp/qdk.deb
WORKDIR /build/qpkg-template
COPY qpkg-template /build/qpkg-template
CMD ["sh", "-c", "qbuild --build-arch x86_64 && cp /build/qpkg-template/build/* /output/"]
EOF
echo "==> 生成 docker-compose.yml..."
cat > ${PROJECT_DIR}/docker-compose.yml <<'EOF'
services:
alpine-builder:
platform: linux/amd64
build:
context: .
dockerfile: Dockerfile.alpine
volumes:
- ./qpkg-template:/build/qpkg-template
container_name: zerotier-alpine-builder
ubuntu-packager:
platform: linux/amd64
build:
context: .
dockerfile: Dockerfile.builder
volumes:
- ./qpkg-template:/build/qpkg-template
- ./output:/output
container_name: zerotier-ubuntu-packager
depends_on:
- alpine-builder
EOF
echo "==> 生成 QPKG 模板基础文件..."
cat > ${PROJECT_DIR}/qpkg-template/package_routines <<'EOF'
#!/bin/sh
pkg_install() {
ln -sf "$QPKG_ROOT/usr/bin/zerotier-cli" "/usr/local/bin/zerotier-cli"
}
pkg_post_install() {
echo "ZeroTier One installed successfully."
}
pkg_pre_remove() {
$QPKG_SERVICE_PROGRAM stop
}
pkg_main_remove() {
rm -f "/usr/local/bin/zerotier-cli"
}
EOF
cat > ${PROJECT_DIR}/qpkg-template/qpkg.cfg <<'EOF'
QPKG_NAME="zerotier"
QPKG_VER="1.16.2"
QPKG_AUTHOR="Ivan Zhang"
QPKG_LICENSE="GPL"
QPKG_DISPLAY_NAME="ZeroTier One"
QPKG_ARCH="x86_64"
QPKG_SERVICE_PROGRAM="zerotier.sh"
EOF
cat > ${PROJECT_DIR}/qpkg-template/shared/zerotier.sh <<'EOF'
#!/bin/sh
QPKG_NAME="zerotier"
CONF=/etc/config/qpkg.conf
QPKG_ROOT=/share/CACHEDEV1_DATA/.qpkg/${QPKG_NAME}
case "$1" in
start)
ENABLED=$(/sbin/getcfg $QPKG_NAME Enable -u -d FALSE -f $CONF)
if [ "$ENABLED" != "TRUE" ]; then
echo "$QPKG_NAME is disabled."
exit 1
fi
$QPKG_ROOT/zerotier-one -d
;;
stop)
killall zerotier-one
;;
restart)
$0 stop
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit 0
EOF
chmod +x ${PROJECT_DIR}/qpkg-template/package_routines
chmod +x ${PROJECT_DIR}/qpkg-template/shared/zerotier.sh
# ===== 仅在非 config-only 模式下执行构建 =====
if [ "$CONFIG_ONLY" = false ]; then
if [ "$DOWNLOAD_ONLY" = false ]; then
echo "==> 开始构建..."
cd ${PROJECT_DIR}
docker compose up --build --force-recreate
echo "==> 构建完成!"
echo "最终 QPKG 文件位于:output/zerotier_1.16.2_x86_64.qpkg"
else
echo "==> 下载和文件生成完成。使用 './build.sh --download-only' 跳过构建。"
fi
else
echo "==> 仅生成/更新配置文件完成。使用 './build.sh --config-only' 跳过下载和构建。"
fi
三、Dockerfile.alpine(编译 ZeroTier)
此镜像基于 Alpine 3.20,使用 单线程 make 规避 Argument list too long 内核限制,并通过 静态链接 生成兼容 QNAP 的二进制文件。
FROM alpine:3.20
RUN apk update && apk add --no-cache \
make gcc g++ linux-headers musl-dev \
openssl-dev openssl-libs-static curl
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
WORKDIR /tmp/ZeroTierOne
COPY ZeroTierOne-src /tmp/ZeroTierOne
RUN make ZT_STATIC=1 -j${nproc}
RUN strip zerotier-one
CMD ["sh", "-c", "cp /tmp/ZeroTierOne/zerotier-one /build/qpkg-template/x86_64/ && cp /tmp/ZeroTierOne/zerotier-cli /build/qpkg-template/x86_64/ && cp /tmp/ZeroTierOne/zerotier-idtool /build/qpkg-template/x86_64/"]
四、Dockerfile.builder(QDK 打包环境)
此镜像基于 Ubuntu 22.04,负责离线安装 QDK 并对 qpkg-template 执行打包操作。
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y \
pv xz-utils rsync gnupg2 curl openssl bsdextrautils
COPY qdk.deb /tmp/qdk.deb
RUN dpkg -i /tmp/qdk.deb
WORKDIR /build/qpkg-template
COPY qpkg-template /build/qpkg-template
CMD ["sh", "-c", "qbuild --build-arch x86_64 && cp /build/qpkg-template/build/* /output/"]
五、docker-compose.yml(编排文件)
该文件整合了 Alpine 编译 与 Ubuntu 打包 两个阶段。构建指令完全由 Dockerfile 的 CMD 定义。
services:
alpine-builder:
platform: linux/amd64
build:
context: .
dockerfile: Dockerfile.alpine
volumes:
- ./qpkg-template:/build/qpkg-template
container_name: zerotier-alpine-builder
ubuntu-packager:
platform: linux/amd64
build:
context: .
dockerfile: Dockerfile.builder
volumes:
- ./qpkg-template:/build/qpkg-template
- ./output:/output
container_name: zerotier-ubuntu-packager
depends_on:
- alpine-builder
六、构建与提取
| 使用场景 | 命令 | 行为 |
|---|---|---|
| 第一次全量构建 | ./build.sh | 下载 + 生成配置 + 构建 |
| 只改配置 | ./build.sh --config-only | 不下载、不构建,只更新 cat 文件 |
| 下载构建 | ./build.sh --download-only | 下载 + 生成 Dockerfile |
| 重新构建 | docker compose up --build --force-recreate | 不下载、不更新,只构建 |
| 完整流程 | ./build.sh | 全部执行 |
构建完成后,最终产物位于:
output/zerotier_1.16.2_x86_64.qpkg


评论区