fix: prepare manual-install certificates before starting workers

This commit is contained in:
whyour
2026-10-18 03:01:33 +08:00
parent c63ff6598e
commit f8ffa48c32
3 changed files with 65 additions and 1 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ node install-bundle.cjs --root /opt/qinglong --file /absolute/path/package.tar.g
QL_DIR=/opt/qinglong QL_DATA_DIR=/opt/qinglong/data bash /opt/qinglong/shell/start-simplify.sh QL_DIR=/opt/qinglong QL_DATA_DIR=/opt/qinglong/data bash /opt/qinglong/shell/start-simplify.sh
``` ```
`--install` 拒绝非空目录,不覆盖既有配置。该包安装青龙及其 Node 生产依赖;首次启动仍需已有 Python、Bash、PM2、nginx 等相应运行环境,不会在线安装或替换它们。服务启动和系统自启按原手动安装流程配置。 `--install` 拒绝非空目录,不覆盖既有配置。该包安装青龙及其 Node 生产依赖;首次启动仍需已有 Python、Bash、OpenSSL、PM2、nginx 等相应运行环境,不会在线安装或替换它们。手动启动脚本会在启动工作进程前完成首次 gRPC 证书准备,避免慢设备生成密钥耗尽工作进程的就绪期限;已有证书继续复用。服务启动和系统自启按原手动安装流程配置。
ARMv6 glibc 小设备(例如 Raspberry Pi 1/Zero 的 Raspbian/Raspberry Pi OS 32 位系统)选择 `linux-armv6-glibc.tar.gz`,以同一安装器执行上述离线命令。该包要求 glibc >= 2.31、ARMv6 硬浮点 Node >= 20.18.1,不适用于 ARMv5、软浮点 Node 或旧版 glibc。安装和升级均不需要 Docker,也不会下载或替换 Node。 ARMv6 glibc 小设备(例如 Raspberry Pi 1/Zero 的 Raspbian/Raspberry Pi OS 32 位系统)选择 `linux-armv6-glibc.tar.gz`,以同一安装器执行上述离线命令。该包要求 glibc >= 2.31、ARMv6 硬浮点 Node >= 20.18.1,不适用于 ARMv5、软浮点 Node 或旧版 glibc。安装和升级均不需要 Docker,也不会下载或替换 Node。
+11
View File
@@ -52,6 +52,17 @@ make_dir /etc/nginx/conf.d
make_dir /run/nginx make_dir /run/nginx
fix_config fix_config
# Slow devices may need more than the worker's readiness window to generate
# first-boot certificates. Reuse the regular initializer before starting workers.
node <<'QL_PREPARE_GRPC_CERTS'
require(require('node:path').join(process.env.QL_DIR, 'static/build/config/grpcCerts.js'))
.initGrpcCerts()
.catch((error) => {
console.error(error);
process.exitCode = 1;
});
QL_PREPARE_GRPC_CERTS
pm2 l &>/dev/null pm2 l &>/dev/null
log_with_style "INFO" "$(t '🔄 2. 启动 nginx...')" log_with_style "INFO" "$(t '🔄 2. 启动 nginx...')"
@@ -0,0 +1,53 @@
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { spawnSync } = require('node:child_process');
const startup = fs.readFileSync('shell/start-simplify.sh', 'utf8');
const preparation = startup.slice(
startup.indexOf('\nfix_config\n'),
startup.indexOf('log_with_style "INFO" "$(t \'🔄'),
);
for (const fails of [false, true]) {
test(`manual startup ${
fails
? 'stops on certificate failure'
: 'awaits certificates before starting supervision'
}`, (t) => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ql-start-certs-'));
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
const module = path.join(root, 'static/build/config/grpcCerts.js');
fs.mkdirSync(path.dirname(module), { recursive: true });
fs.writeFileSync(
module,
`exports.initGrpcCerts = () => new Promise((resolve, reject) => setTimeout(() => {
if (process.env.QA_CERT_FAILURE === '1') return reject(new Error('certificate preparation failed'));
require('node:fs').writeFileSync(require('node:path').join(process.env.QL_DIR, 'certs-ready'), 'ready');
resolve();
}, 50));`,
);
const result = spawnSync(
'/bin/bash',
[
'-c',
`set -e
fix_config(){ :; }
pm2(){ test -f "$QL_DIR/certs-ready"; touch "$QL_DIR/supervisor-started"; }
${preparation}`,
],
{
encoding: 'utf8',
env: {
...process.env,
QL_DIR: root,
QA_CERT_FAILURE: fails ? '1' : '0',
},
},
);
assert.equal(result.status, fails ? 1 : 0, result.stderr);
assert.equal(fs.existsSync(path.join(root, 'supervisor-started')), !fails);
if (fails) assert.match(result.stderr, /certificate preparation failed/);
});
}