Migrate Harbor state and traffic history to SQLite
This commit is contained in:
@@ -10,7 +10,7 @@ GIT_REF="$(git rev-parse --short HEAD 2>/dev/null || echo manual)"
|
||||
IMAGE_TAG="${IMAGE_TAG:-${GIT_REF}-$(date +%Y%m%d%H%M%S)}"
|
||||
GATEWAY_IMAGE="${GATEWAY_IMAGE:-${IMAGE_NAME}:${IMAGE_TAG}}"
|
||||
BASE_IMAGE="${BASE_IMAGE:-vpn-proxy-runtime-base:bookworm-slim}"
|
||||
NODE_BUILD_IMAGE="${NODE_BUILD_IMAGE:-node:20.19-alpine}"
|
||||
NODE_BUILD_IMAGE="${NODE_BUILD_IMAGE:-node:24.21.0-bookworm}"
|
||||
RUNTIME_BASE_SOURCE_IMAGE="${RUNTIME_BASE_SOURCE_IMAGE:-mirror.gcr.io/library/debian:bookworm-slim}"
|
||||
SINGBOX_VERSION="${SINGBOX_VERSION:-1.14.0-rc.5}"
|
||||
DOCKER_BUILD_PULL="${DOCKER_BUILD_PULL:-false}"
|
||||
@@ -63,7 +63,7 @@ else
|
||||
fi
|
||||
|
||||
echo "Building image on ${BUILD_HOST}"
|
||||
BUILD_COMMAND="set -e; echo 'Docker context:' \$(docker context show 2>/dev/null || true); docker info 2>/dev/null | sed -n '/HTTP Proxy:/p;/HTTPS Proxy:/p;/Name:/p'; cd '${BUILD_PATH}'; if ! docker image inspect '${BASE_IMAGE}' >/dev/null 2>&1 || ! docker run --rm '${BASE_IMAGE}' sh -lc \"command -v npm >/dev/null && sing-box version 2>&1 | grep -Fx 'sing-box version ${SINGBOX_VERSION}'\"; then if [ '${AUTO_BUILD_RUNTIME_BASE}' = 'true' ]; then echo 'Runtime base image ${BASE_IMAGE} is missing or does not contain sing-box ${SINGBOX_VERSION}; building it now.'; BASE_IMAGE='${RUNTIME_BASE_SOURCE_IMAGE}' RUNTIME_BASE_IMAGE='${BASE_IMAGE}' SINGBOX_VERSION='${SINGBOX_VERSION}' ./scripts/build-runtime-base.sh; else echo 'Runtime base image ${BASE_IMAGE} is missing or does not contain sing-box ${SINGBOX_VERSION} on ${BUILD_HOST}.'; echo 'Seed it once with: ./scripts/build-runtime-base.sh'; exit 1; fi; fi; docker run --rm '${BASE_IMAGE}' sh -lc \"command -v npm >/dev/null && sing-box version 2>&1 | grep -Fx 'sing-box version ${SINGBOX_VERSION}'\"; npm ci && npm run build:production && docker build --pull='${DOCKER_BUILD_PULL}' --build-arg NODE_BUILD_IMAGE='${NODE_BUILD_IMAGE}' --build-arg BASE_IMAGE='${BASE_IMAGE}' --build-arg SINGBOX_VERSION='${SINGBOX_VERSION}' --build-arg INSTALL_RUNTIME_DEPS='${INSTALL_RUNTIME_DEPS}' --build-arg INSTALL_SINGBOX='${INSTALL_SINGBOX}' -t '${GATEWAY_IMAGE}' . && docker run --rm --entrypoint sing-box '${GATEWAY_IMAGE}' version 2>&1 | grep -Fx 'sing-box version ${SINGBOX_VERSION}'"
|
||||
BUILD_COMMAND="set -e; echo 'Docker context:' \$(docker context show 2>/dev/null || true); docker info 2>/dev/null | sed -n '/HTTP Proxy:/p;/HTTPS Proxy:/p;/Name:/p'; cd '${BUILD_PATH}'; if ! docker image inspect '${BASE_IMAGE}' >/dev/null 2>&1 || ! docker run --rm '${BASE_IMAGE}' sh -lc \"command -v npm >/dev/null && sing-box version 2>&1 | grep -Fx 'sing-box version ${SINGBOX_VERSION}'\"; then if [ '${AUTO_BUILD_RUNTIME_BASE}' = 'true' ]; then echo 'Runtime base image ${BASE_IMAGE} is missing or does not contain sing-box ${SINGBOX_VERSION}; building it now.'; BASE_IMAGE='${RUNTIME_BASE_SOURCE_IMAGE}' RUNTIME_BASE_IMAGE='${BASE_IMAGE}' SINGBOX_VERSION='${SINGBOX_VERSION}' ./scripts/build-runtime-base.sh; else echo 'Runtime base image ${BASE_IMAGE} is missing or does not contain sing-box ${SINGBOX_VERSION} on ${BUILD_HOST}.'; echo 'Seed it once with: ./scripts/build-runtime-base.sh'; exit 1; fi; fi; docker run --rm '${BASE_IMAGE}' sh -lc \"command -v npm >/dev/null && sing-box version 2>&1 | grep -Fx 'sing-box version ${SINGBOX_VERSION}'\"; node scripts/check-sqlite-runtime.mjs && npm ci && npm run build:production && docker build --pull='${DOCKER_BUILD_PULL}' --build-arg NODE_BUILD_IMAGE='${NODE_BUILD_IMAGE}' --build-arg BASE_IMAGE='${BASE_IMAGE}' --build-arg SINGBOX_VERSION='${SINGBOX_VERSION}' --build-arg INSTALL_RUNTIME_DEPS='${INSTALL_RUNTIME_DEPS}' --build-arg INSTALL_SINGBOX='${INSTALL_SINGBOX}' -t '${GATEWAY_IMAGE}' . && docker run --rm --entrypoint sing-box '${GATEWAY_IMAGE}' version 2>&1 | grep -Fx 'sing-box version ${SINGBOX_VERSION}'"
|
||||
if [ "${BUILD_HOST}" = "local" ]; then
|
||||
bash -lc "${BUILD_COMMAND}"
|
||||
else
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
set -euo pipefail
|
||||
|
||||
BASE_IMAGE="${BASE_IMAGE:-mirror.gcr.io/library/debian:bookworm-slim}"
|
||||
NODE_BUILD_IMAGE="${NODE_BUILD_IMAGE:-node:24.21.0-bookworm}"
|
||||
RUNTIME_BASE_IMAGE="${RUNTIME_BASE_IMAGE:-vpn-proxy-runtime-base:bookworm-slim}"
|
||||
SINGBOX_VERSION="${SINGBOX_VERSION:-1.14.0-rc.5}"
|
||||
APT_MIRROR="${APT_MIRROR:-http://mirror.yandex.ru/debian}"
|
||||
@@ -18,6 +19,7 @@ if [ -n "${HTTP_PROXY}" ]; then echo "HTTP proxy: ${HTTP_PROXY}"; fi
|
||||
if [ -n "${HTTPS_PROXY}" ]; then echo "HTTPS proxy: ${HTTPS_PROXY}"; fi
|
||||
|
||||
docker build \
|
||||
--build-arg NODE_BUILD_IMAGE="${NODE_BUILD_IMAGE}" \
|
||||
--build-arg BASE_IMAGE="${BASE_IMAGE}" \
|
||||
--build-arg SINGBOX_VERSION="${SINGBOX_VERSION}" \
|
||||
--build-arg APT_MIRROR="${APT_MIRROR}" \
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { DatabaseSync } from 'node:sqlite';
|
||||
|
||||
assert.equal(process.versions.node, '24.21.0', 'Harbor requires the pinned Node 24.21.0 runtime');
|
||||
const db = new DatabaseSync(':memory:');
|
||||
try {
|
||||
const version = db.prepare('SELECT sqlite_version() AS version').get().version;
|
||||
const [major, minor, patch] = version.split('.').map(Number);
|
||||
assert.ok(major > 3 || (major === 3 && (minor > 51 || (minor === 51 && patch >= 3))),
|
||||
'Harbor requires SQLite >= 3.51.3 with the WAL-reset fix');
|
||||
db.exec('CREATE TABLE probe (bytes INTEGER NOT NULL) STRICT');
|
||||
db.prepare('INSERT INTO probe VALUES (?)').run(9007199254740993n);
|
||||
const statement = db.prepare('SELECT bytes FROM probe');
|
||||
statement.setReadBigInts(true);
|
||||
assert.equal(statement.get().bytes, 9007199254740993n);
|
||||
console.log(`Harbor runtime: Node ${process.versions.node}, SQLite ${version}, ${process.platform}/${process.arch}`);
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
@@ -52,7 +52,7 @@ export function affectedComponents(files) {
|
||||
const add = (...components) => components.forEach((component) => affected.add(component));
|
||||
for (const file of files) {
|
||||
if (file === VERSION_FILE) continue;
|
||||
if (/^(?:\.dockerignore$|package(?:-lock)?\.json$|tsconfig\.base\.json$|src\/shared\/)/.test(file)) add(...COMPONENTS);
|
||||
if (/^(?:\.dockerignore$|\.node-version$|scripts\/check-sqlite-runtime\.mjs$|package(?:-lock)?\.json$|tsconfig\.base\.json$|src\/shared\/)/.test(file)) add(...COMPONENTS);
|
||||
else if (/^(src\/web\/|public\/|monitoring\/grafana\/|index\.html$|tsconfig\.web\.json$|vite\.config\.[cm]?[jt]s$)/.test(file)) {
|
||||
add('macClient', 'gatewayClient');
|
||||
} else if (/^(src\/server\/|tsconfig\.server\.json$)/.test(file)) add('macClient', 'gatewayBackend');
|
||||
|
||||
@@ -22,6 +22,8 @@ const noRuntimeImpact = [
|
||||
/^tools\/test-singbox-(?:client-rc|gateway-native-traffic|native-traffic)\.sh$/,
|
||||
];
|
||||
const foundation = [
|
||||
/^\.node-version$/,
|
||||
/^scripts\/check-sqlite-runtime\.mjs$/,
|
||||
/^\.dockerignore$/,
|
||||
/^\.gitea\/workflows\//,
|
||||
/^Dockerfile(?:\.runtime-base)?$/,
|
||||
@@ -33,6 +35,8 @@ const foundation = [
|
||||
/^tsconfig(?:\.[^.]+)?\.json$/,
|
||||
];
|
||||
const controlAndDataplane = [
|
||||
/^src\/server\/services\/(?:sqlite|trafficHistoryStore|trafficHistoryService|trafficHistoryWorker)\.ts$/,
|
||||
/^src\/shared\/trafficHistory\.ts$/,
|
||||
/^buf\.gen\.yaml$/,
|
||||
/^proto\//,
|
||||
new RegExp(`^src/server/main${CODE_EXTENSION}`),
|
||||
|
||||
Reference in New Issue
Block a user