feat(ql3): establish 3.0 incubation baseline

This commit is contained in:
whyour
2026-08-12 00:25:26 +08:00
parent 4bf92dcfeb
commit c699c32461
2817 changed files with 779642 additions and 653 deletions
@@ -0,0 +1,96 @@
FROM node:24.18.0-bookworm-slim@sha256:6f7b03f7c2c8e2e784dcf9295400527b9b1270fd37b7e9a7285cf83b6951452d AS dependency-manifest
WORKDIR /opt/qinglong
COPY deploy/containers/ql3-cluster-admin/package.json ./
COPY deploy/containers/ql3-cluster-admin/package-lock.json ./
FROM dependency-manifest AS build-dependencies
RUN npm ci --ignore-scripts --no-audit --no-fund \
&& npm cache clean --force
FROM dependency-manifest AS runtime-dependency-manifest
COPY deploy/containers/ql3-cluster-admin/runtime-dependencies/package.json \
package.json
COPY deploy/containers/ql3-cluster-admin/runtime-dependencies/package-lock.json \
package-lock.json
FROM build-dependencies AS workspace
WORKDIR /workspace
COPY packages/ql3-runtime-core packages/ql3-runtime-core
COPY packages/ql3-ai packages/ql3-ai
COPY packages/ql3-cluster-postgres packages/ql3-cluster-postgres
COPY packages/ql3-cluster-admin packages/ql3-cluster-admin
RUN ln -s /opt/qinglong/node_modules node_modules \
&& mkdir -p /opt/qinglong/node_modules/@qinglong \
&& ln -s /workspace/packages/ql3-runtime-core \
/opt/qinglong/node_modules/@qinglong/runtime-core \
&& ln -s /workspace/packages/ql3-ai \
/opt/qinglong/node_modules/@qinglong/ai \
&& ln -s /workspace/packages/ql3-cluster-postgres \
/opt/qinglong/node_modules/@qinglong/cluster-postgres \
&& ln -s /workspace/packages/ql3-cluster-admin \
/opt/qinglong/node_modules/@qinglong/cluster-admin \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-runtime-core/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-ai/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-cluster-postgres/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-cluster-admin/tsconfig.json
FROM runtime-dependency-manifest AS external-dependencies
RUN npm ci --omit=dev --ignore-scripts --no-audit --no-fund \
&& npm cache clean --force
FROM external-dependencies AS assembled
RUN mkdir -p \
node_modules/@qinglong/runtime-core \
node_modules/@qinglong/ai \
node_modules/@qinglong/cluster-postgres \
node_modules/@qinglong/cluster-admin
COPY --from=workspace /workspace/packages/ql3-runtime-core/package.json \
node_modules/@qinglong/runtime-core/package.json
COPY --from=workspace /workspace/packages/ql3-runtime-core/dist \
node_modules/@qinglong/runtime-core/dist
COPY --from=workspace /workspace/packages/ql3-ai/package.json \
node_modules/@qinglong/ai/package.json
COPY --from=workspace /workspace/packages/ql3-ai/dist \
node_modules/@qinglong/ai/dist
COPY --from=workspace /workspace/packages/ql3-cluster-postgres/package.json \
node_modules/@qinglong/cluster-postgres/package.json
COPY --from=workspace /workspace/packages/ql3-cluster-postgres/dist \
node_modules/@qinglong/cluster-postgres/dist
COPY --from=workspace /workspace/packages/ql3-cluster-admin/package.json \
node_modules/@qinglong/cluster-admin/package.json
COPY --from=workspace /workspace/packages/ql3-cluster-admin/dist \
node_modules/@qinglong/cluster-admin/dist
FROM node:24.18.0-bookworm-slim@sha256:6f7b03f7c2c8e2e784dcf9295400527b9b1270fd37b7e9a7285cf83b6951452d AS runtime
ARG SOURCE_REVISION=uncommitted
LABEL org.opencontainers.image.title="QingLong 3.0 Cluster Admin" \
org.opencontainers.image.description="QingLong 3.0 short-lived cluster administration jobs" \
org.opencontainers.image.source="https://github.com/whyour/qinglong" \
org.opencontainers.image.revision="${SOURCE_REVISION}" \
org.opencontainers.image.licenses="Apache-2.0"
ENV NODE_ENV=production
WORKDIR /opt/qinglong
COPY --from=assembled --chown=10001:10001 /opt/qinglong ./
USER 10001:10001
ENTRYPOINT ["node", "/opt/qinglong/node_modules/@qinglong/cluster-admin/dist/plugin-package/recovery/pluginPackageRecoveryCli.js"]
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,21 @@
{
"name": "@qinglong/cluster-admin-image-dependencies",
"version": "3.0.0-alpha.0",
"private": true,
"description": "Locked external dependencies for the QingLong 3.0 short-lived cluster admin image",
"license": "Apache-2.0",
"engines": {
"node": ">=24.18.0 <25"
},
"dependencies": {
"@kubernetes/client-node": "1.4.0",
"drizzle-orm": "0.45.2",
"pg": "8.22.0",
"semver": "7.7.4"
},
"devDependencies": {
"@types/node": "24.13.3",
"@types/pg": "8.20.0",
"typescript": "5.9.3"
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,16 @@
{
"name": "@qinglong/cluster-admin-image-dependencies",
"version": "3.0.0-alpha.0",
"private": true,
"description": "Production-only external dependency root for the QingLong 3.0 short-lived cluster admin image",
"license": "Apache-2.0",
"engines": {
"node": ">=24.18.0 <25"
},
"dependencies": {
"@kubernetes/client-node": "1.4.0",
"drizzle-orm": "0.45.2",
"pg": "8.22.0",
"semver": "7.7.4"
}
}
@@ -0,0 +1,123 @@
FROM node:24.18.0-bookworm-slim@sha256:6f7b03f7c2c8e2e784dcf9295400527b9b1270fd37b7e9a7285cf83b6951452d AS dependency-manifest
WORKDIR /opt/qinglong
COPY deploy/containers/ql3-cluster-control/package.json ./
COPY deploy/containers/ql3-cluster-control/package-lock.json ./
FROM dependency-manifest AS build-dependencies
RUN npm ci --ignore-scripts --no-audit --no-fund \
&& npm cache clean --force
FROM dependency-manifest AS runtime-dependency-manifest
COPY deploy/containers/ql3-cluster-control/runtime-dependencies/package.json \
package.json
COPY deploy/containers/ql3-cluster-control/runtime-dependencies/package-lock.json \
package-lock.json
FROM build-dependencies AS workspace
WORKDIR /workspace
COPY packages/ql3-runtime-core packages/ql3-runtime-core
COPY packages/ql3-cluster-postgres packages/ql3-cluster-postgres
COPY packages/ql3-cluster-control packages/ql3-cluster-control
COPY deploy/containers/ql3-cluster-control/tsconfig.default.json \
deploy/containers/ql3-cluster-control/tsconfig.default.json
RUN ln -s /opt/qinglong/node_modules node_modules \
&& mkdir -p /opt/qinglong/node_modules/@qinglong \
&& ln -s /workspace/packages/ql3-runtime-core \
/opt/qinglong/node_modules/@qinglong/runtime-core \
&& ln -s /workspace/packages/ql3-cluster-postgres \
/opt/qinglong/node_modules/@qinglong/cluster-postgres \
&& ln -s /workspace/packages/ql3-cluster-control \
/opt/qinglong/node_modules/@qinglong/cluster-control \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-runtime-core/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-cluster-postgres/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p deploy/containers/ql3-cluster-control/tsconfig.default.json
FROM workspace AS workspace-ai
COPY packages/ql3-ai packages/ql3-ai
RUN ln -s /workspace/packages/ql3-ai \
/opt/qinglong/node_modules/@qinglong/ai \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-ai/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-cluster-control/tsconfig.json
FROM runtime-dependency-manifest AS external-dependencies
RUN npm ci --omit=dev --ignore-scripts --no-audit --no-fund \
&& npm cache clean --force
FROM external-dependencies AS assembled
RUN mkdir -p \
node_modules/@qinglong/runtime-core \
node_modules/@qinglong/cluster-postgres \
node_modules/@qinglong/cluster-control
COPY --from=workspace /workspace/packages/ql3-runtime-core/package.json \
node_modules/@qinglong/runtime-core/package.json
COPY --from=workspace /workspace/packages/ql3-runtime-core/dist \
node_modules/@qinglong/runtime-core/dist
COPY --from=workspace /workspace/packages/ql3-cluster-postgres/package.json \
node_modules/@qinglong/cluster-postgres/package.json
COPY --from=workspace /workspace/packages/ql3-cluster-postgres/dist \
node_modules/@qinglong/cluster-postgres/dist
COPY --from=workspace /workspace/packages/ql3-cluster-control/package.json \
node_modules/@qinglong/cluster-control/package.json
COPY --from=workspace /workspace/.ql3-image-build/cluster-control-default-dist \
node_modules/@qinglong/cluster-control/dist
FROM assembled AS assembled-ai
RUN mkdir -p node_modules/@qinglong/ai
COPY --from=workspace-ai /workspace/packages/ql3-ai/package.json \
node_modules/@qinglong/ai/package.json
COPY --from=workspace-ai /workspace/packages/ql3-ai/dist \
node_modules/@qinglong/ai/dist
COPY --from=workspace-ai /workspace/packages/ql3-cluster-control/dist \
node_modules/@qinglong/cluster-control/dist
FROM node:24.18.0-bookworm-slim@sha256:6f7b03f7c2c8e2e784dcf9295400527b9b1270fd37b7e9a7285cf83b6951452d AS runtime-base
ARG SOURCE_REVISION=uncommitted
LABEL org.opencontainers.image.title="QingLong 3.0 Cluster Control" \
org.opencontainers.image.description="QingLong 3.0 PostgreSQL-backed cluster control plane" \
org.opencontainers.image.source="https://github.com/whyour/qinglong" \
org.opencontainers.image.revision="${SOURCE_REVISION}" \
org.opencontainers.image.licenses="Apache-2.0"
ENV NODE_ENV=production
WORKDIR /opt/qinglong
USER 10001:10001
EXPOSE 5800
FROM runtime-base AS runtime-ai
LABEL org.opencontainers.image.title="QingLong 3.0 Cluster Control AI" \
org.opencontainers.image.description="Optional QingLong 3.0 AI-enabled cluster control plane"
COPY --from=assembled-ai --chown=10001:10001 /opt/qinglong ./
ENTRYPOINT ["node", "/opt/qinglong/node_modules/@qinglong/cluster-control/dist/aiCli.js"]
FROM runtime-base AS runtime
COPY --from=assembled --chown=10001:10001 /opt/qinglong ./
ENTRYPOINT ["node", "/opt/qinglong/node_modules/@qinglong/cluster-control/dist/cli.js"]
+764
View File
@@ -0,0 +1,764 @@
{
"name": "@qinglong/cluster-control-image-dependencies",
"version": "3.0.0-alpha.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@qinglong/cluster-control-image-dependencies",
"version": "3.0.0-alpha.0",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/client-s3": "3.1093.0",
"croner": "7.0.8",
"drizzle-orm": "0.45.2",
"pg": "8.22.0",
"semver": "7.7.4"
},
"devDependencies": {
"@types/node": "24.13.3",
"@types/pg": "8.20.0",
"typescript": "5.9.3"
},
"engines": {
"node": ">=24.18.0 <25"
}
},
"node_modules/@aws-sdk/checksums": {
"version": "3.1000.19",
"resolved": "https://registry.npmjs.org/@aws-sdk/checksums/-/checksums-3.1000.19.tgz",
"integrity": "sha512-Hc4N100RdkuWshKBnhPzmpdftfi9mCLz+OHFELHM1QIgMH4QRUUWyWgfiebta/YX2Bd62wTcm3EqAP8TeXv0gA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/client-s3": {
"version": "3.1093.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1093.0.tgz",
"integrity": "sha512-7452vEdp/nihIBWijnmcTBujXEFfbs4F02wyBDGqmNr6pwyo5GmQorx0zQIVg8QGFLXiBvsWKXBhCdiBcxNnGA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/checksums": "^3.1000.19",
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/credential-provider-node": "^3.972.71",
"@aws-sdk/middleware-sdk-s3": "^3.972.65",
"@aws-sdk/signature-v4-multi-region": "^3.996.41",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/fetch-http-handler": "^5.6.6",
"@smithy/node-http-handler": "^4.9.6",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/core": {
"version": "3.976.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.976.0.tgz",
"integrity": "sha512-0cjRaEdlVoOrsNb9pP5q1Syyc8pXw5xSj2Np2ryReRTr9FppIIRVSdZK4lbnfmc2Hvgux/xBOUU6baB7z8//uA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/types": "^3.974.2",
"@aws-sdk/xml-builder": "^3.972.36",
"@aws/lambda-invoke-store": "^0.3.0",
"@smithy/core": "^3.29.4",
"@smithy/signature-v4": "^5.6.5",
"@smithy/types": "^4.16.1",
"bowser": "^2.11.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-env": {
"version": "3.972.60",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.60.tgz",
"integrity": "sha512-BAkxdoe7tpDDqCghGpuOeHQRbm/2znVvOQm0AvpQbA2tbfMN46doN4zx65fv85ImP3KADwc2zQPmbrlI9MPfMg==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-http": {
"version": "3.972.62",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.62.tgz",
"integrity": "sha512-g/0fGqKTb9xpKdd9AtpmV5Eo3DFKbnkpA2+w0peISSlu7NfAoWOuYBFxsu+yWBtxU89ka55ezoZBCbFaS8pjYQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/fetch-http-handler": "^5.6.6",
"@smithy/node-http-handler": "^4.9.6",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-ini": {
"version": "3.973.5",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.5.tgz",
"integrity": "sha512-ylubazcRfq2TVus/qXucSXeC42Qdjp5HQxTu68K/BsdMiZlcSLD1zkpoCgApXZX1Y6YJhtGGs7ZHhO/GuIgBlw==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/credential-provider-env": "^3.972.60",
"@aws-sdk/credential-provider-http": "^3.972.62",
"@aws-sdk/credential-provider-login": "^3.972.67",
"@aws-sdk/credential-provider-process": "^3.972.60",
"@aws-sdk/credential-provider-sso": "^3.973.4",
"@aws-sdk/credential-provider-web-identity": "^3.972.66",
"@aws-sdk/nested-clients": "^3.997.34",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/credential-provider-imds": "^4.4.9",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-login": {
"version": "3.972.67",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.67.tgz",
"integrity": "sha512-CCygIKJ9YbI3n84OClSaSppkgKKHVj2TGT33c6FRORZrYNZQ1POmD+ip0FLYokiJAK7sSdc3YVkOsBm90oxWMQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/nested-clients": "^3.997.34",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-node": {
"version": "3.972.71",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.71.tgz",
"integrity": "sha512-HIg7Q2osBzajQwL+1Vkyh2E7Gim3eTNb9RHIsOxDGjW0eZg4oEKtRs5sioCnc73ilhaOm4gX2lHVF8J7+nt2rg==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/credential-provider-env": "^3.972.60",
"@aws-sdk/credential-provider-http": "^3.972.62",
"@aws-sdk/credential-provider-ini": "^3.973.5",
"@aws-sdk/credential-provider-process": "^3.972.60",
"@aws-sdk/credential-provider-sso": "^3.973.4",
"@aws-sdk/credential-provider-web-identity": "^3.972.66",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/credential-provider-imds": "^4.4.9",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-process": {
"version": "3.972.60",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.60.tgz",
"integrity": "sha512-YIo3f99hM43QdYG8hDzwGemnR/pU95b0kramqSJUTleCqaB7+HwKf7YZFHqvOgTqZTPx/mRmNIqoDRr3U0Z3Tw==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-sso": {
"version": "3.973.4",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.4.tgz",
"integrity": "sha512-BPdmL8sSBOCv4ngZ+3LHxyc3CNqDCEK37CHioCk7zGrTMY5sUtkH8q+o6qA80nn6w3/fyBPGNE7OIRlmoOxRQA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/nested-clients": "^3.997.34",
"@aws-sdk/token-providers": "3.1092.0",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-web-identity": {
"version": "3.972.66",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.66.tgz",
"integrity": "sha512-kSAziJboOmZmsR9/MTbiNjowl2BPes1bQuJpne4qAZ62ubi8fjfr/aupJSQje6udBoYxXTQbsL0e0kby2la3ng==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/nested-clients": "^3.997.34",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/middleware-sdk-s3": {
"version": "3.972.65",
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.65.tgz",
"integrity": "sha512-udwNhRfDTfCB98mAHjjgsnKQlxygB4e0X+Obne/XjJpvVsF0YCQC8ZErd/8Z6IPoLQjtiKHzwqEDbZiLrJEnOg==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/signature-v4-multi-region": "^3.996.41",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/nested-clients": {
"version": "3.997.34",
"resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.34.tgz",
"integrity": "sha512-Y9REVrSwmLM+Qy6sZJ7ofMC2S3Hr3tPP/4CzL5U1olPP7OGoF+6+Px0E49cVQBtSxJtyeLJMf0UaBErfeSahAA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/signature-v4-multi-region": "^3.996.41",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/fetch-http-handler": "^5.6.6",
"@smithy/node-http-handler": "^4.9.6",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/signature-v4-multi-region": {
"version": "3.996.41",
"resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.41.tgz",
"integrity": "sha512-QMUytg+FQMGouc8gHS00KoYih3+N6cqmVI/pQGOIo7Nr7OpQaiXjSYOuL+vsPZ1tymY4LAQ8MYcHJmws5LRxng==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/types": "^3.974.2",
"@smithy/signature-v4": "^5.6.5",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/token-providers": {
"version": "3.1092.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1092.0.tgz",
"integrity": "sha512-hBYUAr6iBLNFcsiWTgtBb0stdSw39VOUq4Sp4A5caCNf66BAZplWN4FleKrVpJx5li2YgdnK2DqoFSMWC642FQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/nested-clients": "^3.997.34",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/types": {
"version": "3.974.2",
"resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.2.tgz",
"integrity": "sha512-3W6IUtSxFbH6X7Wb7DzGCV5QiFQsd0g8bOfntpmDxQlzBoKWUMBu/JPQR0DwkE+Hpnxd6db1tXbOwdeHddG6cA==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/xml-builder": {
"version": "3.972.36",
"resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.36.tgz",
"integrity": "sha512-RdGmS1GLrtaTOLE1ElSluMldNrpk9Emq6uYs8SS8iHlu5xTAmM9rRkM91o48+rIRryBtyO9t+uLYCoMG6jVMVA==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws/lambda-invoke-store": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz",
"integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==",
"license": "Apache-2.0",
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/core": {
"version": "3.29.8",
"resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.29.8.tgz",
"integrity": "sha512-rpCbCV+TimOBi3VLNBMmtTvgfOWcFIEAru3+TFlG87SL2F+te4jOnnNR+cf3uR4eJ5Qf4LnT80fqnBKgPRS6zA==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/credential-provider-imds": {
"version": "4.4.13",
"resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.4.13.tgz",
"integrity": "sha512-X+2HNZhWi5i3rJsCas0LPf6fTQUaKyJ40zd8aTO/bwpRfpU3biYaqLr7C1WMibL7PVKJalpi1PyybjGPNoHC8Q==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/core": "^3.29.8",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/fetch-http-handler": {
"version": "5.6.10",
"resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.6.10.tgz",
"integrity": "sha512-5/Yj9mS2JjTsB3B8ZX7euh77mrY9aXW23ag1yAmFykSRmA6vldqBrgqmSeQ50EjY+5SB8+aE4w14B6LKbBVEhQ==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/core": "^3.29.8",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/node-http-handler": {
"version": "4.9.10",
"resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.9.10.tgz",
"integrity": "sha512-ETQz9v/Z+nTQc6fRWTXxUpxJqwpmzB3Tn3WKAdHwWkeT+m+HE5czs6GNG8vW+4vyxXSls65RVcvOZwk7Q/PS/Q==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/core": "^3.29.8",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/signature-v4": {
"version": "5.6.9",
"resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.6.9.tgz",
"integrity": "sha512-g5rnEii/mkT0mjVJmlsaOfyNBtHNTecD9Lo4NP8D5HzMUEnZNpz7/FbvBCjNcV4vteHFAxOGiLUYNxPkDZZAPw==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/core": "^3.29.8",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/types": {
"version": "4.16.1",
"resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.16.1.tgz",
"integrity": "sha512-0JFs3V2y2M9tKW5na/qxe69Zv+uxLMO7QBbhxF/FHu/Gp2NFZAAL9tWl9PU02xxo07pb3G9FTyjNc6D5uZrJIg==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@types/node": {
"version": "24.13.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz",
"integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.18.0"
}
},
"node_modules/@types/pg": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.20.0.tgz",
"integrity": "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==",
"devOptional": true,
"license": "MIT",
"dependencies": {
"@types/node": "*",
"pg-protocol": "*",
"pg-types": "^2.2.0"
}
},
"node_modules/bowser": {
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz",
"integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==",
"license": "MIT"
},
"node_modules/croner": {
"version": "7.0.8",
"resolved": "https://registry.npmjs.org/croner/-/croner-7.0.8.tgz",
"integrity": "sha512-4E27J9ZQV9prM9ggU18QGPYPMSblbA9JuGv4Ff3Gk6supX4RszNGQxBgiFBL6wb/L9HuSMpFbQpduMiDRo+z5Q==",
"license": "MIT",
"engines": {
"node": ">=6.0"
}
},
"node_modules/drizzle-orm": {
"version": "0.45.2",
"resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.45.2.tgz",
"integrity": "sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q==",
"license": "Apache-2.0",
"peerDependencies": {
"@aws-sdk/client-rds-data": ">=3",
"@cloudflare/workers-types": ">=4",
"@electric-sql/pglite": ">=0.2.0",
"@libsql/client": ">=0.10.0",
"@libsql/client-wasm": ">=0.10.0",
"@neondatabase/serverless": ">=0.10.0",
"@op-engineering/op-sqlite": ">=2",
"@opentelemetry/api": "^1.4.1",
"@planetscale/database": ">=1.13",
"@prisma/client": "*",
"@tidbcloud/serverless": "*",
"@types/better-sqlite3": "*",
"@types/pg": "*",
"@types/sql.js": "*",
"@upstash/redis": ">=1.34.7",
"@vercel/postgres": ">=0.8.0",
"@xata.io/client": "*",
"better-sqlite3": ">=7",
"bun-types": "*",
"expo-sqlite": ">=14.0.0",
"gel": ">=2",
"knex": "*",
"kysely": "*",
"mysql2": ">=2",
"pg": ">=8",
"postgres": ">=3",
"sql.js": ">=1",
"sqlite3": ">=5"
},
"peerDependenciesMeta": {
"@aws-sdk/client-rds-data": {
"optional": true
},
"@cloudflare/workers-types": {
"optional": true
},
"@electric-sql/pglite": {
"optional": true
},
"@libsql/client": {
"optional": true
},
"@libsql/client-wasm": {
"optional": true
},
"@neondatabase/serverless": {
"optional": true
},
"@op-engineering/op-sqlite": {
"optional": true
},
"@opentelemetry/api": {
"optional": true
},
"@planetscale/database": {
"optional": true
},
"@prisma/client": {
"optional": true
},
"@tidbcloud/serverless": {
"optional": true
},
"@types/better-sqlite3": {
"optional": true
},
"@types/pg": {
"optional": true
},
"@types/sql.js": {
"optional": true
},
"@upstash/redis": {
"optional": true
},
"@vercel/postgres": {
"optional": true
},
"@xata.io/client": {
"optional": true
},
"better-sqlite3": {
"optional": true
},
"bun-types": {
"optional": true
},
"expo-sqlite": {
"optional": true
},
"gel": {
"optional": true
},
"knex": {
"optional": true
},
"kysely": {
"optional": true
},
"mysql2": {
"optional": true
},
"pg": {
"optional": true
},
"postgres": {
"optional": true
},
"prisma": {
"optional": true
},
"sql.js": {
"optional": true
},
"sqlite3": {
"optional": true
}
}
},
"node_modules/pg": {
"version": "8.22.0",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.22.0.tgz",
"integrity": "sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA==",
"license": "MIT",
"dependencies": {
"pg-connection-string": "^2.14.0",
"pg-pool": "^3.14.0",
"pg-protocol": "^1.15.0",
"pg-types": "2.2.0",
"pgpass": "1.0.5"
},
"engines": {
"node": ">= 16.0.0"
},
"optionalDependencies": {
"pg-cloudflare": "^1.4.0"
},
"peerDependencies": {
"pg-native": ">=3.0.1"
},
"peerDependenciesMeta": {
"pg-native": {
"optional": true
}
}
},
"node_modules/pg-cloudflare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.4.0.tgz",
"integrity": "sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==",
"license": "MIT",
"optional": true
},
"node_modules/pg-connection-string": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.14.0.tgz",
"integrity": "sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg==",
"license": "MIT"
},
"node_modules/pg-int8": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
"license": "ISC",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/pg-pool": {
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.14.0.tgz",
"integrity": "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==",
"license": "MIT",
"peerDependencies": {
"pg": ">=8.0"
}
},
"node_modules/pg-protocol": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.15.0.tgz",
"integrity": "sha512-cq9sECI5s0+uPUXjbz8ioyPJni6RzsRib0US67i5IoTZKw8fNeYlVE7u8F4dG7vEJJtc5wdD1K189lCCUwqWTQ==",
"license": "MIT"
},
"node_modules/pg-types": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
"license": "MIT",
"dependencies": {
"pg-int8": "1.0.1",
"postgres-array": "~2.0.0",
"postgres-bytea": "~1.0.0",
"postgres-date": "~1.0.4",
"postgres-interval": "^1.1.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/pgpass": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
"integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
"license": "MIT",
"dependencies": {
"split2": "^4.1.0"
}
},
"node_modules/postgres-array": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/postgres-bytea": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz",
"integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/postgres-date": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/postgres-interval": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
"license": "MIT",
"dependencies": {
"xtend": "^4.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/semver": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/split2": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
"license": "ISC",
"engines": {
"node": ">= 10.x"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "7.18.2",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
"devOptional": true,
"license": "MIT"
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"license": "MIT",
"engines": {
"node": ">=0.4"
}
}
}
}
@@ -0,0 +1,22 @@
{
"name": "@qinglong/cluster-control-image-dependencies",
"version": "3.0.0-alpha.0",
"private": true,
"description": "Locked external runtime dependencies for the QingLong 3.0 cluster-control image",
"license": "Apache-2.0",
"engines": {
"node": ">=24.18.0 <25"
},
"dependencies": {
"@aws-sdk/client-s3": "3.1093.0",
"croner": "7.0.8",
"drizzle-orm": "0.45.2",
"pg": "8.22.0",
"semver": "7.7.4"
},
"devDependencies": {
"@types/node": "24.13.3",
"@types/pg": "8.20.0",
"typescript": "5.9.3"
}
}
@@ -0,0 +1,716 @@
{
"name": "@qinglong/cluster-control-image-dependencies",
"version": "3.0.0-alpha.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@qinglong/cluster-control-image-dependencies",
"version": "3.0.0-alpha.0",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/client-s3": "3.1093.0",
"croner": "7.0.8",
"drizzle-orm": "0.45.2",
"pg": "8.22.0",
"semver": "7.7.4"
},
"engines": {
"node": ">=24.18.0 <25"
}
},
"node_modules/@aws-sdk/checksums": {
"version": "3.1000.19",
"resolved": "https://registry.npmjs.org/@aws-sdk/checksums/-/checksums-3.1000.19.tgz",
"integrity": "sha512-Hc4N100RdkuWshKBnhPzmpdftfi9mCLz+OHFELHM1QIgMH4QRUUWyWgfiebta/YX2Bd62wTcm3EqAP8TeXv0gA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/client-s3": {
"version": "3.1093.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.1093.0.tgz",
"integrity": "sha512-7452vEdp/nihIBWijnmcTBujXEFfbs4F02wyBDGqmNr6pwyo5GmQorx0zQIVg8QGFLXiBvsWKXBhCdiBcxNnGA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/checksums": "^3.1000.19",
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/credential-provider-node": "^3.972.71",
"@aws-sdk/middleware-sdk-s3": "^3.972.65",
"@aws-sdk/signature-v4-multi-region": "^3.996.41",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/fetch-http-handler": "^5.6.6",
"@smithy/node-http-handler": "^4.9.6",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/core": {
"version": "3.976.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.976.0.tgz",
"integrity": "sha512-0cjRaEdlVoOrsNb9pP5q1Syyc8pXw5xSj2Np2ryReRTr9FppIIRVSdZK4lbnfmc2Hvgux/xBOUU6baB7z8//uA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/types": "^3.974.2",
"@aws-sdk/xml-builder": "^3.972.36",
"@aws/lambda-invoke-store": "^0.3.0",
"@smithy/core": "^3.29.4",
"@smithy/signature-v4": "^5.6.5",
"@smithy/types": "^4.16.1",
"bowser": "^2.11.0",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-env": {
"version": "3.972.60",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.60.tgz",
"integrity": "sha512-BAkxdoe7tpDDqCghGpuOeHQRbm/2znVvOQm0AvpQbA2tbfMN46doN4zx65fv85ImP3KADwc2zQPmbrlI9MPfMg==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-http": {
"version": "3.972.62",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.62.tgz",
"integrity": "sha512-g/0fGqKTb9xpKdd9AtpmV5Eo3DFKbnkpA2+w0peISSlu7NfAoWOuYBFxsu+yWBtxU89ka55ezoZBCbFaS8pjYQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/fetch-http-handler": "^5.6.6",
"@smithy/node-http-handler": "^4.9.6",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-ini": {
"version": "3.973.5",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.5.tgz",
"integrity": "sha512-ylubazcRfq2TVus/qXucSXeC42Qdjp5HQxTu68K/BsdMiZlcSLD1zkpoCgApXZX1Y6YJhtGGs7ZHhO/GuIgBlw==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/credential-provider-env": "^3.972.60",
"@aws-sdk/credential-provider-http": "^3.972.62",
"@aws-sdk/credential-provider-login": "^3.972.67",
"@aws-sdk/credential-provider-process": "^3.972.60",
"@aws-sdk/credential-provider-sso": "^3.973.4",
"@aws-sdk/credential-provider-web-identity": "^3.972.66",
"@aws-sdk/nested-clients": "^3.997.34",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/credential-provider-imds": "^4.4.9",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-login": {
"version": "3.972.67",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.67.tgz",
"integrity": "sha512-CCygIKJ9YbI3n84OClSaSppkgKKHVj2TGT33c6FRORZrYNZQ1POmD+ip0FLYokiJAK7sSdc3YVkOsBm90oxWMQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/nested-clients": "^3.997.34",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-node": {
"version": "3.972.71",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.71.tgz",
"integrity": "sha512-HIg7Q2osBzajQwL+1Vkyh2E7Gim3eTNb9RHIsOxDGjW0eZg4oEKtRs5sioCnc73ilhaOm4gX2lHVF8J7+nt2rg==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/credential-provider-env": "^3.972.60",
"@aws-sdk/credential-provider-http": "^3.972.62",
"@aws-sdk/credential-provider-ini": "^3.973.5",
"@aws-sdk/credential-provider-process": "^3.972.60",
"@aws-sdk/credential-provider-sso": "^3.973.4",
"@aws-sdk/credential-provider-web-identity": "^3.972.66",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/credential-provider-imds": "^4.4.9",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-process": {
"version": "3.972.60",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.60.tgz",
"integrity": "sha512-YIo3f99hM43QdYG8hDzwGemnR/pU95b0kramqSJUTleCqaB7+HwKf7YZFHqvOgTqZTPx/mRmNIqoDRr3U0Z3Tw==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-sso": {
"version": "3.973.4",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.4.tgz",
"integrity": "sha512-BPdmL8sSBOCv4ngZ+3LHxyc3CNqDCEK37CHioCk7zGrTMY5sUtkH8q+o6qA80nn6w3/fyBPGNE7OIRlmoOxRQA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/nested-clients": "^3.997.34",
"@aws-sdk/token-providers": "3.1092.0",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/credential-provider-web-identity": {
"version": "3.972.66",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.66.tgz",
"integrity": "sha512-kSAziJboOmZmsR9/MTbiNjowl2BPes1bQuJpne4qAZ62ubi8fjfr/aupJSQje6udBoYxXTQbsL0e0kby2la3ng==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/nested-clients": "^3.997.34",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/middleware-sdk-s3": {
"version": "3.972.65",
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.972.65.tgz",
"integrity": "sha512-udwNhRfDTfCB98mAHjjgsnKQlxygB4e0X+Obne/XjJpvVsF0YCQC8ZErd/8Z6IPoLQjtiKHzwqEDbZiLrJEnOg==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/signature-v4-multi-region": "^3.996.41",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/nested-clients": {
"version": "3.997.34",
"resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.34.tgz",
"integrity": "sha512-Y9REVrSwmLM+Qy6sZJ7ofMC2S3Hr3tPP/4CzL5U1olPP7OGoF+6+Px0E49cVQBtSxJtyeLJMf0UaBErfeSahAA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/signature-v4-multi-region": "^3.996.41",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/fetch-http-handler": "^5.6.6",
"@smithy/node-http-handler": "^4.9.6",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/signature-v4-multi-region": {
"version": "3.996.41",
"resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.41.tgz",
"integrity": "sha512-QMUytg+FQMGouc8gHS00KoYih3+N6cqmVI/pQGOIo7Nr7OpQaiXjSYOuL+vsPZ1tymY4LAQ8MYcHJmws5LRxng==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/types": "^3.974.2",
"@smithy/signature-v4": "^5.6.5",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/token-providers": {
"version": "3.1092.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1092.0.tgz",
"integrity": "sha512-hBYUAr6iBLNFcsiWTgtBb0stdSw39VOUq4Sp4A5caCNf66BAZplWN4FleKrVpJx5li2YgdnK2DqoFSMWC642FQ==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/core": "^3.976.0",
"@aws-sdk/nested-clients": "^3.997.34",
"@aws-sdk/types": "^3.974.2",
"@smithy/core": "^3.29.4",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/types": {
"version": "3.974.2",
"resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.2.tgz",
"integrity": "sha512-3W6IUtSxFbH6X7Wb7DzGCV5QiFQsd0g8bOfntpmDxQlzBoKWUMBu/JPQR0DwkE+Hpnxd6db1tXbOwdeHddG6cA==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws-sdk/xml-builder": {
"version": "3.972.36",
"resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.36.tgz",
"integrity": "sha512-RdGmS1GLrtaTOLE1ElSluMldNrpk9Emq6uYs8SS8iHlu5xTAmM9rRkM91o48+rIRryBtyO9t+uLYCoMG6jVMVA==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@aws/lambda-invoke-store": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz",
"integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==",
"license": "Apache-2.0",
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/core": {
"version": "3.29.8",
"resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.29.8.tgz",
"integrity": "sha512-rpCbCV+TimOBi3VLNBMmtTvgfOWcFIEAru3+TFlG87SL2F+te4jOnnNR+cf3uR4eJ5Qf4LnT80fqnBKgPRS6zA==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/credential-provider-imds": {
"version": "4.4.13",
"resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.4.13.tgz",
"integrity": "sha512-X+2HNZhWi5i3rJsCas0LPf6fTQUaKyJ40zd8aTO/bwpRfpU3biYaqLr7C1WMibL7PVKJalpi1PyybjGPNoHC8Q==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/core": "^3.29.8",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/fetch-http-handler": {
"version": "5.6.10",
"resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.6.10.tgz",
"integrity": "sha512-5/Yj9mS2JjTsB3B8ZX7euh77mrY9aXW23ag1yAmFykSRmA6vldqBrgqmSeQ50EjY+5SB8+aE4w14B6LKbBVEhQ==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/core": "^3.29.8",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/node-http-handler": {
"version": "4.9.10",
"resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.9.10.tgz",
"integrity": "sha512-ETQz9v/Z+nTQc6fRWTXxUpxJqwpmzB3Tn3WKAdHwWkeT+m+HE5czs6GNG8vW+4vyxXSls65RVcvOZwk7Q/PS/Q==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/core": "^3.29.8",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/signature-v4": {
"version": "5.6.9",
"resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.6.9.tgz",
"integrity": "sha512-g5rnEii/mkT0mjVJmlsaOfyNBtHNTecD9Lo4NP8D5HzMUEnZNpz7/FbvBCjNcV4vteHFAxOGiLUYNxPkDZZAPw==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/core": "^3.29.8",
"@smithy/types": "^4.16.1",
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@smithy/types": {
"version": "4.16.1",
"resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.16.1.tgz",
"integrity": "sha512-0JFs3V2y2M9tKW5na/qxe69Zv+uxLMO7QBbhxF/FHu/Gp2NFZAAL9tWl9PU02xxo07pb3G9FTyjNc6D5uZrJIg==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.6.2"
},
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/bowser": {
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz",
"integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==",
"license": "MIT"
},
"node_modules/croner": {
"version": "7.0.8",
"resolved": "https://registry.npmjs.org/croner/-/croner-7.0.8.tgz",
"integrity": "sha512-4E27J9ZQV9prM9ggU18QGPYPMSblbA9JuGv4Ff3Gk6supX4RszNGQxBgiFBL6wb/L9HuSMpFbQpduMiDRo+z5Q==",
"license": "MIT",
"engines": {
"node": ">=6.0"
}
},
"node_modules/drizzle-orm": {
"version": "0.45.2",
"resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-0.45.2.tgz",
"integrity": "sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q==",
"license": "Apache-2.0",
"peerDependencies": {
"@aws-sdk/client-rds-data": ">=3",
"@cloudflare/workers-types": ">=4",
"@electric-sql/pglite": ">=0.2.0",
"@libsql/client": ">=0.10.0",
"@libsql/client-wasm": ">=0.10.0",
"@neondatabase/serverless": ">=0.10.0",
"@op-engineering/op-sqlite": ">=2",
"@opentelemetry/api": "^1.4.1",
"@planetscale/database": ">=1.13",
"@prisma/client": "*",
"@tidbcloud/serverless": "*",
"@types/better-sqlite3": "*",
"@types/pg": "*",
"@types/sql.js": "*",
"@upstash/redis": ">=1.34.7",
"@vercel/postgres": ">=0.8.0",
"@xata.io/client": "*",
"better-sqlite3": ">=7",
"bun-types": "*",
"expo-sqlite": ">=14.0.0",
"gel": ">=2",
"knex": "*",
"kysely": "*",
"mysql2": ">=2",
"pg": ">=8",
"postgres": ">=3",
"sql.js": ">=1",
"sqlite3": ">=5"
},
"peerDependenciesMeta": {
"@aws-sdk/client-rds-data": {
"optional": true
},
"@cloudflare/workers-types": {
"optional": true
},
"@electric-sql/pglite": {
"optional": true
},
"@libsql/client": {
"optional": true
},
"@libsql/client-wasm": {
"optional": true
},
"@neondatabase/serverless": {
"optional": true
},
"@op-engineering/op-sqlite": {
"optional": true
},
"@opentelemetry/api": {
"optional": true
},
"@planetscale/database": {
"optional": true
},
"@prisma/client": {
"optional": true
},
"@tidbcloud/serverless": {
"optional": true
},
"@types/better-sqlite3": {
"optional": true
},
"@types/pg": {
"optional": true
},
"@types/sql.js": {
"optional": true
},
"@upstash/redis": {
"optional": true
},
"@vercel/postgres": {
"optional": true
},
"@xata.io/client": {
"optional": true
},
"better-sqlite3": {
"optional": true
},
"bun-types": {
"optional": true
},
"expo-sqlite": {
"optional": true
},
"gel": {
"optional": true
},
"knex": {
"optional": true
},
"kysely": {
"optional": true
},
"mysql2": {
"optional": true
},
"pg": {
"optional": true
},
"postgres": {
"optional": true
},
"prisma": {
"optional": true
},
"sql.js": {
"optional": true
},
"sqlite3": {
"optional": true
}
}
},
"node_modules/pg": {
"version": "8.22.0",
"resolved": "https://registry.npmjs.org/pg/-/pg-8.22.0.tgz",
"integrity": "sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA==",
"license": "MIT",
"dependencies": {
"pg-connection-string": "^2.14.0",
"pg-pool": "^3.14.0",
"pg-protocol": "^1.15.0",
"pg-types": "2.2.0",
"pgpass": "1.0.5"
},
"engines": {
"node": ">= 16.0.0"
},
"optionalDependencies": {
"pg-cloudflare": "^1.4.0"
},
"peerDependencies": {
"pg-native": ">=3.0.1"
},
"peerDependenciesMeta": {
"pg-native": {
"optional": true
}
}
},
"node_modules/pg-cloudflare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.4.0.tgz",
"integrity": "sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==",
"license": "MIT",
"optional": true
},
"node_modules/pg-connection-string": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.14.0.tgz",
"integrity": "sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg==",
"license": "MIT"
},
"node_modules/pg-int8": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
"integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
"license": "ISC",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/pg-pool": {
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.14.0.tgz",
"integrity": "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==",
"license": "MIT",
"peerDependencies": {
"pg": ">=8.0"
}
},
"node_modules/pg-protocol": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.15.0.tgz",
"integrity": "sha512-cq9sECI5s0+uPUXjbz8ioyPJni6RzsRib0US67i5IoTZKw8fNeYlVE7u8F4dG7vEJJtc5wdD1K189lCCUwqWTQ==",
"license": "MIT"
},
"node_modules/pg-types": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
"integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
"license": "MIT",
"dependencies": {
"pg-int8": "1.0.1",
"postgres-array": "~2.0.0",
"postgres-bytea": "~1.0.0",
"postgres-date": "~1.0.4",
"postgres-interval": "^1.1.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/pgpass": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
"integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
"license": "MIT",
"dependencies": {
"split2": "^4.1.0"
}
},
"node_modules/postgres-array": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
"integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/postgres-bytea": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz",
"integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/postgres-date": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
"integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/postgres-interval": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
"integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
"license": "MIT",
"dependencies": {
"xtend": "^4.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/semver": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/split2": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
"integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
"license": "ISC",
"engines": {
"node": ">= 10.x"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"license": "MIT",
"engines": {
"node": ">=0.4"
}
}
}
}
@@ -0,0 +1,17 @@
{
"name": "@qinglong/cluster-control-image-dependencies",
"version": "3.0.0-alpha.0",
"private": true,
"description": "Production-only external dependency root for the QingLong 3.0 cluster-control image",
"license": "Apache-2.0",
"engines": {
"node": ">=24.18.0 <25"
},
"dependencies": {
"@aws-sdk/client-s3": "3.1093.0",
"croner": "7.0.8",
"drizzle-orm": "0.45.2",
"pg": "8.22.0",
"semver": "7.7.4"
}
}
@@ -0,0 +1,12 @@
{
"extends": "../../../packages/ql3-cluster-control/tsconfig.json",
"compilerOptions": {
"rootDir": "../../../packages/ql3-cluster-control/src",
"outDir": "../../../.ql3-image-build/cluster-control-default-dist"
},
"include": ["../../../packages/ql3-cluster-control/src/**/*.ts"],
"exclude": [
"../../../packages/ql3-cluster-control/src/aiCli.ts",
"../../../packages/ql3-cluster-control/src/application-runtime/aiProductionApplication.ts"
]
}
@@ -0,0 +1,159 @@
FROM node:24.18.0-bookworm-slim@sha256:6f7b03f7c2c8e2e784dcf9295400527b9b1270fd37b7e9a7285cf83b6951452d AS dependency-manifest
WORKDIR /opt/qinglong
COPY deploy/containers/ql3-local-application/package.json ./
COPY deploy/containers/ql3-local-application/package-lock.json ./
FROM dependency-manifest AS build-dependencies
RUN npm ci --ignore-scripts --no-audit --no-fund \
&& npm cache clean --force
FROM dependency-manifest AS runtime-dependency-manifest
COPY deploy/containers/ql3-local-application/runtime-dependencies/package.json \
package.json
COPY deploy/containers/ql3-local-application/runtime-dependencies/package-lock.json \
package-lock.json
FROM build-dependencies AS workspace
WORKDIR /workspace
COPY packages/ql3-ai packages/ql3-ai
COPY packages/ql3-local-admin packages/ql3-local-admin
COPY packages/ql3-local-application packages/ql3-local-application
COPY packages/ql3-local-command-file packages/ql3-local-command-file
COPY packages/ql3-local-execution packages/ql3-local-execution
COPY packages/ql3-local-process packages/ql3-local-process
COPY packages/ql3-local-secret packages/ql3-local-secret
COPY packages/ql3-local-sqlite packages/ql3-local-sqlite
COPY packages/ql3-runtime-core packages/ql3-runtime-core
RUN ln -s /opt/qinglong/node_modules node_modules \
&& mkdir -p /opt/qinglong/node_modules/@qinglong \
&& ln -s /workspace/packages/ql3-ai \
/opt/qinglong/node_modules/@qinglong/ai \
&& ln -s /workspace/packages/ql3-local-admin \
/opt/qinglong/node_modules/@qinglong/local-admin \
&& ln -s /workspace/packages/ql3-local-application \
/opt/qinglong/node_modules/@qinglong/local-application \
&& ln -s /workspace/packages/ql3-local-command-file \
/opt/qinglong/node_modules/@qinglong/local-command-file \
&& ln -s /workspace/packages/ql3-local-execution \
/opt/qinglong/node_modules/@qinglong/local-execution \
&& ln -s /workspace/packages/ql3-local-process \
/opt/qinglong/node_modules/@qinglong/local-process \
&& ln -s /workspace/packages/ql3-local-secret \
/opt/qinglong/node_modules/@qinglong/local-secret \
&& ln -s /workspace/packages/ql3-local-sqlite \
/opt/qinglong/node_modules/@qinglong/local-sqlite \
&& ln -s /workspace/packages/ql3-runtime-core \
/opt/qinglong/node_modules/@qinglong/runtime-core \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-runtime-core/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-ai/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-local-command-file/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-local-sqlite/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-local-admin/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-local-process/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-local-execution/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-local-secret/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-local-application/tsconfig.json
FROM runtime-dependency-manifest AS external-dependencies
RUN npm ci --omit=dev --ignore-scripts --no-audit --no-fund \
&& npm cache clean --force
FROM external-dependencies AS assembled
COPY scripts/ql3-prune-runtime-artifact.cjs /tmp/ql3-prune-runtime-artifact.cjs
RUN mkdir -p \
node_modules/@qinglong/runtime-core \
node_modules/@qinglong/local-admin \
node_modules/@qinglong/local-application \
node_modules/@qinglong/local-command-file \
node_modules/@qinglong/local-execution \
node_modules/@qinglong/local-process \
node_modules/@qinglong/local-secret \
node_modules/@qinglong/local-sqlite
COPY --from=workspace /workspace/packages/ql3-runtime-core/package.json \
node_modules/@qinglong/runtime-core/package.json
COPY --from=workspace /workspace/packages/ql3-runtime-core/dist \
node_modules/@qinglong/runtime-core/dist
COPY --from=workspace /workspace/packages/ql3-local-admin/package.json \
node_modules/@qinglong/local-admin/package.json
COPY --from=workspace /workspace/packages/ql3-local-admin/dist \
node_modules/@qinglong/local-admin/dist
COPY --from=workspace /workspace/packages/ql3-local-application/package.json \
node_modules/@qinglong/local-application/package.json
COPY --from=workspace /workspace/packages/ql3-local-application/dist \
node_modules/@qinglong/local-application/dist
COPY --from=workspace /workspace/packages/ql3-local-command-file/package.json \
node_modules/@qinglong/local-command-file/package.json
COPY --from=workspace /workspace/packages/ql3-local-command-file/dist \
node_modules/@qinglong/local-command-file/dist
COPY --from=workspace /workspace/packages/ql3-local-execution/package.json \
node_modules/@qinglong/local-execution/package.json
COPY --from=workspace /workspace/packages/ql3-local-execution/dist \
node_modules/@qinglong/local-execution/dist
COPY --from=workspace /workspace/packages/ql3-local-process/package.json \
node_modules/@qinglong/local-process/package.json
COPY --from=workspace /workspace/packages/ql3-local-process/dist \
node_modules/@qinglong/local-process/dist
COPY --from=workspace /workspace/packages/ql3-local-secret/package.json \
node_modules/@qinglong/local-secret/package.json
COPY --from=workspace /workspace/packages/ql3-local-secret/dist \
node_modules/@qinglong/local-secret/dist
COPY --from=workspace /workspace/packages/ql3-local-sqlite/package.json \
node_modules/@qinglong/local-sqlite/package.json
COPY --from=workspace /workspace/packages/ql3-local-sqlite/dist \
node_modules/@qinglong/local-sqlite/dist
RUN rm -rf node_modules/.bin \
&& node /tmp/ql3-prune-runtime-artifact.cjs node_modules/@qinglong \
@qinglong/local-application \
@qinglong/local-application/process \
@qinglong/local-application/plugin-package-recovery-catalog \
--exclude=@qinglong/ai \
&& rm /tmp/ql3-prune-runtime-artifact.cjs
FROM node:24.18.0-bookworm-slim@sha256:6f7b03f7c2c8e2e784dcf9295400527b9b1270fd37b7e9a7285cf83b6951452d AS runtime
ARG SOURCE_REVISION=uncommitted
LABEL org.opencontainers.image.title="QingLong 3.0 Local Application" \
org.opencontainers.image.description="QingLong 3.0 AI-excluded Edge and Standalone runtime" \
org.opencontainers.image.source="https://github.com/whyour/qinglong" \
org.opencontainers.image.revision="${SOURCE_REVISION}" \
org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.version="3.0.0-alpha.0" \
io.qinglong.profile="edge,standalone" \
io.qinglong.ai="excluded" \
io.qinglong.local.application-config="2" \
io.qinglong.local.sqlite-contract-min="43" \
io.qinglong.local.sqlite-contract-max="43" \
io.qinglong.local.sqlite-write-contract="43" \
io.qinglong.local.compose-selection="1"
ENV NODE_ENV=production
WORKDIR /opt/qinglong
COPY --from=assembled --chown=65532:65532 /opt/qinglong ./
USER 65532:65532
ENTRYPOINT ["node", "/opt/qinglong/node_modules/@qinglong/local-application/dist/cli.js"]
+275
View File
@@ -0,0 +1,275 @@
{
"name": "@qinglong/local-application-image",
"version": "3.0.0-alpha.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@qinglong/local-application-image",
"version": "3.0.0-alpha.0",
"license": "Apache-2.0",
"dependencies": {
"croner": "7.0.8",
"drizzle-orm": "1.0.0-rc.4",
"semver": "7.7.4"
},
"devDependencies": {
"@types/node": "24.13.3",
"typescript": "5.9.3"
},
"engines": {
"node": ">=24.18.0 <25"
}
},
"node_modules/@types/node": {
"version": "24.13.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz",
"integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.18.0"
}
},
"node_modules/croner": {
"version": "7.0.8",
"resolved": "https://registry.npmjs.org/croner/-/croner-7.0.8.tgz",
"integrity": "sha512-4E27J9ZQV9prM9ggU18QGPYPMSblbA9JuGv4Ff3Gk6supX4RszNGQxBgiFBL6wb/L9HuSMpFbQpduMiDRo+z5Q==",
"license": "MIT",
"engines": {
"node": ">=6.0"
}
},
"node_modules/drizzle-orm": {
"version": "1.0.0-rc.4",
"resolved": "https://registry.npmjs.org/drizzle-orm/-/drizzle-orm-1.0.0-rc.4.tgz",
"integrity": "sha512-BT+pf+qoiYHqltoA88Jmf6ilGMXPlpfE0hEJKc2adRtMCAl25Swk/t5gXcWxZNAwdtf3F5gCd2FpeOyP/pT0Hw==",
"license": "Apache-2.0",
"peerDependencies": {
"@aws-sdk/client-rds-data": ">=3",
"@cloudflare/workers-types": ">=4",
"@effect/sql-d1": ">=4.0.0-beta.83 || >=4.0.0",
"@effect/sql-libsql": ">=4.0.0-beta.83 || >=4.0.0",
"@effect/sql-mysql2": ">=4.0.0-beta.83 || >=4.0.0",
"@effect/sql-pg": ">=4.0.0-beta.83 || >=4.0.0",
"@effect/sql-pglite": ">=4.0.0-beta.83 || >=4.0.0",
"@effect/sql-sqlite-bun": ">=4.0.0-beta.83 || >=4.0.0",
"@effect/sql-sqlite-do": ">=4.0.0-beta.83 || >=4.0.0",
"@effect/sql-sqlite-node": ">=4.0.0-beta.83 || >=4.0.0",
"@effect/sql-sqlite-wasm": ">=4.0.0-beta.83 || >=4.0.0",
"@electric-sql/pglite": ">=0.2.0",
"@libsql/client": ">=0.10.0",
"@libsql/client-wasm": ">=0.10.0",
"@neondatabase/serverless": ">=0.10.0",
"@op-engineering/op-sqlite": ">=2",
"@opentelemetry/api": "^1.4.1",
"@planetscale/database": ">=1.13",
"@sinclair/typebox": ">=0.34.8",
"@sqlitecloud/drivers": ">=1.0.653",
"@tidbcloud/serverless": "*",
"@tursodatabase/database": ">=0.6.0-pre.28 || >=0.6.0",
"@tursodatabase/database-common": ">=0.6.0-pre.28 || >=0.6.0",
"@tursodatabase/database-wasm": ">=0.6.0-pre.28 || >=0.6.0",
"@tursodatabase/serverless": ">=1.1.3",
"@tursodatabase/sync": ">=0.6.0-pre.28 || >=0.6.0",
"@types/better-sqlite3": "*",
"@types/mssql": "^9.1.4",
"@types/pg": "*",
"@types/sql.js": "*",
"@upstash/redis": ">=1.34.7",
"@vercel/postgres": ">=0.8.0",
"@xata.io/client": "*",
"arktype": ">=2.0.0",
"better-sqlite3": ">=9.3.0",
"bun-types": "*",
"effect": ">=4.0.0-beta.83 || >=4.0.0",
"expo-sqlite": ">=14.0.0",
"mssql": "^11.0.1",
"mysql2": ">=2",
"pg": ">=8",
"postgres": ">=3",
"sql.js": ">=1",
"sqlite3": ">=5",
"typebox": ">=1.0.0",
"valibot": ">=1.0.0-beta.7",
"zod": "^3.25.0 || ^4.0.0"
},
"peerDependenciesMeta": {
"@aws-sdk/client-rds-data": {
"optional": true
},
"@cloudflare/workers-types": {
"optional": true
},
"@effect/sql-d1": {
"optional": true
},
"@effect/sql-libsql": {
"optional": true
},
"@effect/sql-mysql2": {
"optional": true
},
"@effect/sql-pg": {
"optional": true
},
"@effect/sql-pglite": {
"optional": true
},
"@effect/sql-sqlite-bun": {
"optional": true
},
"@effect/sql-sqlite-do": {
"optional": true
},
"@effect/sql-sqlite-node": {
"optional": true
},
"@effect/sql-sqlite-wasm": {
"optional": true
},
"@electric-sql/pglite": {
"optional": true
},
"@libsql/client": {
"optional": true
},
"@libsql/client-wasm": {
"optional": true
},
"@neondatabase/serverless": {
"optional": true
},
"@op-engineering/op-sqlite": {
"optional": true
},
"@opentelemetry/api": {
"optional": true
},
"@planetscale/database": {
"optional": true
},
"@sinclair/typebox": {
"optional": true
},
"@sqlitecloud/drivers": {
"optional": true
},
"@tidbcloud/serverless": {
"optional": true
},
"@tursodatabase/database": {
"optional": true
},
"@tursodatabase/database-common": {
"optional": true
},
"@tursodatabase/database-wasm": {
"optional": true
},
"@tursodatabase/serverless": {
"optional": true
},
"@tursodatabase/sync": {
"optional": true
},
"@types/better-sqlite3": {
"optional": true
},
"@types/mssql": {
"optional": true
},
"@types/pg": {
"optional": true
},
"@types/sql.js": {
"optional": true
},
"@upstash/redis": {
"optional": true
},
"@vercel/postgres": {
"optional": true
},
"@xata.io/client": {
"optional": true
},
"arktype": {
"optional": true
},
"better-sqlite3": {
"optional": true
},
"bun-types": {
"optional": true
},
"effect": {
"optional": true
},
"expo-sqlite": {
"optional": true
},
"mssql": {
"optional": true
},
"mysql2": {
"optional": true
},
"pg": {
"optional": true
},
"postgres": {
"optional": true
},
"sql.js": {
"optional": true
},
"sqlite3": {
"optional": true
},
"typebox": {
"optional": true
},
"valibot": {
"optional": true
},
"zod": {
"optional": true
}
}
},
"node_modules/semver": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "7.18.2",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
"dev": true,
"license": "MIT"
}
}
}
@@ -0,0 +1,19 @@
{
"name": "@qinglong/local-application-image",
"version": "3.0.0-alpha.0",
"private": true,
"description": "Locked build dependencies for the QingLong 3.0 AI-excluded local application image",
"license": "Apache-2.0",
"engines": {
"node": ">=24.18.0 <25"
},
"dependencies": {
"croner": "7.0.8",
"drizzle-orm": "1.0.0-rc.4",
"semver": "7.7.4"
},
"devDependencies": {
"@types/node": "24.13.3",
"typescript": "5.9.3"
}
}
@@ -0,0 +1,41 @@
{
"name": "@qinglong/local-application-image",
"version": "3.0.0-alpha.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@qinglong/local-application-image",
"version": "3.0.0-alpha.0",
"license": "Apache-2.0",
"dependencies": {
"croner": "7.0.8",
"semver": "7.7.4"
},
"engines": {
"node": ">=24.18.0 <25"
}
},
"node_modules/croner": {
"version": "7.0.8",
"resolved": "https://registry.npmjs.org/croner/-/croner-7.0.8.tgz",
"integrity": "sha512-4E27J9ZQV9prM9ggU18QGPYPMSblbA9JuGv4Ff3Gk6supX4RszNGQxBgiFBL6wb/L9HuSMpFbQpduMiDRo+z5Q==",
"license": "MIT",
"engines": {
"node": ">=6.0"
}
},
"node_modules/semver": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
}
}
}
@@ -0,0 +1,14 @@
{
"name": "@qinglong/local-application-image",
"version": "3.0.0-alpha.0",
"private": true,
"description": "Production-only external dependency root for the QingLong 3.0 AI-excluded local application image",
"license": "Apache-2.0",
"engines": {
"node": ">=24.18.0 <25"
},
"dependencies": {
"croner": "7.0.8",
"semver": "7.7.4"
}
}
@@ -0,0 +1,5 @@
{
"schemaVersion": 1,
"fixture": "qinglong/image-os-vulnerability-exceptions@v1",
"exceptions": []
}
@@ -0,0 +1,8 @@
FROM node:24-alpine
RUN apk add --no-cache openrc \
&& addgroup -g 10001 -S ql3service \
&& adduser -u 10001 -S -D -H -G ql3service -s /sbin/nologin ql3service \
&& mkdir -p /run/openrc
ENTRYPOINT ["node", "-e", "const fs=require('node:fs');fs.mkdirSync('/run/openrc',{recursive:true});fs.writeFileSync('/run/openrc/softlevel','default\\n');setInterval(()=>{},2147483647)"]
@@ -0,0 +1,13 @@
FROM node:24-bookworm-slim
RUN apt-get update \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends systemd \
&& groupadd --gid 10001 ql3service \
&& useradd --uid 10001 --gid 10001 --no-create-home --shell /usr/sbin/nologin ql3service \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& systemctl mask systemd-remount-fs.service getty@.service console-getty.service
STOPSIGNAL SIGRTMIN+3
ENTRYPOINT ["/lib/systemd/systemd"]
CMD []
+96
View File
@@ -0,0 +1,96 @@
FROM node:24.18.0-bookworm-slim@sha256:6f7b03f7c2c8e2e784dcf9295400527b9b1270fd37b7e9a7285cf83b6951452d AS dependency-manifest
WORKDIR /opt/qinglong
COPY deploy/containers/ql3-worker/package.json ./
COPY deploy/containers/ql3-worker/package-lock.json ./
FROM dependency-manifest AS build-dependencies
RUN npm ci --ignore-scripts --no-audit --no-fund \
&& npm cache clean --force
FROM dependency-manifest AS runtime-dependency-manifest
COPY deploy/containers/ql3-worker/runtime-dependencies/package.json \
package.json
COPY deploy/containers/ql3-worker/runtime-dependencies/package-lock.json \
package-lock.json
FROM build-dependencies AS workspace
WORKDIR /workspace
COPY packages/ql3-runtime-core packages/ql3-runtime-core
COPY packages/ql3-local-process packages/ql3-local-process
COPY packages/ql3-worker-runtime packages/ql3-worker-runtime
RUN ln -s /opt/qinglong/node_modules node_modules \
&& mkdir -p /opt/qinglong/node_modules/@qinglong \
&& ln -s /workspace/packages/ql3-runtime-core \
/opt/qinglong/node_modules/@qinglong/runtime-core \
&& ln -s /workspace/packages/ql3-local-process \
/opt/qinglong/node_modules/@qinglong/local-process \
&& ln -s /workspace/packages/ql3-worker-runtime \
/opt/qinglong/node_modules/@qinglong/worker-runtime \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-runtime-core/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-local-process/tsconfig.json \
&& /opt/qinglong/node_modules/.bin/tsc \
-p packages/ql3-worker-runtime/tsconfig.json
FROM runtime-dependency-manifest AS external-dependencies
RUN npm ci --omit=dev --ignore-scripts --no-audit --no-fund \
&& npm cache clean --force
FROM external-dependencies AS assembled
RUN mkdir -p \
node_modules/@qinglong/runtime-core \
node_modules/@qinglong/local-process \
node_modules/@qinglong/worker-runtime
COPY --from=workspace /workspace/packages/ql3-runtime-core/package.json \
node_modules/@qinglong/runtime-core/package.json
COPY --from=workspace /workspace/packages/ql3-runtime-core/dist \
node_modules/@qinglong/runtime-core/dist
COPY --from=workspace /workspace/packages/ql3-local-process/package.json \
node_modules/@qinglong/local-process/package.json
COPY --from=workspace /workspace/packages/ql3-local-process/dist \
node_modules/@qinglong/local-process/dist
COPY --from=workspace /workspace/packages/ql3-local-process/assets \
node_modules/@qinglong/local-process/assets
COPY --from=workspace /workspace/packages/ql3-worker-runtime/package.json \
node_modules/@qinglong/worker-runtime/package.json
COPY --from=workspace /workspace/packages/ql3-worker-runtime/dist \
node_modules/@qinglong/worker-runtime/dist
RUN chmod 0555 \
node_modules/@qinglong/local-process/assets/ql3-launcher.sh \
&& rm -rf node_modules/.bin \
&& find node_modules/@qinglong -type f -name '*.map' -delete
FROM node:24.18.0-bookworm-slim@sha256:6f7b03f7c2c8e2e784dcf9295400527b9b1270fd37b7e9a7285cf83b6951452d AS runtime
ARG SOURCE_REVISION=uncommitted
LABEL org.opencontainers.image.title="QingLong 3.0 Worker" \
org.opencontainers.image.description="QingLong 3.0 headless Remote Worker runtime" \
org.opencontainers.image.source="https://github.com/whyour/qinglong" \
org.opencontainers.image.revision="${SOURCE_REVISION}" \
org.opencontainers.image.licenses="Apache-2.0" \
org.opencontainers.image.version="3.0.0-alpha.0" \
io.qinglong.profile="worker" \
io.qinglong.worker.capacity-profiles="edge,node"
ENV NODE_ENV=production
WORKDIR /opt/qinglong
COPY --from=assembled --chown=65532:65532 /opt/qinglong ./
USER 65532:65532
ENTRYPOINT ["node", "/opt/qinglong/node_modules/@qinglong/worker-runtime/dist/process/workerProcessCli.js"]
+341
View File
@@ -0,0 +1,341 @@
{
"name": "@qinglong/worker-image-dependencies",
"version": "3.0.0-alpha.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@qinglong/worker-image-dependencies",
"version": "3.0.0-alpha.0",
"license": "Apache-2.0",
"dependencies": {
"@peculiar/x509": "2.0.0",
"proper-lockfile": "4.1.2",
"reflect-metadata": "0.2.2",
"semver": "7.7.4"
},
"devDependencies": {
"@types/node": "24.13.3",
"@types/proper-lockfile": "4.1.4",
"typescript": "5.9.3"
},
"engines": {
"node": ">=24.18.0 <25"
}
},
"node_modules/@peculiar/x509": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-2.0.0.tgz",
"integrity": "sha512-r10lkuy6BNfRmyYdRAfgu6dq0HOmyIV2OLhXWE3gDEPBdX1b8miztJVyX/UxWhLwemNyDP3CLZHpDxDwSY0xaA==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-cms": "^2.6.0",
"@peculiar/asn1-csr": "^2.6.0",
"@peculiar/asn1-ecc": "^2.6.0",
"@peculiar/asn1-pkcs9": "^2.6.0",
"@peculiar/asn1-rsa": "^2.6.0",
"@peculiar/asn1-schema": "^2.6.0",
"@peculiar/asn1-x509": "^2.6.0",
"pvtsutils": "^1.3.6",
"tslib": "^2.8.1",
"tsyringe": "^4.10.0"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@peculiar/asn1-cms": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.8.0.tgz",
"integrity": "sha512-NgekZOrSJFSBFLFoLfwePguAWAx7z1+f2TEsWFUMyiqqfntZ4+S/S5hzqME3q4pCA0iOsFKdwiQ35dwY24eVqA==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/asn1-x509": "^2.8.0",
"@peculiar/asn1-x509-attr": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-schema": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.8.0.tgz",
"integrity": "sha512-7YT0U/ze0tF2QOBbE15gKZwy5tvgGyLRiRHLzhlbOpf7BT032oBSd0haZqXn5W6l26WLlu3dyxzjM+2638/z2Q==",
"license": "MIT",
"dependencies": {
"@peculiar/utils": "^2.0.2",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/utils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@peculiar/utils/-/utils-2.0.3.tgz",
"integrity": "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==",
"license": "MIT",
"dependencies": {
"tslib": "^2.8.1"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/asn1js": {
"version": "3.0.10",
"resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz",
"integrity": "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==",
"license": "BSD-3-Clause",
"dependencies": {
"pvtsutils": "^1.3.6",
"pvutils": "^1.1.5",
"tslib": "^2.8.1"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/pvtsutils": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz",
"integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==",
"license": "MIT",
"dependencies": {
"tslib": "^2.8.1"
}
},
"node_modules/pvutils": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz",
"integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==",
"license": "MIT",
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@peculiar/asn1-x509": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.8.0.tgz",
"integrity": "sha512-N0CMuhWUzsWEVq6F1q9X6+VKUnWzSW+cSVg+aPaGGwDdbFoFWTYgin5MHwXgpWd6y9COMBxnfy/Qc+Xc7F0Zwg==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/utils": "^2.0.2",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-x509-attr": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.8.0.tgz",
"integrity": "sha512-tHjkfS/qhMnmrlB2J9NhflQlQ7In3khO3CfmVrriOlpTeErY9ZIKOso1hQ5JQiyrJ7ShvqVPk7E5fQmbclkSKA==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/asn1-x509": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-csr": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.8.0.tgz",
"integrity": "sha512-akbF8+uvleHs8sejNPQxwmVFuInAg6FMNHOwMILXfP518YfFJwdR3jr6oNUPOaEJfuEhn/vkNOCIT6ASUd4mbg==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/asn1-x509": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-ecc": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.8.0.tgz",
"integrity": "sha512-ohwlk+u9Rv2NOAY1c6MfHj45ATVF8R1DUN/WCgABiRtLi2ZftlZWZX7KvpAbU8v9xPcmoILfELeEABj/rn18AQ==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/asn1-x509": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-pkcs9": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.8.0.tgz",
"integrity": "sha512-b5nDWCnkV60+cQ141D6sVVwK9nz64R5n3zSVnklGd+ECdkW2Ol3U1a6yYFlalpSOaD557yuJB64A+q42jG7lUQ==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-cms": "^2.8.0",
"@peculiar/asn1-pfx": "^2.8.0",
"@peculiar/asn1-pkcs8": "^2.8.0",
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/asn1-x509": "^2.8.0",
"@peculiar/asn1-x509-attr": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-pfx": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.8.0.tgz",
"integrity": "sha512-5yof1ytoB++RQtaFbqSUJ8pxDJtZT6vbVqZ8XoJ61ph7UjNVvfFwAilnCodqkNsAodpy13gDhoxZXw00pghnyg==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-cms": "^2.8.0",
"@peculiar/asn1-pkcs8": "^2.8.0",
"@peculiar/asn1-rsa": "^2.8.0",
"@peculiar/asn1-schema": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-pkcs8": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.8.0.tgz",
"integrity": "sha512-qAKXtLpBEw9LqhKpjw3ajZSXlBur+ipW+y2ivVBQAG6F6qRx94yO+1ZR4mvw+YaCfKSaOzLeYEzsPaBp4SJELA==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/asn1-x509": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-rsa": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.8.0.tgz",
"integrity": "sha512-zHEUlCqB2mk7x2lxDwHHJy7hWZOPdGHVlsmITWKB5/PbQo61atbu9PJ/0r9dQNMwFzbKPXZ8uK8/91eUhRznSg==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/asn1-x509": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/tsyringe": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz",
"integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==",
"license": "MIT",
"dependencies": {
"tslib": "^1.9.3"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/tsyringe/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"license": "0BSD"
},
"node_modules/proper-lockfile": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz",
"integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==",
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.4",
"retry": "^0.12.0",
"signal-exit": "^3.0.2"
}
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"license": "ISC"
},
"node_modules/retry": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
"integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
"license": "MIT",
"dependencies": {},
"engines": {
"node": ">= 4"
}
},
"node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"license": "ISC"
},
"node_modules/reflect-metadata": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
"integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
"license": "Apache-2.0",
"dependencies": {}
},
"node_modules/semver": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"license": "ISC",
"engines": {
"node": ">=10"
},
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/@types/node": {
"version": "24.13.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz",
"integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.18.0"
},
"peerDependencies": {}
},
"node_modules/undici-types": {
"version": "7.18.2",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
"integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/proper-lockfile": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/@types/proper-lockfile/-/proper-lockfile-4.1.4.tgz",
"integrity": "sha512-uo2ABllncSqg9F1D4nugVl9v93RmjxF6LJzQLMLDdPaXCUIDPeOJ21Gbqi43xNKzBi/WQ0Q0dICqufzQbMjipQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/retry": "*"
}
},
"node_modules/@types/retry": {
"version": "0.12.5",
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.5.tgz",
"integrity": "sha512-3xSjTp3v03X/lSQLkczaN9UIEwJMoMCA1+Nb5HfbJEQWogdeQIyVtTvxPXDQjZ5zws8rFQfVfRdz03ARihPJgw==",
"dev": true,
"license": "MIT",
"dependencies": {}
},
"node_modules/typescript": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=14.17"
},
"bin": {
"tsc": "./bin/tsc",
"tsserver": "./bin/tsserver"
}
}
}
}
+21
View File
@@ -0,0 +1,21 @@
{
"name": "@qinglong/worker-image-dependencies",
"version": "3.0.0-alpha.0",
"private": true,
"description": "Locked external build and runtime dependencies for the QingLong 3.0 Worker image",
"license": "Apache-2.0",
"engines": {
"node": ">=24.18.0 <25"
},
"dependencies": {
"@peculiar/x509": "2.0.0",
"proper-lockfile": "4.1.2",
"reflect-metadata": "0.2.2",
"semver": "7.7.4"
},
"devDependencies": {
"@types/node": "24.13.3",
"@types/proper-lockfile": "4.1.4",
"typescript": "5.9.3"
}
}
@@ -0,0 +1,286 @@
{
"name": "@qinglong/worker-image-dependencies",
"version": "3.0.0-alpha.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@qinglong/worker-image-dependencies",
"version": "3.0.0-alpha.0",
"license": "Apache-2.0",
"dependencies": {
"@peculiar/x509": "2.0.0",
"proper-lockfile": "4.1.2",
"reflect-metadata": "0.2.2",
"semver": "7.7.4"
},
"engines": {
"node": ">=24.18.0 <25"
}
},
"node_modules/@peculiar/x509": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-2.0.0.tgz",
"integrity": "sha512-r10lkuy6BNfRmyYdRAfgu6dq0HOmyIV2OLhXWE3gDEPBdX1b8miztJVyX/UxWhLwemNyDP3CLZHpDxDwSY0xaA==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-cms": "^2.6.0",
"@peculiar/asn1-csr": "^2.6.0",
"@peculiar/asn1-ecc": "^2.6.0",
"@peculiar/asn1-pkcs9": "^2.6.0",
"@peculiar/asn1-rsa": "^2.6.0",
"@peculiar/asn1-schema": "^2.6.0",
"@peculiar/asn1-x509": "^2.6.0",
"pvtsutils": "^1.3.6",
"tslib": "^2.8.1",
"tsyringe": "^4.10.0"
},
"engines": {
"node": ">=20.0.0"
}
},
"node_modules/@peculiar/asn1-cms": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.8.0.tgz",
"integrity": "sha512-NgekZOrSJFSBFLFoLfwePguAWAx7z1+f2TEsWFUMyiqqfntZ4+S/S5hzqME3q4pCA0iOsFKdwiQ35dwY24eVqA==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/asn1-x509": "^2.8.0",
"@peculiar/asn1-x509-attr": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-schema": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.8.0.tgz",
"integrity": "sha512-7YT0U/ze0tF2QOBbE15gKZwy5tvgGyLRiRHLzhlbOpf7BT032oBSd0haZqXn5W6l26WLlu3dyxzjM+2638/z2Q==",
"license": "MIT",
"dependencies": {
"@peculiar/utils": "^2.0.2",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/utils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@peculiar/utils/-/utils-2.0.3.tgz",
"integrity": "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==",
"license": "MIT",
"dependencies": {
"tslib": "^2.8.1"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
"license": "0BSD"
},
"node_modules/asn1js": {
"version": "3.0.10",
"resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz",
"integrity": "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==",
"license": "BSD-3-Clause",
"dependencies": {
"pvtsutils": "^1.3.6",
"pvutils": "^1.1.5",
"tslib": "^2.8.1"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/pvtsutils": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz",
"integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==",
"license": "MIT",
"dependencies": {
"tslib": "^2.8.1"
}
},
"node_modules/pvutils": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz",
"integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==",
"license": "MIT",
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@peculiar/asn1-x509": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.8.0.tgz",
"integrity": "sha512-N0CMuhWUzsWEVq6F1q9X6+VKUnWzSW+cSVg+aPaGGwDdbFoFWTYgin5MHwXgpWd6y9COMBxnfy/Qc+Xc7F0Zwg==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/utils": "^2.0.2",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-x509-attr": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.8.0.tgz",
"integrity": "sha512-tHjkfS/qhMnmrlB2J9NhflQlQ7In3khO3CfmVrriOlpTeErY9ZIKOso1hQ5JQiyrJ7ShvqVPk7E5fQmbclkSKA==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/asn1-x509": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-csr": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.8.0.tgz",
"integrity": "sha512-akbF8+uvleHs8sejNPQxwmVFuInAg6FMNHOwMILXfP518YfFJwdR3jr6oNUPOaEJfuEhn/vkNOCIT6ASUd4mbg==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/asn1-x509": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-ecc": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.8.0.tgz",
"integrity": "sha512-ohwlk+u9Rv2NOAY1c6MfHj45ATVF8R1DUN/WCgABiRtLi2ZftlZWZX7KvpAbU8v9xPcmoILfELeEABj/rn18AQ==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/asn1-x509": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-pkcs9": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.8.0.tgz",
"integrity": "sha512-b5nDWCnkV60+cQ141D6sVVwK9nz64R5n3zSVnklGd+ECdkW2Ol3U1a6yYFlalpSOaD557yuJB64A+q42jG7lUQ==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-cms": "^2.8.0",
"@peculiar/asn1-pfx": "^2.8.0",
"@peculiar/asn1-pkcs8": "^2.8.0",
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/asn1-x509": "^2.8.0",
"@peculiar/asn1-x509-attr": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-pfx": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.8.0.tgz",
"integrity": "sha512-5yof1ytoB++RQtaFbqSUJ8pxDJtZT6vbVqZ8XoJ61ph7UjNVvfFwAilnCodqkNsAodpy13gDhoxZXw00pghnyg==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-cms": "^2.8.0",
"@peculiar/asn1-pkcs8": "^2.8.0",
"@peculiar/asn1-rsa": "^2.8.0",
"@peculiar/asn1-schema": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-pkcs8": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.8.0.tgz",
"integrity": "sha512-qAKXtLpBEw9LqhKpjw3ajZSXlBur+ipW+y2ivVBQAG6F6qRx94yO+1ZR4mvw+YaCfKSaOzLeYEzsPaBp4SJELA==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/asn1-x509": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/@peculiar/asn1-rsa": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.8.0.tgz",
"integrity": "sha512-zHEUlCqB2mk7x2lxDwHHJy7hWZOPdGHVlsmITWKB5/PbQo61atbu9PJ/0r9dQNMwFzbKPXZ8uK8/91eUhRznSg==",
"license": "MIT",
"dependencies": {
"@peculiar/asn1-schema": "^2.8.0",
"@peculiar/asn1-x509": "^2.8.0",
"asn1js": "^3.0.10",
"tslib": "^2.8.1"
}
},
"node_modules/tsyringe": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz",
"integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==",
"license": "MIT",
"dependencies": {
"tslib": "^1.9.3"
},
"engines": {
"node": ">= 6.0.0"
}
},
"node_modules/tsyringe/node_modules/tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"license": "0BSD"
},
"node_modules/proper-lockfile": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz",
"integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==",
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.4",
"retry": "^0.12.0",
"signal-exit": "^3.0.2"
}
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"license": "ISC"
},
"node_modules/retry": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
"integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
"license": "MIT",
"dependencies": {},
"engines": {
"node": ">= 4"
}
},
"node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"license": "ISC"
},
"node_modules/reflect-metadata": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
"integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
"license": "Apache-2.0",
"dependencies": {}
},
"node_modules/semver": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"license": "ISC",
"engines": {
"node": ">=10"
},
"bin": {
"semver": "bin/semver.js"
}
}
}
}
@@ -0,0 +1,16 @@
{
"name": "@qinglong/worker-image-dependencies",
"version": "3.0.0-alpha.0",
"private": true,
"description": "Production-only external dependency root for the QingLong 3.0 Worker image",
"license": "Apache-2.0",
"engines": {
"node": ">=24.18.0 <25"
},
"dependencies": {
"@peculiar/x509": "2.0.0",
"proper-lockfile": "4.1.2",
"reflect-metadata": "0.2.2",
"semver": "7.7.4"
}
}
+5
View File
@@ -1,5 +1,10 @@
# Kubernetes deployment
This directory is the QingLong 2.x single-replica SQLite deployment. The
QingLong 3.0 PostgreSQL-backed multi-replica incubation baseline lives at
[`ql3-cluster`](./ql3-cluster/README.md). The two profiles are intentionally
separate and must not share storage or scaling instructions.
This deploys Qinglong as a single-replica `StatefulSet` with persistent data at `/ql/data`.
```bash
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,275 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ql3-cluster-control
labels:
app.kubernetes.io/name: ql3-cluster-control
app.kubernetes.io/component: control-plane
app.kubernetes.io/part-of: qinglong3
spec:
replicas: 2
minReadySeconds: 10
revisionHistoryLimit: 3
progressDeadlineSeconds: 600
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
selector:
matchLabels:
app.kubernetes.io/name: ql3-cluster-control
app.kubernetes.io/component: control-plane
template:
metadata:
labels:
app.kubernetes.io/name: ql3-cluster-control
app.kubernetes.io/component: control-plane
app.kubernetes.io/part-of: qinglong3
spec:
serviceAccountName: ql3-cluster-control
automountServiceAccountToken: false
terminationGracePeriodSeconds: 30
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: kubernetes.io/hostname
labelSelector:
matchLabels:
app.kubernetes.io/name: ql3-cluster-control
app.kubernetes.io/component: control-plane
containers:
- name: cluster-control
image: qinglong3-cluster-control:3.0.0-alpha.0
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
env:
- name: QL_DEPLOYMENT_PROFILE
value: cluster-control
- name: QL3_CLUSTER_CONTROL_ENABLED
value: "true"
- name: QL3_CLUSTER_HTTP_HOST
value: 0.0.0.0
- name: QL3_CLUSTER_HTTP_PORT
value: "5800"
- name: QL3_CLUSTER_HTTP_DRAIN_TIMEOUT_MS
value: "10000"
- name: QL3_WORKER_INGRESS_ENABLED
value: "true"
- name: QL3_WORKER_INGRESS_HOST
value: 0.0.0.0
- name: QL3_WORKER_INGRESS_PORT
value: "5801"
- name: QL3_WORKER_INGRESS_POSTGRES_TLS_MODE
value: verify-full
- name: QL3_WORKER_INGRESS_POSTGRES_TLS_CA_FILE
value: /var/run/secrets/qinglong3/postgres-worker-ingress/ca.crt
- name: QL3_WORKER_INGRESS_POSTGRES_MAX_CONNECTIONS
value: "4"
- name: QL3_WORKER_INGRESS_POSTGRES_APPLICATION_NAME
value: qinglong3-worker-ingress
- name: QL3_WORKER_INGRESS_TLS_PRIVATE_KEY_FILE
value: /var/run/secrets/qinglong3/worker-ingress-tls/tls.key
- name: QL3_WORKER_INGRESS_TLS_CERTIFICATE_FILE
value: /var/run/secrets/qinglong3/worker-ingress-tls/tls.crt
- name: QL3_WORKER_INGRESS_TLS_CLIENT_CA_FILE
value: /var/run/secrets/qinglong3/worker-ingress-tls/client-ca.crt
- name: QL3_WORKER_SECRET_PROVIDER
value: mounted-files
- name: QL3_WORKER_SECRET_ROOT_DIRECTORY
value: /var/run/secrets/qinglong3/worker-values
- name: QL3_POSTGRES_TLS_MODE
value: verify-full
- name: QL3_POSTGRES_TLS_CA_FILE
value: /var/run/secrets/qinglong3/postgres-runtime/ca.crt
- name: QL3_POSTGRES_MAX_CONNECTIONS
value: "8"
- name: QL3_POSTGRES_APPLICATION_NAME
value: qinglong3-cluster-control
- name: QL3_CLUSTER_REPLICA_ID
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: QL3_POSTGRES_RUNTIME_URL
valueFrom:
secretKeyRef:
name: ql3-cluster-control-runtime
key: postgres-runtime-url
- name: QL3_POSTGRES_TLS_SERVERNAME
valueFrom:
secretKeyRef:
name: ql3-cluster-control-runtime
key: postgres-tls-servername
- name: QL3_API_CREDENTIAL_PEPPER
valueFrom:
secretKeyRef:
name: ql3-cluster-control-runtime
key: api-credential-pepper
- name: QL3_POSTGRES_WORKER_INGRESS_URL
valueFrom:
secretKeyRef:
name: ql3-cluster-worker-ingress
key: postgres-worker-ingress-url
- name: QL3_WORKER_INGRESS_POSTGRES_TLS_SERVERNAME
valueFrom:
secretKeyRef:
name: ql3-cluster-worker-ingress
key: postgres-tls-servername
- name: QL3_WORKER_CREDENTIAL_PEPPER
valueFrom:
secretKeyRef:
name: ql3-cluster-worker-ingress
key: worker-credential-pepper
- name: QL3_WORKER_ARTIFACT_S3_BUCKET
valueFrom:
secretKeyRef:
name: ql3-cluster-worker-ingress
key: artifact-s3-bucket
- name: QL3_WORKER_ARTIFACT_S3_REGION
valueFrom:
secretKeyRef:
name: ql3-cluster-worker-ingress
key: artifact-s3-region
- name: QL3_WORKER_ARTIFACT_S3_ENDPOINT
valueFrom:
secretKeyRef:
name: ql3-cluster-worker-ingress
key: artifact-s3-endpoint
optional: true
- name: QL3_WORKER_ARTIFACT_S3_ALLOW_INSECURE
valueFrom:
secretKeyRef:
name: ql3-cluster-worker-ingress
key: artifact-s3-allow-insecure
optional: true
- name: QL3_WORKER_ARTIFACT_S3_FORCE_PATH_STYLE
valueFrom:
secretKeyRef:
name: ql3-cluster-worker-ingress
key: artifact-s3-force-path-style
optional: true
- name: QL3_WORKER_ARTIFACT_S3_ENCRYPTION
valueFrom:
secretKeyRef:
name: ql3-cluster-worker-ingress
key: artifact-s3-encryption
optional: true
- name: QL3_WORKER_ARTIFACT_S3_KMS_KEY_ID
valueFrom:
secretKeyRef:
name: ql3-cluster-worker-ingress
key: artifact-s3-kms-key-id
optional: true
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: ql3-cluster-worker-ingress
key: artifact-s3-access-key-id
optional: true
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: ql3-cluster-worker-ingress
key: artifact-s3-secret-access-key
optional: true
ports:
- name: http
containerPort: 5800
protocol: TCP
- name: worker-mtls
containerPort: 5801
protocol: TCP
startupProbe:
httpGet:
path: /livez
port: http
scheme: HTTP
periodSeconds: 2
timeoutSeconds: 1
failureThreshold: 30
readinessProbe:
httpGet:
path: /readyz
port: http
scheme: HTTP
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 2
livenessProbe:
httpGet:
path: /livez
port: http
scheme: HTTP
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: "1"
memory: 512Mi
volumeMounts:
- name: tmp
mountPath: /tmp
- name: postgres-runtime-ca
mountPath: /var/run/secrets/qinglong3/postgres-runtime
readOnly: true
- name: postgres-worker-ingress-ca
mountPath: /var/run/secrets/qinglong3/postgres-worker-ingress
readOnly: true
- name: worker-ingress-tls
mountPath: /var/run/secrets/qinglong3/worker-ingress-tls
readOnly: true
- name: worker-secret-values
mountPath: /var/run/secrets/qinglong3/worker-values
readOnly: true
volumes:
- name: tmp
emptyDir:
medium: Memory
sizeLimit: 16Mi
- name: postgres-runtime-ca
secret:
secretName: ql3-cluster-control-runtime
defaultMode: 292
items:
- key: postgres-ca.crt
path: ca.crt
- name: postgres-worker-ingress-ca
secret:
secretName: ql3-cluster-worker-ingress
defaultMode: 288
items:
- key: postgres-ca.crt
path: ca.crt
- name: worker-ingress-tls
secret:
secretName: ql3-cluster-worker-ingress
defaultMode: 288
items:
- key: tls.key
path: tls.key
- key: tls.crt
path: tls.crt
- key: client-ca.crt
path: client-ca.crt
- name: worker-secret-values
secret:
secretName: ql3-cluster-worker-values
optional: true
defaultMode: 288
@@ -0,0 +1,11 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: qinglong3-system
resources:
- namespace.yaml
- service-account.yaml
- service.yaml
- deployment.yaml
- pod-disruption-budget.yaml
@@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: qinglong3-system
labels:
app.kubernetes.io/part-of: qinglong3
@@ -0,0 +1,13 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: ql3-cluster-control
labels:
app.kubernetes.io/name: ql3-cluster-control
app.kubernetes.io/component: control-plane
spec:
minAvailable: 1
selector:
matchLabels:
app.kubernetes.io/name: ql3-cluster-control
app.kubernetes.io/component: control-plane
@@ -0,0 +1,8 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: ql3-cluster-control
labels:
app.kubernetes.io/name: ql3-cluster-control
app.kubernetes.io/component: control-plane
automountServiceAccountToken: false
@@ -0,0 +1,21 @@
apiVersion: v1
kind: Service
metadata:
name: ql3-cluster-control
labels:
app.kubernetes.io/name: ql3-cluster-control
app.kubernetes.io/component: control-plane
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: ql3-cluster-control
app.kubernetes.io/component: control-plane
ports:
- name: http
port: 5800
targetPort: http
protocol: TCP
- name: worker-mtls
port: 5801
targetPort: worker-mtls
protocol: TCP
@@ -0,0 +1,10 @@
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: ql3-postgres
spec:
plugins:
- name: barman-cloud.cloudnative-pg.io
isWALArchiver: true
parameters:
barmanObjectName: ql3-postgres-backup
@@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
resources:
- scheduled-backup.yaml
patches:
- path: cluster-plugin-patch.yaml
@@ -0,0 +1,30 @@
# Example only. Copy into a private overlay and replace every placeholder.
# This resource is intentionally excluded from the Component.
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: ql3-postgres-backup
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-postgres
app.kubernetes.io/component: database-backup
app.kubernetes.io/part-of: qinglong3
spec:
retentionPolicy: 30d
configuration:
destinationPath: s3://REPLACE_WITH_VERSIONED_LOCKED_BUCKET/qinglong3/ql3-postgres
endpointURL: https://REPLACE_WITH_OBJECT_STORE_ENDPOINT
s3Credentials:
accessKeyId:
name: ql3-postgres-backup-object-store
key: ACCESS_KEY_ID
secretAccessKey:
name: ql3-postgres-backup-object-store
key: ACCESS_SECRET_KEY
wal:
compression: lz4
encryption: AES256
maxParallel: 2
data:
compression: lz4
encryption: AES256
@@ -0,0 +1,11 @@
# Example only. Save as kustomization.yaml in a private overlay beside a
# populated object-store.yaml. Do not apply this file directly.
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../operators/cloudnative-pg
- object-store.yaml
components:
- ../../components/barman-cloud-backup
@@ -0,0 +1,20 @@
apiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata:
name: ql3-postgres-daily
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-postgres
app.kubernetes.io/component: database-backup
app.kubernetes.io/part-of: qinglong3
spec:
schedule: '0 0 0 * * *'
backupOwnerReference: self
immediate: false
suspend: false
target: prefer-standby
cluster:
name: ql3-postgres
method: plugin
pluginConfiguration:
name: barman-cloud.cloudnative-pg.io
@@ -0,0 +1,30 @@
# Optional Cluster AI durable Prompt output
This component opts the existing Cluster AI runtime into encrypted, durable
Prompt output. Apply it only together with `../cluster-ai`; the default Cluster
and default Cluster AI profiles remain live-output-only.
The runtime receives only a read-only `0440` projection of
`ql3-prompt-output-keyring/keyring.json`. It does not receive a ServiceAccount
token, Kubernetes API authority, or permission to provision, rotate, or retire
keys. The projected-keyring adapter reopens the manifest for each operation, so
Kubernetes atomic projection updates become visible without a process restart.
Before applying it:
1. Provision the namespaced `ql3-prompt-output-keyring` Secret through the
deployment platform or Secret manager. Do not commit key material or a
deployable Secret manifest to this repository.
2. Store the canonical
`qinglong/plugin-package-prompt-output-keyring@v1` document under the exact
`keyring.json` data key. Keep the active key and bounded decrypt-only history
in that one document.
3. Apply both components from a private overlay and pin the independent Cluster
AI image digest, as shown by
`../../overlays/cluster-ai-prompt-output-example/kustomization.yaml`.
4. Use the reviewed management operation for retirement. Provisioning and
active-key rotation remain deployment-plane responsibilities; the runtime
must never be granted Secret mutation authority.
The Secret must remain non-optional. A missing, malformed, writable, escaped,
or rotating-during-read keyring fails startup or the affected operation closed.
@@ -0,0 +1,26 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ql3-cluster-control
spec:
template:
spec:
containers:
- name: cluster-control
env:
- name: QL3_CLUSTER_AI_PROMPT_OUTPUT_ENABLED
value: 'true'
- name: QL3_CLUSTER_AI_PROMPT_OUTPUT_KEYRING_ROOT
value: /var/run/secrets/qinglong3/ai/prompt-output-keyring
volumeMounts:
- name: cluster-ai-prompt-output-keyring
mountPath: /var/run/secrets/qinglong3/ai/prompt-output-keyring
readOnly: true
volumes:
- name: cluster-ai-prompt-output-keyring
secret:
secretName: ql3-prompt-output-keyring
defaultMode: 288
items:
- key: keyring.json
path: keyring.json
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
patches:
- path: deployment-patch.yaml
@@ -0,0 +1,26 @@
# Optional Cluster AI component
This component replaces only the Cluster Control image with the explicit
`runtime-ai` target. The default Cluster deployment and image remain AI-free.
Before applying it:
1. Replace the example Project, provider URL, model and policy revision in
`provider-authority-configmap.yaml`; keep `authority.json` canonical,
one-line JSON with one trailing newline.
2. Bind the same Project/provider to a canonical SecretRef through the
append-only model-provider credential catalog.
3. Project each provider authorization value under the lowercase SHA-256 of
its canonical SecretRef. Use `provider-secrets.example.yaml` only as a
shape reference and provision the real Secret through a Secret manager.
4. Build and publish the Docker `runtime-ai` target, then pin its independent
digest in a private overlay based on `private-overlay.example.yaml`.
The component mounts ConfigMap and Secret volumes read-only with mode `0440`,
does not mount a ServiceAccount token, and grants no Kubernetes API access.
It remains live-output-only by default. Compose the separate
`../cluster-ai-prompt-output` component only when encrypted durable Prompt
output and its externally provisioned keyring are required.
Each replica adds a separate, bounded PostgreSQL runtime pool of four
connections by default; tune `QL3_CLUSTER_AI_DATABASE_MAX_CONNECTIONS` and
`QL3_CLUSTER_AI_MAX_CONCURRENT` together for the cluster's resource budget.
@@ -0,0 +1,42 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ql3-cluster-control
spec:
template:
spec:
containers:
- name: cluster-control
image: qinglong3-cluster-control-ai:3.0.0-alpha.0
env:
- name: QL3_CLUSTER_AI_ENABLED
value: "true"
- name: QL3_CLUSTER_AI_PROVIDER_AUTHORITY_FILE
value: /var/run/qinglong3/ai/provider-authority/authority.json
- name: QL3_CLUSTER_AI_SECRET_ROOT
value: /var/run/secrets/qinglong3/ai/provider-secrets
- name: QL3_CLUSTER_AI_MAX_CONCURRENT
value: "4"
- name: QL3_CLUSTER_AI_RECOVERY_LIMIT
value: "32"
- name: QL3_CLUSTER_AI_DATABASE_MAX_CONNECTIONS
value: "4"
volumeMounts:
- name: cluster-ai-provider-authority
mountPath: /var/run/qinglong3/ai/provider-authority
readOnly: true
- name: cluster-ai-provider-secrets
mountPath: /var/run/secrets/qinglong3/ai/provider-secrets
readOnly: true
volumes:
- name: cluster-ai-provider-authority
configMap:
name: ql3-cluster-ai-provider-authority
defaultMode: 288
items:
- key: authority.json
path: authority.json
- name: cluster-ai-provider-secrets
secret:
secretName: ql3-cluster-ai-provider-secrets
defaultMode: 288
@@ -0,0 +1,8 @@
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component
resources:
- provider-authority-configmap.yaml
patches:
- path: deployment-patch.yaml
@@ -0,0 +1,15 @@
# Example only. Save as kustomization.yaml in a private overlay and replace the
# digest with the independently verified runtime-ai image digest.
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
components:
- ../../components/cluster-ai
images:
- name: qinglong3-cluster-control-ai
newName: registry.example.com/qinglong/qinglong3-cluster-control-ai
digest: sha256:0000000000000000000000000000000000000000000000000000000000000000
@@ -0,0 +1,11 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: ql3-cluster-ai-provider-authority
labels:
app.kubernetes.io/name: ql3-cluster-control
app.kubernetes.io/component: control-plane-ai
app.kubernetes.io/part-of: qinglong3
data:
authority.json: |
{"schema":"qinglong/projected-model-gateway-authority@v1","providers":[{"type":"openai-compatible","baseUrl":"https://models.example.invalid/v1/","allowPlaintextLoopback":false,"maxResponseBytes":1048576}],"projects":[{"projectId":"replace-project-id","policy":{"revision":"replace-policy-v1","allowedProviders":["openai-compatible"],"allowedModels":["replace-model-id"],"maxInputBytes":65536,"maxOutputBytes":1048576,"maxOutputTokens":4096,"maxTotalTokens":32768,"maxCostMicros":null,"priceRevision":null}}]}
@@ -0,0 +1,11 @@
# Example only. Populate through a Secret manager and never commit real values.
# The data key is sha256(canonical SecretRef); the matching catalog binding is:
# qlsecret:v1:eyJwcm9qZWN0SWQiOiJyZXBsYWNlLXByb2plY3QtaWQiLCJuYW1lIjoib3BlbmFpLWNvbXBhdGlibGUtdG9rZW4ifQ
apiVersion: v1
kind: Secret
metadata:
name: ql3-cluster-ai-provider-secrets
namespace: qinglong3-system
type: Opaque
stringData:
2ac34db919c697fd198d1a4fdfd90f69d9fa58c363c7ce5c8e4ca113413fbc6b: REPLACE_WITH_PROVIDER_AUTHORIZATION_VALUE
@@ -0,0 +1,196 @@
apiVersion: batch/v1
kind: Job
metadata:
name: ql3-approval-management-client
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-approval-management-client
app.kubernetes.io/component: approval-management-client
app.kubernetes.io/part-of: qinglong3
qinglong.io/execution-model: caller-driven
spec:
backoffLimit: 0
activeDeadlineSeconds: 120
ttlSecondsAfterFinished: 600
template:
metadata:
labels:
app.kubernetes.io/name: ql3-approval-management-client
app.kubernetes.io/component: approval-management-client
app.kubernetes.io/part-of: qinglong3
qinglong.io/execution-model: caller-driven
qinglong.io/approval-management-client: 'true'
spec:
serviceAccountName: ql3-approval-management-client
automountServiceAccountToken: false
enableServiceLinks: false
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
initContainers:
- name: wait-for-manager
image: qinglong3-cluster-admin:3.0.0-alpha.0
imagePullPolicy: IfNotPresent
command:
- node
- -e
args:
- |
const fs = require('node:fs');
const https = require('node:https');
const host = 'ql3-approval-management.qinglong3-system.svc';
const ca = fs.readFileSync('/var/run/qinglong3/approval-management-trust/ca.crt');
const cert = fs.readFileSync('/var/run/secrets/qinglong3/approval-management-client-identity/tls.crt');
const key = fs.readFileSync('/var/run/secrets/qinglong3/approval-management-client-identity/tls.key');
const probe = () => new Promise((resolve, reject) => {
const request = https.request({
host,
port: 8447,
path: '/readyz',
method: 'GET',
servername: host,
ca,
cert,
key,
minVersion: 'TLSv1.3',
maxVersion: 'TLSv1.3',
rejectUnauthorized: true,
agent: false,
headers: { connection: 'close' },
}, (response) => {
response.resume();
response.once('end', () =>
response.statusCode === 200
? resolve()
: reject(new Error('manager not ready')));
});
request.setTimeout(3000, () => request.destroy(new Error('timeout')));
request.once('error', reject);
request.end();
});
(async () => {
for (let attempt = 1; attempt <= 30; attempt += 1) {
try {
await probe();
return;
} catch {
if (attempt === 30) throw new Error('manager readiness unavailable');
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}
})().catch((error) => {
process.stderr.write(`${error.message}\n`);
process.exitCode = 1;
});
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
requests:
cpu: 5m
memory: 16Mi
limits:
cpu: 100m
memory: 64Mi
volumeMounts:
- name: trust
mountPath: /var/run/qinglong3/approval-management-trust
readOnly: true
- name: client-identity
mountPath: /var/run/secrets/qinglong3/approval-management-client-identity
readOnly: true
containers:
- name: client
image: qinglong3-cluster-admin:3.0.0-alpha.0
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
args:
- |
set -eu
umask 077
cp /var/run/secrets/qinglong3/approval-management-request/client.json /tmp/client.json
cp /var/run/secrets/qinglong3/approval-management-request/command.json /tmp/command.json
cp /var/run/secrets/qinglong3/approval-management-assertion/assertion.jwt /tmp/assertion.jwt
cp /var/run/qinglong3/approval-management-trust/ca.crt /tmp/ca.crt
cp /var/run/secrets/qinglong3/approval-management-client-identity/tls.crt /tmp/client.crt
cp /var/run/secrets/qinglong3/approval-management-client-identity/tls.key /tmp/client.key
chmod 600 /tmp/client.json /tmp/command.json /tmp/assertion.jwt /tmp/ca.crt /tmp/client.crt /tmp/client.key
exec node /opt/qinglong/node_modules/@qinglong/cluster-admin/dist/approval-management/approvalManagementClientCli.js \
--config=/tmp/client.json \
--command=/tmp/command.json \
--assertion=/tmp/assertion.jwt
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
requests:
cpu: 25m
memory: 48Mi
limits:
cpu: 250m
memory: 128Mi
volumeMounts:
- name: tmp
mountPath: /tmp
- name: request
mountPath: /var/run/secrets/qinglong3/approval-management-request
readOnly: true
- name: assertion
mountPath: /var/run/secrets/qinglong3/approval-management-assertion
readOnly: true
- name: trust
mountPath: /var/run/qinglong3/approval-management-trust
readOnly: true
- name: client-identity
mountPath: /var/run/secrets/qinglong3/approval-management-client-identity
readOnly: true
volumes:
- name: tmp
emptyDir:
medium: Memory
sizeLimit: 4Mi
- name: request
secret:
secretName: ql3-approval-management-request
defaultMode: 288
items:
- key: client.json
path: client.json
- key: command.json
path: command.json
- name: assertion
secret:
secretName: ql3-approval-management-assertion
defaultMode: 288
items:
- key: assertion.jwt
path: assertion.jwt
- name: trust
configMap:
name: ql3-approval-management-client-trust
defaultMode: 292
items:
- key: ca.crt
path: ca.crt
- name: client-identity
secret:
secretName: ql3-approval-management-client-identity
defaultMode: 288
items:
- key: tls.crt
path: tls.crt
- key: tls.key
path: tls.key
@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- service-account.yaml
- job.yaml
- network-policy.yaml
@@ -0,0 +1,39 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ql3-approval-management-client
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-approval-management-client
app.kubernetes.io/component: approval-management-client
app.kubernetes.io/part-of: qinglong3
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: ql3-approval-management-client
app.kubernetes.io/component: approval-management-client
policyTypes:
- Ingress
- Egress
ingress: []
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: ql3-approval-management
app.kubernetes.io/component: approval-management
ports:
- protocol: TCP
port: 8447
@@ -0,0 +1,10 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: ql3-approval-management-client
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-approval-management-client
app.kubernetes.io/component: approval-management-client
app.kubernetes.io/part-of: qinglong3
automountServiceAccountToken: false
@@ -0,0 +1,45 @@
# Example only. Copy these objects into a private, per-command overlay.
# Replace every placeholder. Never commit an assertion, private key or review detail.
apiVersion: v1
kind: Secret
metadata:
name: ql3-approval-management-request
namespace: qinglong3-system
immutable: true
type: Opaque
stringData:
client.json: |
{"schemaVersion":1,"endpoint":"https://ql3-approval-management.qinglong3-system.svc:8447/api/v3/approvals/management","servername":"ql3-approval-management.qinglong3-system.svc","caFile":"/tmp/ca.crt","clientCertificateFile":"/tmp/client.crt","clientPrivateKeyFile":"/tmp/client.key","requestTimeoutMs":15000}
command.json: |
{"schemaVersion":1,"operation":"approval.inspect","request":{"projectId":"REPLACE_WITH_PROJECT_ID","approvalRequestId":"REPLACE_WITH_APPROVAL_REQUEST_ID","requestId":"REPLACE_WITH_UNIQUE_REQUEST_ID","auditEventId":"REPLACE_WITH_UUID_V4","failureAuditEventId":"REPLACE_WITH_DIFFERENT_UUID_V4"}}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: ql3-approval-management-client-trust
namespace: qinglong3-system
immutable: true
data:
ca.crt: |
REPLACE_WITH_REVIEWED_MANAGER_CA_CERTIFICATE
---
apiVersion: v1
kind: Secret
metadata:
name: ql3-approval-management-assertion
namespace: qinglong3-system
immutable: true
type: Opaque
stringData:
assertion.jwt: REPLACE_WITH_SHORT_LIVED_STRONG_USER_ASSERTION
---
apiVersion: v1
kind: Secret
metadata:
name: ql3-approval-management-client-identity
namespace: qinglong3-system
immutable: true
type: kubernetes.io/tls
stringData:
tls.crt: REPLACE_WITH_SHORT_LIVED_CLIENT_CERTIFICATE_CHAIN
tls.key: REPLACE_WITH_CLIENT_PRIVATE_KEY
@@ -0,0 +1,11 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- base
images:
- name: qinglong3-cluster-admin
newName: registry.example.com/qinglong/qinglong3-cluster-admin
# Fail closed until the independently verified release digest is supplied.
digest: sha256:0000000000000000000000000000000000000000000000000000000000000000
@@ -0,0 +1,198 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ql3-approval-management
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-approval-management
app.kubernetes.io/component: approval-management
app.kubernetes.io/part-of: qinglong3
spec:
replicas: 2
minReadySeconds: 10
revisionHistoryLimit: 3
progressDeadlineSeconds: 600
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
selector:
matchLabels:
app.kubernetes.io/name: ql3-approval-management
app.kubernetes.io/component: approval-management
template:
metadata:
annotations:
qinglong.io/approval-management-client-ca-sha256: sha256:0000000000000000000000000000000000000000000000000000000000000000
qinglong.io/approval-management-client-crl-sha256: sha256:0000000000000000000000000000000000000000000000000000000000000000
labels:
app.kubernetes.io/name: ql3-approval-management
app.kubernetes.io/component: approval-management
app.kubernetes.io/part-of: qinglong3
spec:
serviceAccountName: ql3-approval-management
automountServiceAccountToken: false
terminationGracePeriodSeconds: 30
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: kubernetes.io/hostname
labelSelector:
matchLabels:
app.kubernetes.io/name: ql3-approval-management
app.kubernetes.io/component: approval-management
containers:
- name: management
image: qinglong3-cluster-admin:3.0.0-alpha.0
imagePullPolicy: IfNotPresent
command:
- node
- /opt/qinglong/node_modules/@qinglong/cluster-admin/dist/approval-management/approvalManagementCli.js
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
env:
- name: QL3_PROFILE
value: cluster-admin
- name: QL3_APPROVAL_MANAGEMENT_ENABLED
value: 'true'
- name: QL3_APPROVAL_MANAGEMENT_HOST
value: 0.0.0.0
- name: QL3_APPROVAL_MANAGEMENT_PORT
value: '8447'
- name: QL3_APPROVAL_MANAGEMENT_TLS_CERT_FILE
value: /var/run/secrets/qinglong3/approval-management-tls/tls.crt
- name: QL3_APPROVAL_MANAGEMENT_TLS_KEY_FILE
value: /var/run/secrets/qinglong3/approval-management-tls/tls.key
- name: QL3_APPROVAL_MANAGEMENT_CLIENT_CA_FILE
value: /var/run/secrets/qinglong3/approval-management-tls/ca.crt
- name: QL3_APPROVAL_MANAGEMENT_CLIENT_CRL_FILE
value: /var/run/secrets/qinglong3/approval-management-tls/client.crl
- name: QL3_APPROVAL_MANAGEMENT_IDENTITY_KEYSET_FILE
value: /var/run/qinglong3/approval-management-identity/keyset.json
- name: QL3_APPROVAL_MANAGEMENT_MAX_BODY_BYTES
value: '65536'
- name: QL3_APPROVAL_MANAGEMENT_MAX_CONNECTIONS
value: '32'
- name: QL3_APPROVAL_MANAGEMENT_MAX_CONCURRENT_REQUESTS
value: '16'
- name: QL3_APPROVAL_MANAGEMENT_REQUEST_TIMEOUT_MS
value: '10000'
- name: QL3_APPROVAL_MANAGEMENT_DRAIN_TIMEOUT_MS
value: '5000'
- name: QL3_APPROVAL_MANAGEMENT_RATE_WINDOW_MS
value: '60000'
- name: QL3_APPROVAL_MANAGEMENT_PEER_REQUEST_LIMIT
value: '30'
- name: QL3_APPROVAL_MANAGEMENT_GLOBAL_REQUEST_LIMIT
value: '300'
- name: QL3_APPROVAL_MANAGEMENT_MAX_RATE_LIMIT_PEERS
value: '1024'
- name: QL3_POSTGRES_APPROVAL_MANAGER_TLS_MODE
value: verify-full
- name: QL3_POSTGRES_APPROVAL_MANAGER_TLS_CA_FILE
value: /var/run/secrets/qinglong3/postgres-approval-manager/ca.crt
- name: QL3_POSTGRES_APPROVAL_MANAGER_APPLICATION_NAME
value: qinglong3-approval-manager
- name: QL3_POSTGRES_APPROVAL_MANAGER_POOL_MAX
value: '2'
- name: QL3_POSTGRES_APPROVAL_MANAGER_URL
valueFrom:
secretKeyRef:
name: ql3-cluster-approval-management-database
key: postgres-approval-manager-url
- name: QL3_POSTGRES_APPROVAL_MANAGER_TLS_SERVERNAME
valueFrom:
secretKeyRef:
name: ql3-cluster-approval-management-database
key: postgres-tls-servername
ports:
- name: https
containerPort: 8447
protocol: TCP
startupProbe:
httpGet:
path: /livez
port: https
scheme: HTTPS
periodSeconds: 2
timeoutSeconds: 1
failureThreshold: 30
readinessProbe:
httpGet:
path: /readyz
port: https
scheme: HTTPS
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 2
livenessProbe:
httpGet:
path: /livez
port: https
scheme: HTTPS
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
resources:
requests:
cpu: 50m
memory: 96Mi
limits:
cpu: '1'
memory: 384Mi
volumeMounts:
- name: tmp
mountPath: /tmp
- name: management-tls
mountPath: /var/run/secrets/qinglong3/approval-management-tls
readOnly: true
- name: management-identity
mountPath: /var/run/qinglong3/approval-management-identity
readOnly: true
- name: postgres-approval-manager-ca
mountPath: /var/run/secrets/qinglong3/postgres-approval-manager
readOnly: true
volumes:
- name: tmp
emptyDir:
medium: Memory
sizeLimit: 16Mi
- name: management-tls
secret:
secretName: ql3-approval-management-tls
defaultMode: 288
items:
- key: tls.crt
path: tls.crt
- key: tls.key
path: tls.key
- key: ca.crt
path: ca.crt
- key: client.crl
path: client.crl
- name: management-identity
secret:
secretName: ql3-approval-management-identity
defaultMode: 292
items:
- key: keyset.json
path: keyset.json
- name: postgres-approval-manager-ca
secret:
secretName: ql3-cluster-approval-management-database
defaultMode: 292
items:
- key: postgres-ca.crt
path: ca.crt
@@ -0,0 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- service-account.yaml
- service.yaml
- deployment.yaml
- pod-disruption-budget.yaml
- network-policy.yaml
@@ -0,0 +1,38 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ql3-approval-management
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-approval-management
app.kubernetes.io/component: approval-management
app.kubernetes.io/part-of: qinglong3
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: ql3-approval-management
app.kubernetes.io/component: approval-management
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
qinglong.io/approval-management-client: 'true'
ports:
- protocol: TCP
port: 8447
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
@@ -0,0 +1,15 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: ql3-approval-management
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-approval-management
app.kubernetes.io/component: approval-management
app.kubernetes.io/part-of: qinglong3
spec:
minAvailable: 1
selector:
matchLabels:
app.kubernetes.io/name: ql3-approval-management
app.kubernetes.io/component: approval-management
@@ -0,0 +1,10 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: ql3-approval-management
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-approval-management
app.kubernetes.io/component: approval-management
app.kubernetes.io/part-of: qinglong3
automountServiceAccountToken: false
@@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: ql3-approval-management
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-approval-management
app.kubernetes.io/component: approval-management
app.kubernetes.io/part-of: qinglong3
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: ql3-approval-management
app.kubernetes.io/component: approval-management
ports:
- name: https
port: 8447
targetPort: https
protocol: TCP
@@ -0,0 +1,71 @@
- op: replace
path: /spec/template/spec/containers/0/env
value:
- name: QL3_PROFILE
value: cluster-admin
- name: QL3_APPROVAL_MANAGEMENT_ENABLED
value: 'true'
- name: QL3_APPROVAL_MANAGEMENT_HOST
value: 0.0.0.0
- name: QL3_APPROVAL_MANAGEMENT_PORT
value: '8447'
- name: QL3_APPROVAL_MANAGEMENT_TLS_CERT_FILE
value: /var/run/secrets/qinglong3/approval-management-tls/tls.crt
- name: QL3_APPROVAL_MANAGEMENT_TLS_KEY_FILE
value: /var/run/secrets/qinglong3/approval-management-tls/tls.key
- name: QL3_APPROVAL_MANAGEMENT_CLIENT_CA_FILE
value: /var/run/secrets/qinglong3/approval-management-tls/ca.crt
- name: QL3_APPROVAL_MANAGEMENT_CLIENT_CRL_FILE
value: /var/run/secrets/qinglong3/approval-management-tls/client.crl
- name: QL3_APPROVAL_MANAGEMENT_IDENTITY_KEYSET_FILE
value: /var/run/qinglong3/approval-management-identity/keyset.json
- name: QL3_APPROVAL_MANAGEMENT_MAX_BODY_BYTES
value: '65536'
- name: QL3_APPROVAL_MANAGEMENT_MAX_CONNECTIONS
value: '32'
- name: QL3_APPROVAL_MANAGEMENT_MAX_CONCURRENT_REQUESTS
value: '16'
- name: QL3_APPROVAL_MANAGEMENT_REQUEST_TIMEOUT_MS
value: '10000'
- name: QL3_APPROVAL_MANAGEMENT_DRAIN_TIMEOUT_MS
value: '5000'
- name: QL3_APPROVAL_MANAGEMENT_RATE_WINDOW_MS
value: '60000'
- name: QL3_APPROVAL_MANAGEMENT_PEER_REQUEST_LIMIT
value: '30'
- name: QL3_APPROVAL_MANAGEMENT_GLOBAL_REQUEST_LIMIT
value: '300'
- name: QL3_APPROVAL_MANAGEMENT_MAX_RATE_LIMIT_PEERS
value: '1024'
- name: QL3_POSTGRES_APPROVAL_MANAGER_TLS_MODE
value: verify-full
- name: QL3_POSTGRES_APPROVAL_MANAGER_TLS_CA_FILE
value: /var/run/secrets/qinglong3/postgres-approval-manager/ca.crt
- name: QL3_POSTGRES_APPROVAL_MANAGER_APPLICATION_NAME
value: qinglong3-approval-manager
- name: QL3_POSTGRES_APPROVAL_MANAGER_POOL_MAX
value: '2'
- name: QL3_POSTGRES_APPROVAL_MANAGER_HOST
value: ql3-postgres-rw.qinglong3-system.svc
- name: QL3_POSTGRES_APPROVAL_MANAGER_PORT
value: '5432'
- name: QL3_POSTGRES_APPROVAL_MANAGER_DATABASE
value: qinglong
- name: QL3_POSTGRES_APPROVAL_MANAGER_USER
valueFrom:
secretKeyRef:
name: ql3-postgres-approval-manager-auth
key: username
- name: QL3_POSTGRES_APPROVAL_MANAGER_PASSWORD
valueFrom:
secretKeyRef:
name: ql3-postgres-approval-manager-auth
key: password
- name: QL3_POSTGRES_APPROVAL_MANAGER_TLS_SERVERNAME
value: ql3-postgres-rw.qinglong3-system.svc
- op: replace
path: /spec/template/spec/volumes/3/secret/secretName
value: ql3-postgres-ca
- op: replace
path: /spec/template/spec/volumes/3/secret/items/0/key
value: ca.crt
@@ -0,0 +1,25 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base
patches:
- target:
group: apps
version: v1
kind: Deployment
labelSelector: app.kubernetes.io/name=ql3-approval-management
path: deployment-patch.yaml
- target:
group: networking.k8s.io
version: v1
kind: NetworkPolicy
name: ql3-approval-management
path: network-policy-patch.yaml
images:
- name: qinglong3-cluster-admin
newName: registry.example.com/qinglong/qinglong3-cluster-admin
# Fail closed until the independently verified release digest is supplied.
digest: sha256:0000000000000000000000000000000000000000000000000000000000000000
@@ -0,0 +1,26 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ql3-approval-management
namespace: qinglong3-system
spec:
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
- to:
- podSelector:
matchLabels:
cnpg.io/cluster: ql3-postgres
ports:
- protocol: TCP
port: 5432
@@ -0,0 +1,72 @@
# Example only. Copy into a private overlay and replace every placeholder.
# This file is intentionally excluded from committed Kustomizations.
# Assertions require aud=qinglong3-approval-management,
# typ=ql3-approval-management+jwt and ql3_purpose=approval-management.
apiVersion: v1
kind: Secret
metadata:
name: ql3-approval-management-identity
namespace: qinglong3-system
type: Opaque
stringData:
keyset.json: |
{
"schemaVersion": 1,
"generation": 1,
"issuer": "https://identity.example.test/",
"audience": "qinglong3-approval-management",
"keys": [
{
"alg": "EdDSA",
"crv": "Ed25519",
"kid": "REPLACE_WITH_KEY_ID",
"kty": "OKP",
"use": "sig",
"x": "REPLACE_WITH_ED25519_PUBLIC_JWK_X"
}
],
"revokedKids": [],
"assuranceMappings": [
{
"acr": "urn:example:mfa",
"assurance": "multi_factor",
"requiredAmr": ["pwd", "otp"]
},
{
"acr": "urn:example:hardware",
"assurance": "hardware",
"requiredAmr": ["hwk"]
}
],
"constraints": {
"maxAssertionBytes": 8192,
"maxLifetimeMs": 300000,
"maxAuthenticationAgeMs": 300000,
"clockSkewMs": 5000
}
}
---
apiVersion: v1
kind: Secret
metadata:
name: ql3-approval-management-tls
namespace: qinglong3-system
type: kubernetes.io/tls
stringData:
tls.crt: REPLACE_WITH_SERVER_CERTIFICATE_CHAIN
tls.key: REPLACE_WITH_SERVER_PRIVATE_KEY
ca.crt: REPLACE_WITH_1_TO_16_CLIENT_CERTIFICATE_AUTHORITIES
client.crl: REPLACE_WITH_1_TO_16_CLIENT_CERTIFICATE_REVOCATION_LISTS
---
# Non-CloudNativePG deployments only. The reviewed overlay uses
# ql3-postgres-approval-manager-auth and ql3-postgres-ca instead.
apiVersion: v1
kind: Secret
metadata:
name: ql3-cluster-approval-management-database
namespace: qinglong3-system
type: Opaque
stringData:
postgres-approval-manager-url: REPLACE_WITH_APPROVAL_MANAGER_DSN
postgres-tls-servername: REPLACE_WITH_POSTGRES_DNS_NAME
postgres-ca.crt: REPLACE_WITH_POSTGRES_CA_CERTIFICATE
@@ -0,0 +1,196 @@
apiVersion: batch/v1
kind: Job
metadata:
name: ql3-automation-management-client
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-automation-management-client
app.kubernetes.io/component: automation-management-client
app.kubernetes.io/part-of: qinglong3
qinglong.io/execution-model: caller-driven
spec:
backoffLimit: 0
activeDeadlineSeconds: 120
ttlSecondsAfterFinished: 600
template:
metadata:
labels:
app.kubernetes.io/name: ql3-automation-management-client
app.kubernetes.io/component: automation-management-client
app.kubernetes.io/part-of: qinglong3
qinglong.io/execution-model: caller-driven
qinglong.io/automation-management-client: 'true'
spec:
serviceAccountName: ql3-automation-management-client
automountServiceAccountToken: false
enableServiceLinks: false
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
initContainers:
- name: wait-for-manager
image: qinglong3-cluster-admin:3.0.0-alpha.0
imagePullPolicy: IfNotPresent
command:
- node
- -e
args:
- |
const fs = require('node:fs');
const https = require('node:https');
const host = 'ql3-automation-management.qinglong3-system.svc';
const ca = fs.readFileSync('/var/run/qinglong3/automation-management-trust/ca.crt');
const cert = fs.readFileSync('/var/run/secrets/qinglong3/automation-management-client-identity/tls.crt');
const key = fs.readFileSync('/var/run/secrets/qinglong3/automation-management-client-identity/tls.key');
const probe = () => new Promise((resolve, reject) => {
const request = https.request({
host,
port: 8445,
path: '/readyz',
method: 'GET',
servername: host,
ca,
cert,
key,
minVersion: 'TLSv1.3',
maxVersion: 'TLSv1.3',
rejectUnauthorized: true,
agent: false,
headers: { connection: 'close' },
}, (response) => {
response.resume();
response.once('end', () =>
response.statusCode === 200
? resolve()
: reject(new Error('manager not ready')));
});
request.setTimeout(3000, () => request.destroy(new Error('timeout')));
request.once('error', reject);
request.end();
});
(async () => {
for (let attempt = 1; attempt <= 30; attempt += 1) {
try {
await probe();
return;
} catch {
if (attempt === 30) throw new Error('manager readiness unavailable');
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}
})().catch((error) => {
process.stderr.write(`${error.message}\n`);
process.exitCode = 1;
});
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
requests:
cpu: 5m
memory: 16Mi
limits:
cpu: 100m
memory: 64Mi
volumeMounts:
- name: trust
mountPath: /var/run/qinglong3/automation-management-trust
readOnly: true
- name: client-identity
mountPath: /var/run/secrets/qinglong3/automation-management-client-identity
readOnly: true
containers:
- name: client
image: qinglong3-cluster-admin:3.0.0-alpha.0
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
args:
- |
set -eu
umask 077
cp /var/run/secrets/qinglong3/automation-management-request/client.json /tmp/client.json
cp /var/run/secrets/qinglong3/automation-management-request/command.json /tmp/command.json
cp /var/run/secrets/qinglong3/automation-management-assertion/assertion.jwt /tmp/assertion.jwt
cp /var/run/qinglong3/automation-management-trust/ca.crt /tmp/ca.crt
cp /var/run/secrets/qinglong3/automation-management-client-identity/tls.crt /tmp/client.crt
cp /var/run/secrets/qinglong3/automation-management-client-identity/tls.key /tmp/client.key
chmod 600 /tmp/client.json /tmp/command.json /tmp/assertion.jwt /tmp/ca.crt /tmp/client.crt /tmp/client.key
exec node /opt/qinglong/node_modules/@qinglong/cluster-admin/dist/automation-management/automationManagementClientCli.js \
--config=/tmp/client.json \
--command=/tmp/command.json \
--assertion=/tmp/assertion.jwt
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
requests:
cpu: 25m
memory: 48Mi
limits:
cpu: 250m
memory: 128Mi
volumeMounts:
- name: tmp
mountPath: /tmp
- name: request
mountPath: /var/run/secrets/qinglong3/automation-management-request
readOnly: true
- name: assertion
mountPath: /var/run/secrets/qinglong3/automation-management-assertion
readOnly: true
- name: trust
mountPath: /var/run/qinglong3/automation-management-trust
readOnly: true
- name: client-identity
mountPath: /var/run/secrets/qinglong3/automation-management-client-identity
readOnly: true
volumes:
- name: tmp
emptyDir:
medium: Memory
sizeLimit: 4Mi
- name: request
secret:
secretName: ql3-automation-management-request
defaultMode: 288
items:
- key: client.json
path: client.json
- key: command.json
path: command.json
- name: assertion
secret:
secretName: ql3-automation-management-assertion
defaultMode: 288
items:
- key: assertion.jwt
path: assertion.jwt
- name: trust
configMap:
name: ql3-automation-management-client-trust
defaultMode: 292
items:
- key: ca.crt
path: ca.crt
- name: client-identity
secret:
secretName: ql3-automation-management-client-identity
defaultMode: 288
items:
- key: tls.crt
path: tls.crt
- key: tls.key
path: tls.key
@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- service-account.yaml
- job.yaml
- network-policy.yaml
@@ -0,0 +1,39 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ql3-automation-management-client
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-automation-management-client
app.kubernetes.io/component: automation-management-client
app.kubernetes.io/part-of: qinglong3
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: ql3-automation-management-client
app.kubernetes.io/component: automation-management-client
policyTypes:
- Ingress
- Egress
ingress: []
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
- to:
- podSelector:
matchLabels:
app.kubernetes.io/name: ql3-automation-management
app.kubernetes.io/component: automation-management
ports:
- protocol: TCP
port: 8445
@@ -0,0 +1,10 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: ql3-automation-management-client
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-automation-management-client
app.kubernetes.io/component: automation-management-client
app.kubernetes.io/part-of: qinglong3
automountServiceAccountToken: false
@@ -0,0 +1,45 @@
# Example only. Copy these objects into a private, per-command overlay.
# Replace every placeholder. Never commit a Task body, assertion or private key.
apiVersion: v1
kind: Secret
metadata:
name: ql3-automation-management-request
namespace: qinglong3-system
immutable: true
type: Opaque
stringData:
client.json: |
{"schemaVersion":1,"endpoint":"https://ql3-automation-management.qinglong3-system.svc:8445/api/v3/automations/management","servername":"ql3-automation-management.qinglong3-system.svc","caFile":"/tmp/ca.crt","clientCertificateFile":"/tmp/client.crt","clientPrivateKeyFile":"/tmp/client.key","requestTimeoutMs":15000}
command.json: |
{"schemaVersion":1,"operation":"task.publish","request":{"requestId":"REPLACE_WITH_UNIQUE_REQUEST_ID","command":{"projectId":"REPLACE_WITH_PROJECT_ID","taskId":"REPLACE_WITH_TASK_ID","expectedRevision":null,"mutationId":"REPLACE_WITH_UUID_V4","name":"REPLACE_WITH_TASK_NAME","kind":"script","spec":{"schema":"qinglong/script@v1","config":{"source":"REPLACE_WITH_REVIEWED_TASK_SOURCE"}},"labels":{},"enabled":true,"occurredAtMs":0}}}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: ql3-automation-management-client-trust
namespace: qinglong3-system
immutable: true
data:
ca.crt: |
REPLACE_WITH_REVIEWED_MANAGER_CA_CERTIFICATE
---
apiVersion: v1
kind: Secret
metadata:
name: ql3-automation-management-assertion
namespace: qinglong3-system
immutable: true
type: Opaque
stringData:
assertion.jwt: REPLACE_WITH_SHORT_LIVED_STRONG_USER_ASSERTION
---
apiVersion: v1
kind: Secret
metadata:
name: ql3-automation-management-client-identity
namespace: qinglong3-system
immutable: true
type: kubernetes.io/tls
stringData:
tls.crt: REPLACE_WITH_SHORT_LIVED_CLIENT_CERTIFICATE_CHAIN
tls.key: REPLACE_WITH_CLIENT_PRIVATE_KEY
@@ -0,0 +1,11 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- base
images:
- name: qinglong3-cluster-admin
newName: registry.example.com/qinglong/qinglong3-cluster-admin
# Fail closed until the independently verified release digest is supplied.
digest: sha256:0000000000000000000000000000000000000000000000000000000000000000
@@ -0,0 +1,200 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ql3-automation-management
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-automation-management
app.kubernetes.io/component: automation-management
app.kubernetes.io/part-of: qinglong3
spec:
replicas: 2
minReadySeconds: 10
revisionHistoryLimit: 3
progressDeadlineSeconds: 600
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
selector:
matchLabels:
app.kubernetes.io/name: ql3-automation-management
app.kubernetes.io/component: automation-management
template:
metadata:
annotations:
# Private production overlays must replace these with the exact bundle
# digests before changing the client trust generation.
qinglong.io/automation-management-client-ca-sha256: sha256:0000000000000000000000000000000000000000000000000000000000000000
qinglong.io/automation-management-client-crl-sha256: sha256:0000000000000000000000000000000000000000000000000000000000000000
labels:
app.kubernetes.io/name: ql3-automation-management
app.kubernetes.io/component: automation-management
app.kubernetes.io/part-of: qinglong3
spec:
serviceAccountName: ql3-automation-management
automountServiceAccountToken: false
terminationGracePeriodSeconds: 30
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: kubernetes.io/hostname
labelSelector:
matchLabels:
app.kubernetes.io/name: ql3-automation-management
app.kubernetes.io/component: automation-management
containers:
- name: management
image: qinglong3-cluster-admin:3.0.0-alpha.0
imagePullPolicy: IfNotPresent
command:
- node
- /opt/qinglong/node_modules/@qinglong/cluster-admin/dist/automation-management/automationManagementCli.js
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
env:
- name: QL3_PROFILE
value: cluster-admin
- name: QL3_AUTOMATION_MANAGEMENT_ENABLED
value: 'true'
- name: QL3_AUTOMATION_MANAGEMENT_HOST
value: 0.0.0.0
- name: QL3_AUTOMATION_MANAGEMENT_PORT
value: '8445'
- name: QL3_AUTOMATION_MANAGEMENT_TLS_CERT_FILE
value: /var/run/secrets/qinglong3/automation-management-tls/tls.crt
- name: QL3_AUTOMATION_MANAGEMENT_TLS_KEY_FILE
value: /var/run/secrets/qinglong3/automation-management-tls/tls.key
- name: QL3_AUTOMATION_MANAGEMENT_CLIENT_CA_FILE
value: /var/run/secrets/qinglong3/automation-management-tls/ca.crt
- name: QL3_AUTOMATION_MANAGEMENT_CLIENT_CRL_FILE
value: /var/run/secrets/qinglong3/automation-management-tls/client.crl
- name: QL3_AUTOMATION_MANAGEMENT_IDENTITY_KEYSET_FILE
value: /var/run/qinglong3/automation-management-identity/keyset.json
- name: QL3_AUTOMATION_MANAGEMENT_MAX_BODY_BYTES
value: '65536'
- name: QL3_AUTOMATION_MANAGEMENT_MAX_CONNECTIONS
value: '32'
- name: QL3_AUTOMATION_MANAGEMENT_MAX_CONCURRENT_REQUESTS
value: '16'
- name: QL3_AUTOMATION_MANAGEMENT_REQUEST_TIMEOUT_MS
value: '10000'
- name: QL3_AUTOMATION_MANAGEMENT_DRAIN_TIMEOUT_MS
value: '5000'
- name: QL3_AUTOMATION_MANAGEMENT_RATE_WINDOW_MS
value: '60000'
- name: QL3_AUTOMATION_MANAGEMENT_PEER_REQUEST_LIMIT
value: '60'
- name: QL3_AUTOMATION_MANAGEMENT_GLOBAL_REQUEST_LIMIT
value: '600'
- name: QL3_AUTOMATION_MANAGEMENT_MAX_RATE_LIMIT_PEERS
value: '1024'
- name: QL3_POSTGRES_AUTOMATION_MANAGER_TLS_MODE
value: verify-full
- name: QL3_POSTGRES_AUTOMATION_MANAGER_TLS_CA_FILE
value: /var/run/secrets/qinglong3/postgres-automation-manager/ca.crt
- name: QL3_POSTGRES_AUTOMATION_MANAGER_APPLICATION_NAME
value: qinglong3-automation-manager
- name: QL3_POSTGRES_AUTOMATION_MANAGER_POOL_MAX
value: '2'
- name: QL3_POSTGRES_AUTOMATION_MANAGER_URL
valueFrom:
secretKeyRef:
name: ql3-cluster-automation-management-database
key: postgres-automation-manager-url
- name: QL3_POSTGRES_AUTOMATION_MANAGER_TLS_SERVERNAME
valueFrom:
secretKeyRef:
name: ql3-cluster-automation-management-database
key: postgres-tls-servername
ports:
- name: https
containerPort: 8445
protocol: TCP
startupProbe:
httpGet:
path: /livez
port: https
scheme: HTTPS
periodSeconds: 2
timeoutSeconds: 1
failureThreshold: 30
readinessProbe:
httpGet:
path: /readyz
port: https
scheme: HTTPS
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 2
livenessProbe:
httpGet:
path: /livez
port: https
scheme: HTTPS
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: '1'
memory: 512Mi
volumeMounts:
- name: tmp
mountPath: /tmp
- name: management-tls
mountPath: /var/run/secrets/qinglong3/automation-management-tls
readOnly: true
- name: management-identity
mountPath: /var/run/qinglong3/automation-management-identity
readOnly: true
- name: postgres-automation-manager-ca
mountPath: /var/run/secrets/qinglong3/postgres-automation-manager
readOnly: true
volumes:
- name: tmp
emptyDir:
medium: Memory
sizeLimit: 16Mi
- name: management-tls
secret:
secretName: ql3-automation-management-tls
defaultMode: 288
items:
- key: tls.crt
path: tls.crt
- key: tls.key
path: tls.key
- key: ca.crt
path: ca.crt
- key: client.crl
path: client.crl
- name: management-identity
secret:
secretName: ql3-automation-management-identity
defaultMode: 292
items:
- key: keyset.json
path: keyset.json
- name: postgres-automation-manager-ca
secret:
secretName: ql3-cluster-automation-management-database
defaultMode: 292
items:
- key: postgres-ca.crt
path: ca.crt
@@ -0,0 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- service-account.yaml
- service.yaml
- deployment.yaml
- pod-disruption-budget.yaml
- network-policy.yaml
@@ -0,0 +1,38 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ql3-automation-management
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-automation-management
app.kubernetes.io/component: automation-management
app.kubernetes.io/part-of: qinglong3
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: ql3-automation-management
app.kubernetes.io/component: automation-management
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
qinglong.io/automation-management-client: 'true'
ports:
- protocol: TCP
port: 8445
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
@@ -0,0 +1,15 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: ql3-automation-management
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-automation-management
app.kubernetes.io/component: automation-management
app.kubernetes.io/part-of: qinglong3
spec:
minAvailable: 1
selector:
matchLabels:
app.kubernetes.io/name: ql3-automation-management
app.kubernetes.io/component: automation-management
@@ -0,0 +1,10 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: ql3-automation-management
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-automation-management
app.kubernetes.io/component: automation-management
app.kubernetes.io/part-of: qinglong3
automountServiceAccountToken: false
@@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: ql3-automation-management
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-automation-management
app.kubernetes.io/component: automation-management
app.kubernetes.io/part-of: qinglong3
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: ql3-automation-management
app.kubernetes.io/component: automation-management
ports:
- name: https
port: 8445
targetPort: https
protocol: TCP
@@ -0,0 +1,71 @@
- op: replace
path: /spec/template/spec/containers/0/env
value:
- name: QL3_PROFILE
value: cluster-admin
- name: QL3_AUTOMATION_MANAGEMENT_ENABLED
value: 'true'
- name: QL3_AUTOMATION_MANAGEMENT_HOST
value: 0.0.0.0
- name: QL3_AUTOMATION_MANAGEMENT_PORT
value: '8445'
- name: QL3_AUTOMATION_MANAGEMENT_TLS_CERT_FILE
value: /var/run/secrets/qinglong3/automation-management-tls/tls.crt
- name: QL3_AUTOMATION_MANAGEMENT_TLS_KEY_FILE
value: /var/run/secrets/qinglong3/automation-management-tls/tls.key
- name: QL3_AUTOMATION_MANAGEMENT_CLIENT_CA_FILE
value: /var/run/secrets/qinglong3/automation-management-tls/ca.crt
- name: QL3_AUTOMATION_MANAGEMENT_CLIENT_CRL_FILE
value: /var/run/secrets/qinglong3/automation-management-tls/client.crl
- name: QL3_AUTOMATION_MANAGEMENT_IDENTITY_KEYSET_FILE
value: /var/run/qinglong3/automation-management-identity/keyset.json
- name: QL3_AUTOMATION_MANAGEMENT_MAX_BODY_BYTES
value: '65536'
- name: QL3_AUTOMATION_MANAGEMENT_MAX_CONNECTIONS
value: '32'
- name: QL3_AUTOMATION_MANAGEMENT_MAX_CONCURRENT_REQUESTS
value: '16'
- name: QL3_AUTOMATION_MANAGEMENT_REQUEST_TIMEOUT_MS
value: '10000'
- name: QL3_AUTOMATION_MANAGEMENT_DRAIN_TIMEOUT_MS
value: '5000'
- name: QL3_AUTOMATION_MANAGEMENT_RATE_WINDOW_MS
value: '60000'
- name: QL3_AUTOMATION_MANAGEMENT_PEER_REQUEST_LIMIT
value: '60'
- name: QL3_AUTOMATION_MANAGEMENT_GLOBAL_REQUEST_LIMIT
value: '600'
- name: QL3_AUTOMATION_MANAGEMENT_MAX_RATE_LIMIT_PEERS
value: '1024'
- name: QL3_POSTGRES_AUTOMATION_MANAGER_TLS_MODE
value: verify-full
- name: QL3_POSTGRES_AUTOMATION_MANAGER_TLS_CA_FILE
value: /var/run/secrets/qinglong3/postgres-automation-manager/ca.crt
- name: QL3_POSTGRES_AUTOMATION_MANAGER_APPLICATION_NAME
value: qinglong3-automation-manager
- name: QL3_POSTGRES_AUTOMATION_MANAGER_POOL_MAX
value: '2'
- name: QL3_POSTGRES_AUTOMATION_MANAGER_HOST
value: ql3-postgres-rw.qinglong3-system.svc
- name: QL3_POSTGRES_AUTOMATION_MANAGER_PORT
value: '5432'
- name: QL3_POSTGRES_AUTOMATION_MANAGER_DATABASE
value: qinglong
- name: QL3_POSTGRES_AUTOMATION_MANAGER_USER
valueFrom:
secretKeyRef:
name: ql3-postgres-automation-manager-auth
key: username
- name: QL3_POSTGRES_AUTOMATION_MANAGER_PASSWORD
valueFrom:
secretKeyRef:
name: ql3-postgres-automation-manager-auth
key: password
- name: QL3_POSTGRES_AUTOMATION_MANAGER_TLS_SERVERNAME
value: ql3-postgres-rw.qinglong3-system.svc
- op: replace
path: /spec/template/spec/volumes/3/secret/secretName
value: ql3-postgres-ca
- op: replace
path: /spec/template/spec/volumes/3/secret/items/0/key
value: ca.crt
@@ -0,0 +1,25 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base
patches:
- target:
group: apps
version: v1
kind: Deployment
labelSelector: app.kubernetes.io/name=ql3-automation-management
path: deployment-patch.yaml
- target:
group: networking.k8s.io
version: v1
kind: NetworkPolicy
name: ql3-automation-management
path: network-policy-patch.yaml
images:
- name: qinglong3-cluster-admin
newName: registry.example.com/qinglong/qinglong3-cluster-admin
# Fail closed until the independently verified release digest is supplied.
digest: sha256:0000000000000000000000000000000000000000000000000000000000000000
@@ -0,0 +1,26 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ql3-automation-management
namespace: qinglong3-system
spec:
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
- to:
- podSelector:
matchLabels:
cnpg.io/cluster: ql3-postgres
ports:
- protocol: TCP
port: 5432
@@ -0,0 +1,75 @@
# Example only. Copy into a private overlay and replace every placeholder.
# This file is intentionally excluded from all committed Kustomizations.
# Assertions signed by this keyset must use all three automation-specific values:
# aud=qinglong3-automation-management, typ=ql3-automation-management+jwt, and
# ql3_purpose=automation-management. Plugin Package and Worker assertions are
# rejected even when they use the same issuer and signing key.
apiVersion: v1
kind: Secret
metadata:
name: ql3-automation-management-identity
namespace: qinglong3-system
type: Opaque
stringData:
keyset.json: |
{
"schemaVersion": 1,
"generation": 1,
"issuer": "https://identity.example.test/",
"audience": "qinglong3-automation-management",
"keys": [
{
"alg": "EdDSA",
"crv": "Ed25519",
"kid": "REPLACE_WITH_KEY_ID",
"kty": "OKP",
"use": "sig",
"x": "REPLACE_WITH_ED25519_PUBLIC_JWK_X"
}
],
"revokedKids": [],
"assuranceMappings": [
{
"acr": "urn:example:mfa",
"assurance": "multi_factor",
"requiredAmr": ["pwd", "otp"]
},
{
"acr": "urn:example:hardware",
"assurance": "hardware",
"requiredAmr": ["hwk"]
}
],
"constraints": {
"maxAssertionBytes": 8192,
"maxLifetimeMs": 300000,
"maxAuthenticationAgeMs": 300000,
"clockSkewMs": 5000
}
}
---
apiVersion: v1
kind: Secret
metadata:
name: ql3-automation-management-tls
namespace: qinglong3-system
type: kubernetes.io/tls
stringData:
tls.crt: REPLACE_WITH_SERVER_CERTIFICATE_CHAIN
tls.key: REPLACE_WITH_SERVER_PRIVATE_KEY
ca.crt: REPLACE_WITH_1_TO_16_CLIENT_CERTIFICATE_AUTHORITIES
client.crl: REPLACE_WITH_1_TO_16_CLIENT_CERTIFICATE_REVOCATION_LISTS
---
# Non-CloudNativePG deployments only. The reviewed CloudNativePG overlay uses
# the operator-managed ql3-postgres-automation-manager-auth and ql3-postgres-ca
# Secrets instead of this resource.
apiVersion: v1
kind: Secret
metadata:
name: ql3-cluster-automation-management-database
namespace: qinglong3-system
type: Opaque
stringData:
postgres-automation-manager-url: REPLACE_WITH_AUTOMATION_MANAGER_DSN
postgres-tls-servername: REPLACE_WITH_POSTGRES_DNS_NAME
postgres-ca.crt: REPLACE_WITH_POSTGRES_CA_CERTIFICATE
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- migrate-job.yaml
@@ -0,0 +1,85 @@
apiVersion: batch/v1
kind: Job
metadata:
name: ql3-cluster-migration
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-cluster-migration
app.kubernetes.io/component: database-migration
app.kubernetes.io/part-of: qinglong3
spec:
backoffLimit: 0
activeDeadlineSeconds: 600
ttlSecondsAfterFinished: 600
template:
metadata:
labels:
app.kubernetes.io/name: ql3-cluster-migration
app.kubernetes.io/component: database-migration
app.kubernetes.io/part-of: qinglong3
spec:
serviceAccountName: ql3-cluster-control
automountServiceAccountToken: false
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
containers:
- name: migration
image: qinglong3-cluster-control:3.0.0-alpha.0
imagePullPolicy: IfNotPresent
command:
- node
- /opt/qinglong/node_modules/@qinglong/cluster-postgres/dist/migration/migrationCli.js
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
env:
- name: QL3_POSTGRES_TLS_MODE
value: verify-full
- name: QL3_POSTGRES_TLS_CA_FILE
value: /var/run/secrets/qinglong3/postgres-migration/ca.crt
- name: QL3_POSTGRES_APPLICATION_NAME
value: qinglong3-cluster-migration
- name: QL3_POSTGRES_MIGRATION_URL
valueFrom:
secretKeyRef:
name: ql3-cluster-migration
key: postgres-migration-url
- name: QL3_POSTGRES_TLS_SERVERNAME
valueFrom:
secretKeyRef:
name: ql3-cluster-migration
key: postgres-tls-servername
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: '1'
memory: 256Mi
volumeMounts:
- name: tmp
mountPath: /tmp
- name: postgres-migration-ca
mountPath: /var/run/secrets/qinglong3/postgres-migration
readOnly: true
volumes:
- name: tmp
emptyDir:
medium: Memory
sizeLimit: 16Mi
- name: postgres-migration-ca
secret:
secretName: ql3-cluster-migration
defaultMode: 292
items:
- key: postgres-ca.crt
path: ca.crt
@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: qinglong3-system
resources:
- restore-cluster.yaml
@@ -0,0 +1,27 @@
# Example only. Recovery credentials should be read-only wherever the provider
# supports separate read/list and write/delete authorities. This resource is
# intentionally excluded from Kustomize.
apiVersion: barmancloud.cnpg.io/v1
kind: ObjectStore
metadata:
name: ql3-postgres-recovery-source
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-postgres-restore
app.kubernetes.io/component: database-restore-source
app.kubernetes.io/part-of: qinglong3
spec:
configuration:
destinationPath: s3://REPLACE_WITH_VERSIONED_LOCKED_BUCKET/qinglong3/ql3-postgres
endpointURL: https://REPLACE_WITH_OBJECT_STORE_ENDPOINT
s3Credentials:
accessKeyId:
name: ql3-postgres-restore-object-store
key: ACCESS_KEY_ID
secretAccessKey:
name: ql3-postgres-restore-object-store
key: ACCESS_SECRET_KEY
wal:
compression: lz4
encryption: AES256
maxParallel: 4
@@ -0,0 +1,59 @@
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: ql3-postgres-restore
labels:
app.kubernetes.io/name: ql3-postgres-restore
app.kubernetes.io/component: database-restore-drill
app.kubernetes.io/part-of: qinglong3
app.kubernetes.io/managed-by: cloudnative-pg
spec:
instances: 3
imageName: ghcr.io/cloudnative-pg/postgresql:18.4-minimal-trixie@sha256:24d229d801663f95b584416f8ebdfad4849b1a3fa4cfcf95a7f026df7aa6e22d
enableSuperuserAccess: false
primaryUpdateMethod: switchover
failoverDelay: 0
switchoverDelay: 60
smartShutdownTimeout: 60
stopDelay: 300
bootstrap:
recovery:
source: ql3-postgres-origin
externalClusters:
- name: ql3-postgres-origin
plugin:
name: barman-cloud.cloudnative-pg.io
parameters:
barmanObjectName: ql3-postgres-recovery-source
serverName: ql3-postgres
postgresql:
parameters:
max_connections: '100'
password_encryption: scram-sha-256
shared_buffers: 128MB
synchronous_commit: remote_apply
synchronous:
method: any
number: 1
dataDurability: required
failoverQuorum: true
affinity:
enablePodAntiAffinity: true
podAntiAffinityType: required
topologyKey: kubernetes.io/hostname
managed:
services:
disabledDefaultServices:
- r
- ro
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: '2'
memory: 1Gi
storage:
size: 20Gi
walStorage:
size: 5Gi
@@ -0,0 +1,19 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base
images:
- name: qinglong3-cluster-control
newName: registry.example.com/qinglong/qinglong3-cluster-control
# Fail closed until the independently verified release digest is supplied.
digest: sha256:0000000000000000000000000000000000000000000000000000000000000000
patches:
- target:
group: batch
version: v1
kind: Job
labelSelector: app.kubernetes.io/name=ql3-cluster-migration
path: migrate-job-patch.yaml
@@ -0,0 +1,33 @@
- op: replace
path: /spec/template/spec/containers/0/env
value:
- name: QL3_POSTGRES_TLS_MODE
value: verify-full
- name: QL3_POSTGRES_TLS_CA_FILE
value: /var/run/secrets/qinglong3/postgres-migration/ca.crt
- name: QL3_POSTGRES_APPLICATION_NAME
value: qinglong3-cluster-migration
- name: QL3_POSTGRES_MIGRATION_HOST
value: ql3-postgres-rw.qinglong3-system.svc
- name: QL3_POSTGRES_MIGRATION_PORT
value: '5432'
- name: QL3_POSTGRES_MIGRATION_DATABASE
value: qinglong
- name: QL3_POSTGRES_MIGRATION_USER
valueFrom:
secretKeyRef:
name: ql3-postgres-migration-auth
key: username
- name: QL3_POSTGRES_MIGRATION_PASSWORD
valueFrom:
secretKeyRef:
name: ql3-postgres-migration-auth
key: password
- name: QL3_POSTGRES_TLS_SERVERNAME
value: ql3-postgres-rw.qinglong3-system.svc
- op: replace
path: /spec/template/spec/volumes/1/secret/secretName
value: ql3-postgres-ca
- op: replace
path: /spec/template/spec/volumes/1/secret/items/0/key
value: ca.crt
@@ -0,0 +1,5 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- base
@@ -0,0 +1,110 @@
apiVersion: batch/v1
kind: CronJob
metadata:
name: ql3-plugin-package-executor
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-plugin-package-executor
app.kubernetes.io/component: plugin-package-executor
app.kubernetes.io/part-of: qinglong3
spec:
schedule: '*/2 * * * *'
concurrencyPolicy: Forbid
startingDeadlineSeconds: 60
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 3
jobTemplate:
spec:
backoffLimit: 2
activeDeadlineSeconds: 600
ttlSecondsAfterFinished: 600
template:
metadata:
labels:
app.kubernetes.io/name: ql3-plugin-package-executor
app.kubernetes.io/component: plugin-package-executor
app.kubernetes.io/part-of: qinglong3
spec:
serviceAccountName: ql3-plugin-package-executor
automountServiceAccountToken: false
restartPolicy: Never
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
containers:
- name: executor
image: qinglong3-cluster-admin:3.0.0-alpha.0
imagePullPolicy: IfNotPresent
command:
- node
- /opt/qinglong/node_modules/@qinglong/cluster-admin/dist/plugin-package/executor/pluginPackageExecutorCli.js
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
env:
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_ENABLED
value: 'true'
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_OWNER
value: cluster_package_executor
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_APPROVAL_BATCH_SIZE
value: '8'
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_DISPATCH_BATCH_SIZE
value: '8'
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_MAX_BATCHES
value: '4'
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_LEASE_DURATION_MS
value: '600000'
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_REVOCATION_PAGE_SIZE
value: '16'
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_REVOCATION_MAX_PAGES
value: '16'
- name: QL3_POSTGRES_TLS_MODE
value: verify-full
- name: QL3_POSTGRES_TLS_CA_FILE
value: /var/run/secrets/qinglong3/postgres-package-executor/ca.crt
- name: QL3_POSTGRES_APPLICATION_NAME
value: qinglong3-plugin-package-executor
- name: QL3_POSTGRES_MAX_CONNECTIONS
value: '2'
- name: QL3_POSTGRES_PACKAGE_EXECUTOR_URL
valueFrom:
secretKeyRef:
name: ql3-cluster-plugin-package-executor
key: postgres-package-executor-url
- name: QL3_POSTGRES_TLS_SERVERNAME
valueFrom:
secretKeyRef:
name: ql3-cluster-plugin-package-executor
key: postgres-tls-servername
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 500m
memory: 256Mi
volumeMounts:
- name: tmp
mountPath: /tmp
- name: postgres-package-executor-ca
mountPath: /var/run/secrets/qinglong3/postgres-package-executor
readOnly: true
volumes:
- name: tmp
emptyDir:
medium: Memory
sizeLimit: 8Mi
- name: postgres-package-executor-ca
secret:
secretName: ql3-cluster-plugin-package-executor
defaultMode: 292
items:
- key: postgres-ca.crt
path: ca.crt
@@ -0,0 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- service-account.yaml
- cron-job.yaml
- network-policy.yaml
@@ -0,0 +1,31 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ql3-plugin-package-executor
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-plugin-package-executor
app.kubernetes.io/component: plugin-package-executor
app.kubernetes.io/part-of: qinglong3
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: ql3-plugin-package-executor
app.kubernetes.io/component: plugin-package-executor
policyTypes:
- Ingress
- Egress
ingress: []
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
@@ -0,0 +1,10 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: ql3-plugin-package-executor
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-plugin-package-executor
app.kubernetes.io/component: plugin-package-executor
app.kubernetes.io/part-of: qinglong3
automountServiceAccountToken: false
@@ -0,0 +1,51 @@
- op: replace
path: /spec/jobTemplate/spec/template/spec/containers/0/env
value:
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_ENABLED
value: 'true'
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_OWNER
value: cluster_package_executor
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_APPROVAL_BATCH_SIZE
value: '8'
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_DISPATCH_BATCH_SIZE
value: '8'
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_MAX_BATCHES
value: '4'
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_LEASE_DURATION_MS
value: '600000'
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_REVOCATION_PAGE_SIZE
value: '16'
- name: QL3_PLUGIN_PACKAGE_EXECUTOR_REVOCATION_MAX_PAGES
value: '16'
- name: QL3_POSTGRES_TLS_MODE
value: verify-full
- name: QL3_POSTGRES_TLS_CA_FILE
value: /var/run/secrets/qinglong3/postgres-package-executor/ca.crt
- name: QL3_POSTGRES_APPLICATION_NAME
value: qinglong3-plugin-package-executor
- name: QL3_POSTGRES_MAX_CONNECTIONS
value: '2'
- name: QL3_POSTGRES_PACKAGE_EXECUTOR_HOST
value: ql3-postgres-rw.qinglong3-system.svc
- name: QL3_POSTGRES_PACKAGE_EXECUTOR_PORT
value: '5432'
- name: QL3_POSTGRES_PACKAGE_EXECUTOR_DATABASE
value: qinglong
- name: QL3_POSTGRES_PACKAGE_EXECUTOR_USER
valueFrom:
secretKeyRef:
name: ql3-postgres-package-executor-auth
key: username
- name: QL3_POSTGRES_PACKAGE_EXECUTOR_PASSWORD
valueFrom:
secretKeyRef:
name: ql3-postgres-package-executor-auth
key: password
- name: QL3_POSTGRES_TLS_SERVERNAME
value: ql3-postgres-rw.qinglong3-system.svc
- op: replace
path: /spec/jobTemplate/spec/template/spec/volumes/1/secret/secretName
value: ql3-postgres-ca
- op: replace
path: /spec/jobTemplate/spec/template/spec/volumes/1/secret/items/0/key
value: ca.crt
@@ -0,0 +1,25 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base
patches:
- target:
group: batch
version: v1
kind: CronJob
labelSelector: app.kubernetes.io/name=ql3-plugin-package-executor
path: cron-job-patch.yaml
- target:
group: networking.k8s.io
version: v1
kind: NetworkPolicy
name: ql3-plugin-package-executor
path: network-policy-patch.yaml
images:
- name: qinglong3-cluster-admin
newName: registry.example.com/qinglong/qinglong3-cluster-admin
# Fail closed until the independently verified release digest is supplied.
digest: sha256:0000000000000000000000000000000000000000000000000000000000000000
@@ -0,0 +1,10 @@
- op: add
path: /spec/egress/-
value:
to:
- podSelector:
matchLabels:
cnpg.io/cluster: ql3-postgres
ports:
- protocol: TCP
port: 5432
@@ -0,0 +1,12 @@
# Example only. Copy into a private overlay and replace every placeholder.
# The executor must receive only the package-executor database credential.
apiVersion: v1
kind: Secret
metadata:
name: ql3-cluster-plugin-package-executor
namespace: qinglong3-system
type: Opaque
stringData:
postgres-package-executor-url: REPLACE_WITH_PACKAGE_EXECUTOR_DSN
postgres-tls-servername: REPLACE_WITH_POSTGRES_DNS_NAME
postgres-ca.crt: REPLACE_WITH_POSTGRES_CA_CERTIFICATE
@@ -0,0 +1,215 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: ql3-plugin-package-management
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-plugin-package-management
app.kubernetes.io/component: plugin-package-management
app.kubernetes.io/part-of: qinglong3
spec:
replicas: 2
minReadySeconds: 10
revisionHistoryLimit: 3
progressDeadlineSeconds: 600
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
selector:
matchLabels:
app.kubernetes.io/name: ql3-plugin-package-management
app.kubernetes.io/component: plugin-package-management
template:
metadata:
labels:
app.kubernetes.io/name: ql3-plugin-package-management
app.kubernetes.io/component: plugin-package-management
app.kubernetes.io/part-of: qinglong3
spec:
serviceAccountName: ql3-plugin-package-management
automountServiceAccountToken: false
terminationGracePeriodSeconds: 30
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: kubernetes.io/hostname
labelSelector:
matchLabels:
app.kubernetes.io/name: ql3-plugin-package-management
app.kubernetes.io/component: plugin-package-management
containers:
- name: management
image: qinglong3-cluster-admin:3.0.0-alpha.0
imagePullPolicy: IfNotPresent
command:
- node
- /opt/qinglong/node_modules/@qinglong/cluster-admin/dist/plugin-package/management/pluginPackageManagementCli.js
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
env:
- name: QL3_PROFILE
value: cluster-admin
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_ENABLED
value: 'true'
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_HOST
value: 0.0.0.0
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_PORT
value: '8443'
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_TLS_CERT_FILE
value: /var/run/secrets/qinglong3/plugin-package-management-tls/tls.crt
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_TLS_KEY_FILE
value: /var/run/secrets/qinglong3/plugin-package-management-tls/tls.key
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_IDENTITY_KEYSET_FILE
value: /var/run/qinglong3/plugin-package-management-identity/keyset.json
- name: QL3_PLUGIN_PACKAGE_PUBLISHER_TRUST_FILE
value: /var/run/qinglong3/plugin-package-trust/publishers.json
- name: QL3_PLUGIN_PACKAGE_TRUST_AUTHORITY_PROJECT_ID
value: cluster-trust-authority
- name: QL3_PLUGIN_PACKAGE_TRUST_AUTHORITY_ID
value: cluster
- name: QL3_PLUGIN_PACKAGE_TRUST_OBSERVER_ID
value: cluster-package-manager
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_APPROVAL_LIFETIME_MS
value: '900000'
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_QUOTA_WINDOW_MS
value: '60000'
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_PROPOSE_QUOTA
value: '30'
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_DECIDE_QUOTA
value: '60'
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_INSPECT_QUOTA
value: '600'
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_MAX_BODY_BYTES
value: '65536'
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_MAX_CONNECTIONS
value: '32'
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_MAX_CONCURRENT_REQUESTS
value: '16'
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_REQUEST_TIMEOUT_MS
value: '10000'
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_DRAIN_TIMEOUT_MS
value: '10000'
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_RATE_WINDOW_MS
value: '60000'
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_PEER_REQUEST_LIMIT
value: '60'
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_GLOBAL_REQUEST_LIMIT
value: '600'
- name: QL3_PLUGIN_PACKAGE_MANAGEMENT_MAX_RATE_LIMIT_PEERS
value: '512'
- name: QL3_POSTGRES_PACKAGE_MANAGER_TLS_MODE
value: verify-full
- name: QL3_POSTGRES_PACKAGE_MANAGER_TLS_CA_FILE
value: /var/run/secrets/qinglong3/postgres-package-manager/ca.crt
- name: QL3_POSTGRES_PACKAGE_MANAGER_APPLICATION_NAME
value: qinglong3-plugin-package-manager
- name: QL3_POSTGRES_PACKAGE_MANAGER_MAX_CONNECTIONS
value: '2'
- name: QL3_POSTGRES_PACKAGE_MANAGER_URL
valueFrom:
secretKeyRef:
name: ql3-cluster-plugin-package-management-database
key: postgres-package-manager-url
- name: QL3_POSTGRES_PACKAGE_MANAGER_TLS_SERVERNAME
valueFrom:
secretKeyRef:
name: ql3-cluster-plugin-package-management-database
key: postgres-tls-servername
ports:
- name: https
containerPort: 8443
protocol: TCP
startupProbe:
httpGet:
path: /livez
port: https
scheme: HTTPS
periodSeconds: 2
timeoutSeconds: 1
failureThreshold: 30
readinessProbe:
httpGet:
path: /readyz
port: https
scheme: HTTPS
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 2
livenessProbe:
httpGet:
path: /livez
port: https
scheme: HTTPS
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: '1'
memory: 512Mi
volumeMounts:
- name: tmp
mountPath: /tmp
- name: management-tls
mountPath: /var/run/secrets/qinglong3/plugin-package-management-tls
readOnly: true
- name: management-identity
mountPath: /var/run/qinglong3/plugin-package-management-identity
readOnly: true
- name: plugin-package-trust
mountPath: /var/run/qinglong3/plugin-package-trust
readOnly: true
- name: postgres-package-manager-ca
mountPath: /var/run/secrets/qinglong3/postgres-package-manager
readOnly: true
volumes:
- name: tmp
emptyDir:
medium: Memory
sizeLimit: 16Mi
- name: management-tls
secret:
secretName: ql3-plugin-package-management-tls
defaultMode: 288
items:
- key: tls.crt
path: tls.crt
- key: tls.key
path: tls.key
- name: management-identity
secret:
secretName: ql3-plugin-package-management-identity
defaultMode: 292
items:
- key: keyset.json
path: keyset.json
- name: plugin-package-trust
configMap:
name: ql3-plugin-publisher-trust
defaultMode: 292
items:
- key: publishers.json
path: publishers.json
- name: postgres-package-manager-ca
secret:
secretName: ql3-cluster-plugin-package-management-database
defaultMode: 292
items:
- key: postgres-ca.crt
path: ca.crt
@@ -0,0 +1,9 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- service-account.yaml
- service.yaml
- deployment.yaml
- pod-disruption-budget.yaml
- network-policy.yaml
@@ -0,0 +1,38 @@
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: ql3-plugin-package-management
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-plugin-package-management
app.kubernetes.io/component: plugin-package-management
app.kubernetes.io/part-of: qinglong3
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: ql3-plugin-package-management
app.kubernetes.io/component: plugin-package-management
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
qinglong.io/plugin-package-management-client: 'true'
ports:
- protocol: TCP
port: 8443
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
@@ -0,0 +1,15 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: ql3-plugin-package-management
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-plugin-package-management
app.kubernetes.io/component: plugin-package-management
app.kubernetes.io/part-of: qinglong3
spec:
minAvailable: 1
selector:
matchLabels:
app.kubernetes.io/name: ql3-plugin-package-management
app.kubernetes.io/component: plugin-package-management
@@ -0,0 +1,10 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: ql3-plugin-package-management
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-plugin-package-management
app.kubernetes.io/component: plugin-package-management
app.kubernetes.io/part-of: qinglong3
automountServiceAccountToken: false
@@ -0,0 +1,19 @@
apiVersion: v1
kind: Service
metadata:
name: ql3-plugin-package-management
namespace: qinglong3-system
labels:
app.kubernetes.io/name: ql3-plugin-package-management
app.kubernetes.io/component: plugin-package-management
app.kubernetes.io/part-of: qinglong3
spec:
type: ClusterIP
selector:
app.kubernetes.io/name: ql3-plugin-package-management
app.kubernetes.io/component: plugin-package-management
ports:
- name: https
port: 8443
targetPort: https
protocol: TCP

Some files were not shown because too many files have changed in this diff Show More