
如果你使用 DeepSeek、元宝 AI、Copilot、ChatGPT 等 AI 工具,协助配置轩辕镜像、编写 docker pull 命令、修改 Docker Compose 镜像地址、配置镜像加速、排查镜像拉取失败、分析报错日志等问题,请先让 AI 阅读并遵守轩辕镜像的规则文档。
只需在 AI 对话中先发送下面这句话即可:
请先完整阅读并严格遵守以下文档中的全部规则与要求:
https://xuanyuan.cloud/agents.md
在未充分阅读并理解该文档前,不要生成任何命令、配置、修改建议、故障排查方案或技术回答。后续所有输出都必须严格以该文档中的规范为最高优先级执行。查看 agents.md 用法指南与完整示范。国内用户首推 元宝 AI、DeepSeek 的深度思考模式,不推荐豆包 AI;Cursor 等编辑器可在对话 @ 该链接,或加入 User Rules。 若 AI 无法访问外链,可 打开说明文档 复制全文粘贴。文档会随站点更新,复制内容可能过期,建议定期检查。
一个轻量级Docker镜像,提供Corosync QDevice仲裁器(corosync-qnetd)——为双节点Proxmox VE集群添加外部打破平局的投票,使其成为真正的高可用性(HA)设置。
Proxmox VE集群需要法定票数(多数投票)才能安全地做出HA决策。双节点集群有2票,若其中一个节点无法通信,双方都无法获得多数票,集群会冻结HA管理的VM以防止脑裂。
Proxmox官方推荐的解决方案是QDevice:在第三台机器上运行的小型进程,添加1票,使任何存活的单节点获得3票中的2票,保持法定状态。
但Proxmox文档假设你有第三台Linux机器,而大多数家庭实验室或小型企业没有——他们只有NAS。corosync-qnetd没有官方容器镜像,因此用户不得不添加树莓派或在NAS主机OS上安装包。本镜像解决了这个问题:可部署在任何支持Docker的主机(QNAP Container Station、Synology、TrueNAS、树莓派等)上,让NAS成为仲裁器。
┌──────────────┐ ┌──────────────┐ │ pve01 │◄───── corosync ──────►│ pve02 │ │ (1票) │ │ (1票) │ └──────┬───────┘ └───────┬──────┘ │ │ │ corosync-qdevice(每个节点) │ └────────────┬──────────────────────────┘ │ │ TCP/5403(TLS,NSS证书) ▼ ┌─────────────────────┐ │ corosync-qnetd │ <-- 本容器 │ (1票,仲裁器) │ └─────────────────────┘
| 组件 | 运行位置 | 功能 |
|---|---|---|
corosync | 每个PVE节点 | 集群消息总线 |
corosync-qdevice | 每个PVE节点 | 仲裁器的本地客户端 |
corosync-qnetd | 本容器 | 外部仲裁器,提供额外1票 |
部署本镜像后的法定票数计算:
| 场景 | 可用票数 | 法定票数(≥2) | 集群状态 |
|---|---|---|---|
| 所有节点健康 | 3(2个节点 + qnetd) | 是 | 法定状态 |
| 一个PVE节点宕机 | 2(1个节点 + qnetd) | 是 | 法定状态,HA恢复VM |
| qnetd宕机,两个节点正常 | 2(2个节点) | 是 | 法定状态,无法进行HA故障转移 |
| 一个PVE节点宕机且qnetd宕机 | 1 | 否 | 存活节点冻结(正确行为) |
debian:13-slim + corosync-qnetd + openssh-server),大小约120 MB。pvecm qdevice setup <ip>可直接使用——Proxmox使用22端口(硬编码)安装NSS证书。/root/.ssh/authorized_keys的所有权为root:root,避免SMB上传的非root UID文件被SSH StrictModes静默拒绝。linux/amd64、linux/arm64。| 标签 | 描述 | 架构 |
|---|---|---|
1.0.0, 1.0, 1, latest | 稳定版本 | linux/amd64, linux/arm64 |
标签遵循https://semver.org/。`latest`标签始终指向最新稳定版本。
若仅需验证容器运行:
bashdocker run -d \ --name corosync-qnetd \ -p 5403:5403/tcp \ -p 22:22/tcp \ -v ./configs/qnetd-nssdb:/etc/corosync/qnetd/nssdb \ -v ./configs/ssh-host-keys:/etc/ssh/keys \ -v ./configs/ssh-authorized-keys:/root/.ssh \ docker.xuanyuan.run/lpgonzalez/corosync-qnetd:latest
容器将启动,生成密钥,暴露5403/tcp(qnetd)和22/tcp(SSH),等待pvecm qdevice setup填充NSS数据库。
这本身不足以完成设置——请阅读Proxmox VE完整设置部分以实现与PVE的集成。
pvecm status——应列出两个节点且Quorum: 2)。bashapt update && apt install -y corosync-qdevice
选择与主机匹配的部署方案并启动容器。容器将:
configs/ssh-host-keys/下生成持久化SSH主机密钥。configs/qnetd-nssdb/下初始化空的qnetd NSS数据库。sshd和corosync-qnetd(前台运行)。验证容器健康状态:
bashdocker ps --filter name=corosync-qnetd # 状态列应显示“Up X minutes (healthy)”(约30秒后)
Proxmox通过root用户SSH引导QDevice。容器仅允许公钥认证,因此每个PVE节点的root公钥需添加到容器的authorized_keys中。
在每个PVE节点上:
bash# 若不存在密钥则生成: [ -f /root/.ssh/id_rsa ] || ssh-keygen -t rsa -b 4096 -N "" -f /root/.ssh/id_rsa cat /root/.ssh/id_rsa.pub
将输出的公钥添加到容器的authorized_keys文件中:
<主机路径>/configs/ssh-authorized-keys/authorized_keys
每个节点一行。容器的入口点将在下次重启时重新应用正确的所有权(root:root)和权限(600),因此上传文件的UID无关紧要。
若文件通过SMB/CIFS或NFS上传,容器内的所有权可能显示为UID 1000等。重启容器让入口点修复,或运行
docker exec corosync-qnetd chown -R root:root /root/.ssh。
从每个PVE节点测试SSH连接容器:
bashssh -o IdentitiesOnly=yes -i /root/.ssh/id_rsa root@<qnetd主机> hostname
应输出容器的主机名。若提示接受主机密钥,请输入yes——该指纹对应configs/ssh-host-keys/中的密钥。
在任意一个PVE节点上运行一次(通过Corosync自动配置两个节点):
bashpvecm qdevice setup <qnetd主机>
幕后,pvecm将:
/etc/corosync/qnetd/nssdb/(持久化卷)中。/etc/corosync/corosync.conf以声明QDevice。bashpvecm status
预期输出:
Votequorum information ---------------------- Expected votes: 3 Highest expected: 3 Total votes: 3 Quorum: 2 Flags: Quorate Qdevice Membership information ---------------------- Nodeid Votes Qdevice Name 0x00000001 1 A,V,NMW <node1> 0x00000002 1 A,V,NMW <node2> 0x00000000 1 Qdevice
若Flags显示Quorate Qdevice且Total votes:3,设置完成。
| 容器路径 | 用途 | 是否需要持久化 |
|---|---|---|
/etc/corosync/qnetd/nssdb | 存储集群证书的NSS数据库 | 是——丢失将需重新运行pvecm qdevice setup |
/etc/ssh/keys | SSH主机密钥(服务器身份) | 推荐——避免PVE在容器重建后出现“主机密钥更改”警告 |
/root/.ssh | 授权密钥文件 | 是——操作员/PVE公钥存储于此 |
| 端口 | 协议 | 用途 | 备注 |
|---|---|---|---|
| 5403 | TCP | Corosync QNet协议(TLS) | PVE节点连接此端口获取法定票数 |
| 22 | TCP | OpenSSH服务器 | 仅在pvecm qdevice setup期间使用——之后可防火墙阻断 |
两个端口必须从每个PVE节点可达容器。qnetd端口(5403)必须保持可达;SSH端口在证书引导后可关闭以减少***面。
本镜像不接受运行时环境变量——所有行为由持久化NSS数据库和授权密钥文件驱动。Compose文件中的configs/env/vars.env为未来扩展预留。
唯一值得备份的状态是NSS数据库。没有它需重新运行pvecm qdevice setup;有了它可在几分钟内重建主机。
备份:
bashdocker compose stop # 快速停止以避免写入中捕获 tar czf qnetd-state-$(date +%F).tar.gz \ configs/qnetd-nssdb \ configs/ssh-host-keys \ configs/ssh-authorized-keys docker compose start
主机上每周一次的Cron任务通常足够——NSS数据库在集群设置后几乎不变化。
在新主机上恢复:
bashtar xzf qnetd-state-YYYY-MM-DD.tar.gz docker compose up -d
PVE端无需操作——两个节点将在下次Corosync轮询时重新连接到恢复的qnetd。若qnetd移至新IP,需在PVE端更新Corosync:
bashpvecm qdevice remove pvecm qdevice setup <新qnetd主机>
旧款QNAP型号(如TS-x63系列)的Container Station有两个已知问题:
build:的Compose时,Container Station将YAML复制到临时目录而无其他文件,导致构建失败(open Dockerfile: no such file or directory)。docker CLI可能无法创建$HOME——运行docker build时可能看到ERROR: mkdir /share/CACHEDEV1_DATA/.qpkg/.../homes/<user>: permission denied。推荐方法:
yamlservices: corosync-qnetd: image: docker.xuanyuan.run/lpgonzalez/corosync-qnetd:latest container_name: corosync-qnetd restart: unless-stopped ports: - "5403:5403/tcp" - "22:22/tcp" volumes: - /share/Container/corosync-qnetd/configs/qnetd-nssdb:/etc/corosync/qnetd/nssdb - /share/Container/corosync-qnetd/configs/ssh-host-keys:/etc/ssh/keys - /share/Container/corosync-qnetd/configs/ssh-authorized-keys:/root/.ssh
控制面板 → 网络与文件服务 → Telnet/SSH。QTS SSH移至7000后,上述22:22映射无冲突。/share/Container/corosync-qnetd/,然后在Container Station中创建指向该Compose的应用。替代方案(无需拉取DockerHub): 在工作站本地构建镜像,通过docker save/docker load上传至NAS。参见从源码构建——包含的Makefile通过make nas-deploy自动完成此流程。
标准docker compose up -d即可。需检查主机的22端口是否空闲,或重新映射容器SSH到其他端口(如2222:22)。但**pvecm qdevice setup硬编码SSH 22端口**,若重新映射需手动引导证书:
bash# 在PVE节点上仅生成证书文件(SSH步骤将失败): pvecm qdevice setup <主机> 2>/dev/null || true # 将/etc/pve/qnetd-cacert.crt通过scp -P 2222复制到容器,然后: ssh -p 2222 root@<主机> \ corosync-qnetd-certutil -s -c /tmp/qnetd-cacert.crt -n <集群名称> # 在PVE上重新运行以完成设置: pvecm qdevice setup <主机>
30欧元的树莓派运行Docker是最便宜且可靠的QDevice主机。标准安装:
bashsudo apt install -y docker.io docker-compose-plugin git clone https://github.com/lpgonzalez/corosync-qnetd-docker cd corosync-qnetd-docker docker compose up -d
镜像的arm64变体原生运行于树莓派3/4/5(64位Raspberry Pi OS)。压缩包约50MB。
Permission denied (publickey)按可能性排序:
authorized_keys所有权非root:SSH的StrictModes会静默拒绝非目标用户所有的授权密钥。修复:
重启容器让入口点固化这些权限。bashdocker exec corosync-qnetd chown -R root:root /root/.ssh docker exec corosync-qnetd chmod 700 /root/.ssh docker exec corosync-qnetd chmod 600 /root/.ssh/authorized_keys
authorized_keys中的公钥与PVE的id_rsa.pub不匹配:比较指纹:
bash# 在容器主机上: docker exec corosync-qnetd ssh-keygen -lf /root/.ssh/authorized_keys # 在每个PVE节点上: ssh-keygen -lf /root/.ssh/id_rsa.pub
bashdocker inspect corosync-qnetd --format '{{ range .Mounts }}{{ .Source }} -> {{ .Destination }}{{ "\n" }}{{ end }}'
pvecm qdevice setup失败并显示No route to host容器健康但PVE节点无法访问TCP/22端口。常见原因:
macvlan网络,其父网卡未连接电缆。exec: corosync-qnetd: not found(容器重启循环)若从源码构建,确保Dockerfile使用Debian bookworm或更新版本——旧版本中二进制路径为/usr/sbin/corosync-qnetd,当前Debian移至/usr/bin/corosync-qnetd。包含的入口点使用exec corosync-qnetd -f(无绝对路径),兼容两种布局。
容器仅在/etc/ssh/keys卷为空时重新生成SSH主机密钥。若未持久化该卷(或已清空),新密钥为全新。在每个PVE节点上清除过时条目:
bashssh-keygen -R <qnetd主机>
sshd -d时出现bind: address already in use忘记终止入口点的sshd。使用:
bashdocker exec corosync-qnetd pkill sshd docker exec -d corosync-qnetd /usr/sbin/sshd -d -e -E /tmp/sshd.log
克隆并使用Makefile:
bashgit clone https://github.com/lpgonzalez/corosync-qnetd-docker cd corosync-qnetd-docker make help # 列出所有目标
常见流程:
bash# 本地单架构构建(当前主机架构): make build # 构建、保存为tar.gz、通过SSH上传至NAS并加载: make nas-deploy # (先编辑Makefile顶部的nas-user、nas-host、nas-ssh-port、nas-dest) # 多架构发布至Docker Hub: docker login make release
release目标使用Docker Buildx生成覆盖platforms变量(默认:linux/amd64,linux/arm64)所有平台的清单列表,并推送到release-tags(默认:当前image-version和latest)。
要更新版本,编辑Makefile中的image-version并重新运行make release。
sshd监听22端口,仅允许root用户通过公钥登录。禁用密码、PAM和挑战响应。root无密码。authorized_keys。切勿将私钥放入容器。pvecm qdevice setup期间需要。引导后可防火墙阻断,集群仍正常工作——corosync-qnetd本身使用TCP/5403。configs/qnetd-nssdb/中的NSS数据库包含集群证书颁发机构。视为机密:不要推送到公共Git仓库(包含的.gitignore默认排除)。Q: 能否用一个qnetd容器仲裁多个PVE集群?
可以。corosync-qnetd原生支持多个集群——每个集群以不同名称注册。只需从每个集群运行pvecm qdevice setup <主机>。
Q: qnetd容器宕机会发生什么?
只要两个PVE节点仍能通信(仍有3票中的2票),集群继续工作。HA故障转移停止,直到qnetd恢复。无数据丢失。
Q: qnetd需要连接UPS吗?
不严格需要。最坏情况(qnetd宕机+一个PVE节点宕机)仅冻结存活节点,这是正确行为。若希望NAS电源中断时HA仍可用,可将NAS连接UPS。
Q: 能否在PVE节点上运行qnetd?
不能。QDevice的核心是外部于集群。若qnetd随节点宕机,则无任何法定票数收益。
Q: 镜像支持IPv6吗?
支持。corosync-qnetd默认监听双栈。在Compose中相应暴露端口即可。
Q: 容器内为何包含SSH服务器?是否有额外开销?
Proxmox的pvecm qdevice setup脚本通过SSH引导证书。无容器内SSH需手动操作,但官方工具无法使用。sshd的开销约5MB空间和3MB空闲RAM。
MIT © Lisardo Prieto
corosync-qnetd开发者)。13-slim镜像)。发现 bug 或想贡献? 在https://github.com/lpgonzalez/corosync-qnetd-docker提交issue或PR。
您可以使用以下命令拉取该镜像。请将 <标签> 替换为具体的标签版本。如需查看所有可用标签版本,请访问 标签列表页面。
来自真实用户的反馈,见证轩辕镜像的优质服务