mirror of
https://github.com/whyour/qinglong.git
synced 2026-08-06 16:54:33 +08:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5aaabf62c8 | |||
| bd40c44951 | |||
| 73753ff9f7 |
@@ -7,6 +7,8 @@ on:
|
||||
branches:
|
||||
- "master"
|
||||
- "develop"
|
||||
- "debian"
|
||||
- "debian-dev"
|
||||
tags:
|
||||
- "v*"
|
||||
schedule:
|
||||
@@ -129,6 +131,13 @@ jobs:
|
||||
with:
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Read version from version.yaml
|
||||
id: version
|
||||
run: |
|
||||
VERSION=$(grep '^version:' version.yaml | awk '{print $2}')
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Version: $VERSION"
|
||||
|
||||
- name: Setup timezone
|
||||
uses: szenius/set-timezone@v2.0
|
||||
with:
|
||||
@@ -164,6 +173,7 @@ jobs:
|
||||
type=ref,event=pr
|
||||
type=ref,event=branch,enable=${{ github.ref != format('refs/heads/{0}', 'master') }}
|
||||
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'master') }}
|
||||
type=raw,value=${{ steps.version.outputs.version }}-debian,enable=${{ github.ref == format('refs/heads/{0}', 'debian') || github.ref == format('refs/heads/{0}', 'debian-dev') }}
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
@@ -183,22 +193,21 @@ jobs:
|
||||
QL_BRANCH=${{ github.ref_name }}
|
||||
SOURCE_COMMIT=${{ github.sha }}
|
||||
network: host
|
||||
# linux/s390x npm 暂不可用
|
||||
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/386
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
|
||||
context: .
|
||||
file: ./docker/Dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=registry,ref=whyour/qinglong:cache
|
||||
cache-to: type=registry,ref=whyour/qinglong:cache,mode=max
|
||||
cache-from: type=registry,ref=whyour/qinglong:cache-debian
|
||||
cache-to: type=registry,ref=whyour/qinglong:cache-debian,mode=max
|
||||
|
||||
- name: Image digest
|
||||
run: |
|
||||
echo ${{ steps.docker_build.outputs.digest }}
|
||||
|
||||
build310:
|
||||
if: ${{ github.ref_name == 'master' }}
|
||||
if: ${{ github.ref_name == 'debian' }}
|
||||
needs: build-static
|
||||
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -216,6 +225,13 @@ jobs:
|
||||
with:
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Read version from version.yaml
|
||||
id: version
|
||||
run: |
|
||||
VERSION=$(grep '^version:' version.yaml | awk '{print $2}')
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Version: $VERSION"
|
||||
|
||||
- name: Setup timezone
|
||||
uses: szenius/set-timezone@v2.0
|
||||
with:
|
||||
@@ -249,15 +265,46 @@ jobs:
|
||||
QL_BRANCH=${{ github.ref_name }}
|
||||
SOURCE_COMMIT=${{ github.sha }}
|
||||
network: host
|
||||
# linux/s390x npm 暂不可用
|
||||
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64,linux/ppc64le,linux/386
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le,linux/s390x
|
||||
context: .
|
||||
file: ./docker/310.Dockerfile
|
||||
push: true
|
||||
tags: whyour/qinglong:python3.10
|
||||
cache-from: type=registry,ref=whyour/qinglong:cache-python3.10
|
||||
cache-to: type=registry,ref=whyour/qinglong:cache-python3.10,mode=max
|
||||
tags: |
|
||||
whyour/qinglong:debian-python3.10
|
||||
whyour/qinglong:${{ steps.version.outputs.version }}-debian-python3.10
|
||||
cache-from: type=registry,ref=whyour/qinglong:cache-debian-python3.10
|
||||
cache-to: type=registry,ref=whyour/qinglong:cache-debian-python3.10,mode=max
|
||||
|
||||
- name: Image digest
|
||||
run: |
|
||||
echo ${{ steps.docker_build_310.outputs.digest }}
|
||||
|
||||
publish:
|
||||
if: ${{ github.ref_name == 'debian' }}
|
||||
needs: build
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v3
|
||||
with:
|
||||
version: "8.3.1"
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
cache: "pnpm"
|
||||
|
||||
- name: build front and back
|
||||
run: |
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm build:front
|
||||
pnpm build:back
|
||||
|
||||
- name: publich npm package
|
||||
run: |
|
||||
echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" >> ~/.npmrc
|
||||
npm publish
|
||||
|
||||
@@ -426,24 +426,6 @@ export default (app: Router) => {
|
||||
},
|
||||
);
|
||||
|
||||
route.put(
|
||||
'/config/global-ssh-key',
|
||||
celebrate({
|
||||
body: Joi.object({
|
||||
globalSshKey: Joi.string().allow('').allow(null),
|
||||
}),
|
||||
}),
|
||||
async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const systemService = Container.get(SystemService);
|
||||
const result = await systemService.updateGlobalSshKey(req.body);
|
||||
res.send(result);
|
||||
} catch (e) {
|
||||
return next(e);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
route.put(
|
||||
'/config/dependence-clean',
|
||||
celebrate({
|
||||
|
||||
@@ -38,7 +38,6 @@ export interface SystemConfigInfo {
|
||||
pythonMirror?: string;
|
||||
linuxMirror?: string;
|
||||
timezone?: string;
|
||||
globalSshKey?: string;
|
||||
}
|
||||
|
||||
export interface LoginLogInfo {
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Container } from 'typedi';
|
||||
import SystemService from '../services/system';
|
||||
import ScheduleService, { ScheduleTaskType } from '../services/schedule';
|
||||
import SubscriptionService from '../services/subscription';
|
||||
import SshKeyService from '../services/sshKey';
|
||||
import config from '../config';
|
||||
import { fileExist } from '../config/util';
|
||||
import { join } from 'path';
|
||||
@@ -11,7 +10,6 @@ export default async () => {
|
||||
const systemService = Container.get(SystemService);
|
||||
const scheduleService = Container.get(ScheduleService);
|
||||
const subscriptionService = Container.get(SubscriptionService);
|
||||
const sshKeyService = Container.get(SshKeyService);
|
||||
|
||||
// 生成内置token
|
||||
let tokenCommand = `ts-node-transpile-only ${join(
|
||||
@@ -59,11 +57,6 @@ export default async () => {
|
||||
}
|
||||
|
||||
systemService.updateTimezone(data.info);
|
||||
|
||||
// Apply global SSH key if configured
|
||||
if (data.info.globalSshKey) {
|
||||
await sshKeyService.addGlobalSSHKey(data.info.globalSshKey, 'global');
|
||||
}
|
||||
}
|
||||
|
||||
await subscriptionService.setSshConfig();
|
||||
|
||||
@@ -507,7 +507,7 @@ export default class CronService {
|
||||
let { id, command, log_name } = cron;
|
||||
|
||||
const uniqPath =
|
||||
log_name === '/dev/null' || !log_name
|
||||
log_name === '/dev/null'
|
||||
? await getUniqPath(command, `${id}`)
|
||||
: log_name;
|
||||
const logTime = dayjs().format('YYYY-MM-DD-HH-mm-ss-SSS');
|
||||
@@ -641,11 +641,7 @@ export default class CronService {
|
||||
if (!command.startsWith(TASK_PREFIX) && !command.startsWith(QL_PREFIX)) {
|
||||
command = `${TASK_PREFIX}${tab.command}`;
|
||||
}
|
||||
let commandVariable = `real_time=${Boolean(realTime)} no_tee=true ID=${tab.id} `;
|
||||
// Only include log_name if it has a truthy value to avoid passing null/undefined to shell
|
||||
if (tab.log_name) {
|
||||
commandVariable += `log_name=${tab.log_name} `;
|
||||
}
|
||||
let commandVariable = `real_time=${Boolean(realTime)} log_name=${tab.log_name} no_tee=true ID=${tab.id} `;
|
||||
if (tab.task_before) {
|
||||
commandVariable += `task_before='${tab.task_before
|
||||
.replace(/'/g, "'\\''")
|
||||
|
||||
@@ -131,32 +131,4 @@ export default class SshKeyService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async addGlobalSSHKey(key: string, alias: string): Promise<void> {
|
||||
await this.generatePrivateKeyFile(`~global_${alias}`, key);
|
||||
// Create a global SSH config entry that matches all hosts
|
||||
// This allows the key to be used for any Git repository
|
||||
await this.generateGlobalSshConfig(`~global_${alias}`);
|
||||
}
|
||||
|
||||
public async removeGlobalSSHKey(alias: string): Promise<void> {
|
||||
await this.removePrivateKeyFile(`~global_${alias}`);
|
||||
await this.removeSshConfig(`~global_${alias}`);
|
||||
}
|
||||
|
||||
private async generateGlobalSshConfig(alias: string) {
|
||||
// Create a config that matches all hosts, making this key globally available
|
||||
const config = `Host *\n IdentityFile ${path.join(
|
||||
this.sshPath,
|
||||
alias,
|
||||
)}\n StrictHostKeyChecking no\n`;
|
||||
await writeFileWithLock(
|
||||
`${path.join(this.sshPath, `${alias}.config`)}`,
|
||||
config,
|
||||
{
|
||||
encoding: 'utf8',
|
||||
mode: '600',
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -530,27 +530,6 @@ export default class SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
public async updateGlobalSshKey(info: SystemModelInfo) {
|
||||
const oDoc = await this.getSystemConfig();
|
||||
const result = await this.updateAuthDb({
|
||||
...oDoc,
|
||||
info: { ...oDoc.info, ...info },
|
||||
});
|
||||
|
||||
// Apply the global SSH key
|
||||
const SshKeyService = require('./sshKey').default;
|
||||
const Container = require('typedi').Container;
|
||||
const sshKeyService = Container.get(SshKeyService);
|
||||
|
||||
if (info.globalSshKey) {
|
||||
await sshKeyService.addGlobalSSHKey(info.globalSshKey, 'global');
|
||||
} else {
|
||||
await sshKeyService.removeGlobalSSHKey('global');
|
||||
}
|
||||
|
||||
return { code: 200, data: result };
|
||||
}
|
||||
|
||||
public async cleanDependence(type: 'node' | 'python3') {
|
||||
if (!type || !['node', 'python3'].includes(type)) {
|
||||
return { code: 400, message: '参数错误' };
|
||||
|
||||
+65
-42
@@ -1,13 +1,18 @@
|
||||
FROM python:3.10-alpine3.18 AS builder
|
||||
COPY package.json .npmrc pnpm-lock.yaml /tmp/build/
|
||||
RUN set -x \
|
||||
&& apk update \
|
||||
&& apk add nodejs npm git \
|
||||
&& npm i -g pnpm@8.3.1 pm2 ts-node \
|
||||
&& cd /tmp/build \
|
||||
&& pnpm install --prod
|
||||
FROM node:22-slim AS nodebuilder
|
||||
|
||||
FROM python:3.10-alpine
|
||||
FROM python:3.10-slim-bookworm AS builder
|
||||
COPY package.json .npmrc pnpm-lock.yaml /tmp/build/
|
||||
COPY --from=nodebuilder /usr/local/bin/node /usr/local/bin/
|
||||
COPY --from=nodebuilder /usr/local/lib/node_modules/. /usr/local/lib/node_modules/
|
||||
RUN set -x && \
|
||||
ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && \
|
||||
apt-get update && \
|
||||
apt-get install --no-install-recommends -y libatomic1 && \
|
||||
npm i -g pnpm@8.3.1 && \
|
||||
cd /tmp/build && \
|
||||
pnpm install --prod
|
||||
|
||||
FROM python:3.10-slim-bookworm
|
||||
|
||||
ARG QL_MAINTAINER="whyour"
|
||||
LABEL maintainer="${QL_MAINTAINER}"
|
||||
@@ -21,51 +26,63 @@ ENV QL_DIR=/ql \
|
||||
SHELL=/bin/bash \
|
||||
PS1="\u@\h:\w \$ "
|
||||
|
||||
VOLUME /ql/data
|
||||
|
||||
EXPOSE 5700
|
||||
ARG QL_UID=5432
|
||||
ARG QL_GID=5432
|
||||
RUN groupadd -g ${QL_GID} qinglong && \
|
||||
useradd -m -u ${QL_UID} -g ${QL_GID} -s /bin/bash qinglong && \
|
||||
mkdir -p /home/qinglong/bin /home/qinglong/.ssh && \
|
||||
chmod 700 /home/qinglong/.ssh && \
|
||||
chown -R ${QL_UID}:${QL_GID} /home/qinglong
|
||||
|
||||
COPY --from=builder /usr/local/lib/node_modules/. /usr/local/lib/node_modules/
|
||||
COPY --from=builder /usr/local/bin/. /usr/local/bin/
|
||||
ENV QL_USER=qinglong
|
||||
ENV QL_HOME=/home/$QL_USER
|
||||
|
||||
RUN set -x \
|
||||
&& apk update -f \
|
||||
&& apk upgrade \
|
||||
&& apk --no-cache add -f bash \
|
||||
coreutils \
|
||||
git \
|
||||
COPY --from=nodebuilder /usr/local/bin/node /usr/local/bin/
|
||||
COPY --from=nodebuilder /usr/local/lib/node_modules/. /usr/local/lib/node_modules/
|
||||
|
||||
RUN set -x && \
|
||||
ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && \
|
||||
apt-get update && \
|
||||
apt-get upgrade -y && \
|
||||
apt-get install --no-install-recommends -y git \
|
||||
curl \
|
||||
wget \
|
||||
tzdata \
|
||||
perl \
|
||||
openssl \
|
||||
nodejs \
|
||||
openssh-client \
|
||||
jq \
|
||||
openssh \
|
||||
procps \
|
||||
netcat-openbsd \
|
||||
unzip \
|
||||
npm \
|
||||
&& rm -rf /var/cache/apk/* \
|
||||
&& apk update \
|
||||
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
|
||||
&& echo "Asia/Shanghai" > /etc/timezone \
|
||||
&& git config --global user.email "qinglong@users.noreply.github.com" \
|
||||
&& git config --global user.name "qinglong" \
|
||||
&& git config --global http.postBuffer 524288000 \
|
||||
&& rm -rf /root/.cache \
|
||||
&& ulimit -c 0
|
||||
libatomic1 && \
|
||||
apt-get clean && \
|
||||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
|
||||
echo "Asia/Shanghai" >/etc/timezone && \
|
||||
git config --global user.email "qinglong@users.noreply.github.com" && \
|
||||
git config --global user.name "qinglong" && \
|
||||
git config --global http.postBuffer 524288000 && \
|
||||
npm install -g pnpm@8.3.1 pm2 ts-node && \
|
||||
rm -rf /root/.cache && \
|
||||
rm -rf /root/.npm && \
|
||||
rm -rf /etc/apt/apt.conf.d/docker-clean && \
|
||||
ulimit -c 0
|
||||
|
||||
RUN mkdir -p ${QL_DIR} && \
|
||||
chown -R ${QL_UID}:${QL_GID} ${QL_DIR}
|
||||
|
||||
USER qinglong
|
||||
|
||||
ARG SOURCE_COMMIT
|
||||
RUN git clone --depth=1 -b ${QL_BRANCH} ${QL_URL} ${QL_DIR} \
|
||||
&& cd ${QL_DIR} \
|
||||
&& cp -f .env.example .env \
|
||||
&& chmod 777 ${QL_DIR}/shell/*.sh \
|
||||
&& chmod 777 ${QL_DIR}/docker/*.sh \
|
||||
&& git clone --depth=1 -b ${QL_BRANCH} https://github.com/${QL_MAINTAINER}/qinglong-static.git /static \
|
||||
&& mkdir -p ${QL_DIR}/static \
|
||||
&& cp -rf /static/* ${QL_DIR}/static \
|
||||
&& rm -rf /static
|
||||
RUN git clone --depth=1 -b ${QL_BRANCH} ${QL_URL} ${QL_DIR} && \
|
||||
cd ${QL_DIR} && \
|
||||
cp -f .env.example .env && \
|
||||
chmod 777 ${QL_DIR}/shell/*.sh && \
|
||||
chmod 777 ${QL_DIR}/docker/*.sh && \
|
||||
git clone --depth=1 -b ${QL_BRANCH} https://github.com/${QL_MAINTAINER}/qinglong-static.git /tmp/static && \
|
||||
mkdir -p ${QL_DIR}/static && \
|
||||
cp -rf /tmp/static/* ${QL_DIR}/static && \
|
||||
rm -rf /tmp/static
|
||||
|
||||
ENV PNPM_HOME=${QL_DIR}/data/dep_cache/node \
|
||||
PYTHON_HOME=${QL_DIR}/data/dep_cache/python3 \
|
||||
@@ -78,7 +95,9 @@ ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PNPM_HOM
|
||||
|
||||
RUN pip3 install --prefix ${PYTHON_HOME} requests
|
||||
|
||||
COPY --from=builder /tmp/build/node_modules/. /ql/node_modules/
|
||||
COPY --chown=qinglong:qinglong --from=builder /tmp/build/node_modules/. /ql/node_modules/
|
||||
|
||||
USER root
|
||||
|
||||
WORKDIR ${QL_DIR}
|
||||
|
||||
@@ -86,3 +105,7 @@ HEALTHCHECK --interval=5s --timeout=2s --retries=20 \
|
||||
CMD curl -sf --noproxy '*' http://127.0.0.1:5700/api/health || exit 1
|
||||
|
||||
ENTRYPOINT ["./docker/docker-entrypoint.sh"]
|
||||
|
||||
VOLUME /ql/data
|
||||
|
||||
EXPOSE 5700
|
||||
|
||||
+65
-42
@@ -1,13 +1,18 @@
|
||||
FROM python:3.11-alpine3.18 AS builder
|
||||
COPY package.json .npmrc pnpm-lock.yaml /tmp/build/
|
||||
RUN set -x \
|
||||
&& apk update \
|
||||
&& apk add nodejs npm git \
|
||||
&& npm i -g pnpm@8.3.1 pm2 ts-node \
|
||||
&& cd /tmp/build \
|
||||
&& pnpm install --prod
|
||||
FROM node:22-slim AS nodebuilder
|
||||
|
||||
FROM python:3.11-alpine
|
||||
FROM python:3.11-slim-bookworm AS builder
|
||||
COPY package.json .npmrc pnpm-lock.yaml /tmp/build/
|
||||
COPY --from=nodebuilder /usr/local/bin/node /usr/local/bin/
|
||||
COPY --from=nodebuilder /usr/local/lib/node_modules/. /usr/local/lib/node_modules/
|
||||
RUN set -x && \
|
||||
ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && \
|
||||
apt-get update && \
|
||||
apt-get install --no-install-recommends -y libatomic1 && \
|
||||
npm i -g pnpm@8.3.1 && \
|
||||
cd /tmp/build && \
|
||||
pnpm install --prod
|
||||
|
||||
FROM python:3.11-slim-bookworm
|
||||
|
||||
ARG QL_MAINTAINER="whyour"
|
||||
LABEL maintainer="${QL_MAINTAINER}"
|
||||
@@ -21,51 +26,63 @@ ENV QL_DIR=/ql \
|
||||
SHELL=/bin/bash \
|
||||
PS1="\u@\h:\w \$ "
|
||||
|
||||
VOLUME /ql/data
|
||||
|
||||
EXPOSE 5700
|
||||
ARG QL_UID=5432
|
||||
ARG QL_GID=5432
|
||||
RUN groupadd -g ${QL_GID} qinglong && \
|
||||
useradd -m -u ${QL_UID} -g ${QL_GID} -s /bin/bash qinglong && \
|
||||
mkdir -p /home/qinglong/bin /home/qinglong/.ssh && \
|
||||
chmod 700 /home/qinglong/.ssh && \
|
||||
chown -R ${QL_UID}:${QL_GID} /home/qinglong
|
||||
|
||||
COPY --from=builder /usr/local/lib/node_modules/. /usr/local/lib/node_modules/
|
||||
COPY --from=builder /usr/local/bin/. /usr/local/bin/
|
||||
ENV QL_USER=qinglong
|
||||
ENV QL_HOME=/home/$QL_USER
|
||||
|
||||
RUN set -x \
|
||||
&& apk update -f \
|
||||
&& apk upgrade \
|
||||
&& apk --no-cache add -f bash \
|
||||
coreutils \
|
||||
git \
|
||||
COPY --from=nodebuilder /usr/local/bin/node /usr/local/bin/
|
||||
COPY --from=nodebuilder /usr/local/lib/node_modules/. /usr/local/lib/node_modules/
|
||||
|
||||
RUN set -x && \
|
||||
ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && \
|
||||
ln -s /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx && \
|
||||
apt-get update && \
|
||||
apt-get upgrade -y && \
|
||||
apt-get install --no-install-recommends -y git \
|
||||
curl \
|
||||
wget \
|
||||
tzdata \
|
||||
perl \
|
||||
openssl \
|
||||
nodejs \
|
||||
openssh-client \
|
||||
jq \
|
||||
openssh \
|
||||
procps \
|
||||
netcat-openbsd \
|
||||
unzip \
|
||||
npm \
|
||||
&& rm -rf /var/cache/apk/* \
|
||||
&& apk update \
|
||||
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
|
||||
&& echo "Asia/Shanghai" > /etc/timezone \
|
||||
&& git config --global user.email "qinglong@users.noreply.github.com" \
|
||||
&& git config --global user.name "qinglong" \
|
||||
&& git config --global http.postBuffer 524288000 \
|
||||
&& rm -rf /root/.cache \
|
||||
&& ulimit -c 0
|
||||
libatomic1 && \
|
||||
apt-get clean && \
|
||||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
|
||||
echo "Asia/Shanghai" >/etc/timezone && \
|
||||
git config --global user.email "qinglong@users.noreply.github.com" && \
|
||||
git config --global user.name "qinglong" && \
|
||||
git config --global http.postBuffer 524288000 && \
|
||||
npm install -g pnpm@8.3.1 pm2 ts-node && \
|
||||
rm -rf /root/.cache && \
|
||||
rm -rf /root/.npm && \
|
||||
rm -rf /etc/apt/apt.conf.d/docker-clean && \
|
||||
ulimit -c 0
|
||||
|
||||
RUN mkdir -p ${QL_DIR} && \
|
||||
chown -R ${QL_UID}:${QL_GID} ${QL_DIR}
|
||||
|
||||
USER qinglong
|
||||
ARG SOURCE_COMMIT
|
||||
RUN git clone --depth=1 -b ${QL_BRANCH} ${QL_URL} ${QL_DIR} \
|
||||
&& cd ${QL_DIR} \
|
||||
&& cp -f .env.example .env \
|
||||
&& chmod 777 ${QL_DIR}/shell/*.sh \
|
||||
&& chmod 777 ${QL_DIR}/docker/*.sh \
|
||||
&& git clone --depth=1 -b ${QL_BRANCH} https://github.com/${QL_MAINTAINER}/qinglong-static.git /static \
|
||||
&& mkdir -p ${QL_DIR}/static \
|
||||
&& cp -rf /static/* ${QL_DIR}/static \
|
||||
&& rm -rf /static
|
||||
RUN git clone --depth=1 -b ${QL_BRANCH} ${QL_URL} ${QL_DIR} && \
|
||||
cd ${QL_DIR} && \
|
||||
cp -f .env.example .env && \
|
||||
chmod 777 ${QL_DIR}/shell/*.sh && \
|
||||
chmod 777 ${QL_DIR}/docker/*.sh && \
|
||||
git clone --depth=1 -b ${QL_BRANCH} https://github.com/${QL_MAINTAINER}/qinglong-static.git /tmp/static && \
|
||||
mkdir -p ${QL_DIR}/static && \
|
||||
cp -rf /tmp/static/* ${QL_DIR}/static && \
|
||||
rm -rf /tmp/static
|
||||
|
||||
ENV PNPM_HOME=${QL_DIR}/data/dep_cache/node \
|
||||
PYTHON_HOME=${QL_DIR}/data/dep_cache/python3 \
|
||||
@@ -78,7 +95,9 @@ ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PNPM_HOM
|
||||
|
||||
RUN pip3 install --prefix ${PYTHON_HOME} requests
|
||||
|
||||
COPY --from=builder /tmp/build/node_modules/. /ql/node_modules/
|
||||
COPY --chown=qinglong:qinglong --from=builder /tmp/build/node_modules/. /ql/node_modules/
|
||||
|
||||
USER root
|
||||
|
||||
WORKDIR ${QL_DIR}
|
||||
|
||||
@@ -86,3 +105,7 @@ HEALTHCHECK --interval=5s --timeout=2s --retries=20 \
|
||||
CMD curl -sf --noproxy '*' http://127.0.0.1:5700/api/health || exit 1
|
||||
|
||||
ENTRYPOINT ["./docker/docker-entrypoint.sh"]
|
||||
|
||||
VOLUME /ql/data
|
||||
|
||||
EXPOSE 5700
|
||||
|
||||
@@ -23,11 +23,11 @@ log_with_style() {
|
||||
if [ -f /etc/alpine-release ]; then
|
||||
if ! grep -q "^options ndots:0" /etc/resolv.conf 2>/dev/null; then
|
||||
echo "options ndots:0" >> /etc/resolv.conf
|
||||
log_with_style "INFO" "🔧 0. 已配置 DNS 解析优化 (ndots:0)"
|
||||
log_with_style "INFO" "🔧 已配置 DNS 解析优化 (ndots:0)"
|
||||
fi
|
||||
fi
|
||||
|
||||
log_with_style "INFO" "🚀 1. 检测配置文件..."
|
||||
log_with_style "INFO" "🚀 1. 检测配置文件..."
|
||||
load_ql_envs
|
||||
export_ql_envs
|
||||
. $dir_shell/env.sh
|
||||
@@ -41,16 +41,16 @@ log_with_style "INFO" "⚙️ 2. 启动 pm2 服务..."
|
||||
reload_pm2
|
||||
|
||||
if [[ $AutoStartBot == true ]]; then
|
||||
log_with_style "INFO" "🤖 3. 启动 bot..."
|
||||
log_with_style "INFO" "🤖 3. 启动 bot..."
|
||||
nohup ql bot >$dir_log/bot.log 2>&1 &
|
||||
fi
|
||||
|
||||
if [[ $EnableExtraShell == true ]]; then
|
||||
log_with_style "INFO" "🛠️ 4. 执行自定义脚本..."
|
||||
log_with_style "INFO" "🛠️ 4. 执行自定义脚本..."
|
||||
nohup ql extra >$dir_log/extra.log 2>&1 &
|
||||
fi
|
||||
|
||||
log_with_style "SUCCESS" "🎉 容器启动成功!"
|
||||
log_with_style "SUCCESS" "🎉 容器启动成功!"
|
||||
|
||||
crond -f >/dev/null
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ function run() {
|
||||
numParam,
|
||||
file_task_before,
|
||||
file_task_before_js,
|
||||
file_preload_js,
|
||||
dir_scripts,
|
||||
task_before,
|
||||
PREV_NODE_OPTIONS,
|
||||
@@ -41,13 +40,7 @@ function run() {
|
||||
const fileName = process.argv[1].replace(`${dir_scripts}/`, '');
|
||||
const tempFile = `/tmp/env_${process.pid}.json`;
|
||||
|
||||
// Export NODE_OPTIONS so task_before can use it for any node commands
|
||||
const nodeOptionsForBash = file_preload_js
|
||||
? ['-r', file_preload_js, PREV_NODE_OPTIONS].filter(Boolean).join(' ')
|
||||
: PREV_NODE_OPTIONS || '';
|
||||
|
||||
const commands = [
|
||||
`export NODE_OPTIONS="${nodeOptionsForBash}"`,
|
||||
`source ${file_task_before} ${fileName}`,
|
||||
task_before ? `eval '${task_before.replace(/'/g, "'\\''")}'` : null,
|
||||
`echo -e '${splitStr}'`,
|
||||
|
||||
@@ -44,19 +44,11 @@ def run():
|
||||
split_str = "__sitecustomize__"
|
||||
file_name = sys.argv[0].replace(f"{os.getenv('dir_scripts')}/", "")
|
||||
|
||||
# Get environment variables needed for PYTHONPATH
|
||||
dir_preload = os.getenv("dir_preload", "")
|
||||
dir_config = os.getenv("dir_config", "")
|
||||
|
||||
# 创建临时文件路径
|
||||
temp_file = f"/tmp/env_{os.getpid()}.json"
|
||||
|
||||
# Export PYTHONPATH so task_before can use it for any python commands
|
||||
pythonpath_for_bash = ':'.join(filter(None, [dir_preload, dir_config, prev_pythonpath]))
|
||||
|
||||
# 构建命令数组
|
||||
commands = [
|
||||
f'export PYTHONPATH="{pythonpath_for_bash}"',
|
||||
f'source {os.getenv("file_task_before")} {file_name}'
|
||||
]
|
||||
|
||||
|
||||
+3
-17
@@ -104,7 +104,7 @@
|
||||
"序号": "Number",
|
||||
"备注": "Remarks",
|
||||
"更新时间": "Update Time",
|
||||
"创建时间": "Created Time",
|
||||
"创建时间": "Creation Time",
|
||||
"确认删除依赖": "Confirm to delete the dependency",
|
||||
"确认重新安装": "Confirm to reinstall",
|
||||
"确认取消安装": "Confirm to cancel install",
|
||||
@@ -252,7 +252,7 @@
|
||||
"登录日志": "Login Logs",
|
||||
"其他设置": "Other Settings",
|
||||
"关于": "About",
|
||||
"成功": "Successfully",
|
||||
"成功": "Success",
|
||||
"失败": "Failure",
|
||||
"登录时间": "Login Time",
|
||||
"登录地址": "Login Address",
|
||||
@@ -538,19 +538,5 @@
|
||||
"单实例模式:定时启动新任务前会自动停止旧任务;多实例模式:允许同时运行多个任务实例": "Single instance mode: automatically stop old task before starting new scheduled task; Multi-instance mode: allow multiple task instances to run simultaneously",
|
||||
"请选择实例模式": "Please select instance mode",
|
||||
"单实例": "Single Instance",
|
||||
"多实例": "Multi-Instance",
|
||||
"SSH密钥": "SSH Keys",
|
||||
"别名": "Alias",
|
||||
"编辑SSH密钥": "Edit SSH Key",
|
||||
"创建SSH密钥": "Create SSH Key",
|
||||
"更新SSH密钥成功": "SSH key updated successfully",
|
||||
"创建SSH密钥成功": "SSH key created successfully",
|
||||
"请输入SSH密钥别名": "Please enter SSH key alias",
|
||||
"请输入SSH私钥": "Please enter SSH private key",
|
||||
"请输入SSH私钥内容(以 -----BEGIN 开头)": "Please enter SSH private key content (starts with -----BEGIN)",
|
||||
"确认删除SSH密钥": "Confirm to delete SSH key",
|
||||
"批量": "Batch",
|
||||
"全局SSH私钥": "Global SSH Private Key",
|
||||
"用于访问所有私有仓库的全局SSH私钥": "Global SSH private key for accessing all private repositories",
|
||||
"请输入完整的SSH私钥内容": "Please enter the complete SSH private key content"
|
||||
"多实例": "Multi-Instance"
|
||||
}
|
||||
|
||||
+1
-15
@@ -538,19 +538,5 @@
|
||||
"单实例模式:定时启动新任务前会自动停止旧任务;多实例模式:允许同时运行多个任务实例": "单实例模式:定时启动新任务前会自动停止旧任务;多实例模式:允许同时运行多个任务实例",
|
||||
"请选择实例模式": "请选择实例模式",
|
||||
"单实例": "单实例",
|
||||
"多实例": "多实例",
|
||||
"SSH密钥": "SSH密钥",
|
||||
"别名": "别名",
|
||||
"编辑SSH密钥": "编辑SSH密钥",
|
||||
"创建SSH密钥": "创建SSH密钥",
|
||||
"更新SSH密钥成功": "更新SSH密钥成功",
|
||||
"创建SSH密钥成功": "创建SSH密钥成功",
|
||||
"请输入SSH密钥别名": "请输入SSH密钥别名",
|
||||
"请输入SSH私钥": "请输入SSH私钥",
|
||||
"请输入SSH私钥内容(以 -----BEGIN 开头)": "请输入SSH私钥内容(以 -----BEGIN 开头)",
|
||||
"确认删除SSH密钥": "确认删除SSH密钥",
|
||||
"批量": "批量",
|
||||
"全局SSH私钥": "全局SSH私钥",
|
||||
"用于访问所有私有仓库的全局SSH私钥": "用于访问所有私有仓库的全局SSH私钥",
|
||||
"请输入完整的SSH私钥内容": "请输入完整的SSH私钥内容"
|
||||
"多实例": "多实例"
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ const dataMap = {
|
||||
'log-remove-frequency': 'logRemoveFrequency',
|
||||
'cron-concurrency': 'cronConcurrency',
|
||||
timezone: 'timezone',
|
||||
'global-ssh-key': 'globalSshKey',
|
||||
};
|
||||
|
||||
const exportModules = [
|
||||
@@ -55,7 +54,6 @@ const Other = ({
|
||||
logRemoveFrequency?: number | null;
|
||||
cronConcurrency?: number | null;
|
||||
timezone?: string | null;
|
||||
globalSshKey?: string | null;
|
||||
}>();
|
||||
const [form] = Form.useForm();
|
||||
const [exportLoading, setExportLoading] = useState(false);
|
||||
@@ -310,32 +308,6 @@ const Other = ({
|
||||
</Button>
|
||||
</Input.Group>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={intl.get('全局SSH私钥')}
|
||||
name="globalSshKey"
|
||||
tooltip={intl.get('用于访问所有私有仓库的全局SSH私钥')}
|
||||
>
|
||||
<Input.Group compact>
|
||||
<Input.TextArea
|
||||
value={systemConfig?.globalSshKey || ''}
|
||||
style={{ width: 264 }}
|
||||
autoSize={{ minRows: 3, maxRows: 8 }}
|
||||
placeholder={intl.get('请输入完整的SSH私钥内容')}
|
||||
onChange={(e) => {
|
||||
setSystemConfig({ ...systemConfig, globalSshKey: e.target.value });
|
||||
}}
|
||||
/>
|
||||
</Input.Group>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
updateSystemConfig('global-ssh-key');
|
||||
}}
|
||||
style={{ width: 264, marginTop: 8 }}
|
||||
>
|
||||
{intl.get('确认')}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
<Form.Item label={intl.get('语言')} name="lang">
|
||||
<Select
|
||||
defaultValue={localStorage.getItem('lang') || ''}
|
||||
|
||||
Reference in New Issue
Block a user