@whyour/qinglong 2.20.2-3 → 2.21.0-10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/.env.example +5 -0
  2. package/AGENTS.md +43 -0
  3. package/README-en.md +11 -0
  4. package/README.md +11 -0
  5. package/back/protos/api.proto +3 -0
  6. package/deploy/kubernetes/README.md +81 -0
  7. package/deploy/kubernetes/base/kustomization.yaml +5 -0
  8. package/deploy/kubernetes/base/qinglong.yaml +95 -0
  9. package/deploy/kubernetes/overlays/example/kustomization.yaml +10 -0
  10. package/docker/Dockerfile +51 -69
  11. package/docker/Dockerfile.310 +94 -0
  12. package/docker/Dockerfile.debian +120 -0
  13. package/docker/{310.Dockerfile → Dockerfile.debian310} +13 -5
  14. package/docker/docker-entrypoint.sh +95 -3
  15. package/docs/PROJECT_ARCHITECTURE.md +550 -0
  16. package/package.json +29 -28
  17. package/sample/config.sample.sh +19 -3
  18. package/sample/notify.js +145 -9
  19. package/sample/notify.py +110 -11
  20. package/shell/api.sh +51 -21
  21. package/shell/bot.sh +30 -16
  22. package/shell/check.sh +21 -19
  23. package/shell/lang/en.sh +105 -0
  24. package/shell/lang/zh.sh +105 -0
  25. package/shell/otask.sh +117 -28
  26. package/shell/preload/client.js +20 -2
  27. package/shell/preload/esm-loader.mjs +41 -0
  28. package/shell/preload/sitecustomize.js +36 -0
  29. package/shell/pub.sh +8 -8
  30. package/shell/rmlog.sh +5 -5
  31. package/shell/share.sh +50 -31
  32. package/shell/start.sh +40 -27
  33. package/shell/task.sh +10 -2
  34. package/shell/update.sh +22 -22
  35. package/static/build/api/config.js +17 -7
  36. package/static/build/api/cron.js +40 -3
  37. package/static/build/api/dashboard.js +344 -0
  38. package/static/build/api/env.js +40 -2
  39. package/static/build/api/index.js +2 -0
  40. package/static/build/api/log.js +15 -5
  41. package/static/build/api/script.js +34 -9
  42. package/static/build/api/system.js +22 -8
  43. package/static/build/api/user.js +6 -5
  44. package/static/build/app.js +22 -19
  45. package/static/build/config/const.js +8 -6
  46. package/static/build/config/container.js +12 -0
  47. package/static/build/config/grpcCerts.js +150 -0
  48. package/static/build/config/index.js +6 -4
  49. package/static/build/config/util.js +69 -18
  50. package/static/build/data/cron.js +3 -1
  51. package/static/build/data/cronStats.js +59 -0
  52. package/static/build/data/env.js +2 -0
  53. package/static/build/data/notify.js +18 -1
  54. package/static/build/data/runningInstance.js +57 -0
  55. package/static/build/data/sock.js +1 -0
  56. package/static/build/loaders/app.js +7 -7
  57. package/static/build/loaders/db.js +8 -2
  58. package/static/build/loaders/deps.js +1 -22
  59. package/static/build/loaders/express.js +19 -15
  60. package/static/build/loaders/initData.js +20 -2
  61. package/static/build/loaders/initFile.js +3 -1
  62. package/static/build/loaders/initTask.js +3 -2
  63. package/static/build/loaders/server.js +1 -1
  64. package/static/build/protos/api.js +23 -1
  65. package/static/build/schedule/addCron.js +67 -10
  66. package/static/build/schedule/api.js +1 -1
  67. package/static/build/schedule/client.js +9 -1
  68. package/static/build/schedule/delCron.js +11 -1
  69. package/static/build/schedule/health.js +1 -1
  70. package/static/build/services/config.js +19 -5
  71. package/static/build/services/cron.js +198 -38
  72. package/static/build/services/dependence.js +19 -18
  73. package/static/build/services/env.js +31 -3
  74. package/static/build/services/grpc.js +32 -6
  75. package/static/build/services/http.js +33 -18
  76. package/static/build/services/notify.js +87 -8
  77. package/static/build/services/open.js +2 -1
  78. package/static/build/services/sshKey.js +6 -3
  79. package/static/build/services/subscription.js +8 -5
  80. package/static/build/services/system.js +34 -9
  81. package/static/build/services/user.js +39 -13
  82. package/static/build/shared/auth.js +7 -1
  83. package/static/build/shared/i18n.js +160 -0
  84. package/static/build/shared/pLimit.js +15 -3
  85. package/static/build/shared/runCron.js +5 -0
  86. package/static/build/shared/store.js +7 -0
  87. package/static/build/validation/schedule.js +10 -0
  88. package/static/dist/1089.0ecc5383.async.js +1 -0
  89. package/static/dist/1147.62793604.async.js +1 -0
  90. package/static/dist/1192.4e5740f2.async.js +1 -0
  91. package/static/dist/1214.c6469b53.async.js +1 -0
  92. package/static/dist/134.54df9e38.async.js +1 -0
  93. package/static/dist/1352.96a77e1d.async.js +1 -0
  94. package/static/dist/{1765.d8e002d7.async.js → 1765.5ac01a93.async.js} +1 -1
  95. package/static/dist/1836.f0b74cf1.async.js +1 -0
  96. package/static/dist/{1885.e0d00d2d.async.js → 1885.e1ea09f6.async.js} +1 -1
  97. package/static/dist/1967.3f3945d0.async.js +1 -0
  98. package/static/dist/{2096.383c1047.async.js → 2096.6d98fd12.async.js} +1 -1
  99. package/static/dist/2208.85285476.async.js +1 -0
  100. package/static/dist/2286.f371c743.async.js +1 -0
  101. package/static/dist/2476.4e9b0992.async.js +1 -0
  102. package/static/dist/2537.2b262ee0.async.js +1 -0
  103. package/static/dist/{255.12f03ab2.async.js → 255.8a80b983.async.js} +1 -1
  104. package/static/dist/2635.d4c59d23.async.js +1 -0
  105. package/static/dist/2808.cdc0995c.async.js +1 -0
  106. package/static/dist/{2821.be3dc88e.async.js → 2821.651f31e5.async.js} +1 -1
  107. package/static/dist/2986.4c49eef7.async.js +1 -0
  108. package/static/dist/300.08ac9875.async.js +1 -0
  109. package/static/dist/3191.545ab873.async.js +1 -0
  110. package/static/dist/3714.8d6dba9e.async.js +1 -0
  111. package/static/dist/3906.a5eee612.async.js +1 -0
  112. package/static/dist/{6541.a6d499de.async.js → 3948.4fe809fd.async.js} +1 -1
  113. package/static/dist/{5171.7fc6d0a2.async.js → 4573.16f19278.async.js} +1 -1
  114. package/static/dist/{4859.93e63ea6.async.js → 4859.6592cebb.async.js} +1 -1
  115. package/static/dist/4887.8e3ae573.async.js +1 -0
  116. package/static/dist/{4902.54ecbdb5.async.js → 4902.555f92ab.async.js} +1 -1
  117. package/static/dist/{4934.1ca6b6b0.async.js → 4934.f3539d08.async.js} +1 -1
  118. package/static/dist/5077.cbd111cd.async.js +1 -0
  119. package/static/dist/{6247.b550d996.async.js → 5157.7c5af144.async.js} +1 -1
  120. package/static/dist/{540.481d4708.async.js → 540.19ddf020.async.js} +1 -1
  121. package/static/dist/{5970.10ac4f16.async.js → 5970.d3a6e7bd.async.js} +1 -1
  122. package/static/dist/{6013.2d7bb12a.async.js → 6013.4e38de36.async.js} +1 -1
  123. package/static/dist/{6016.9c379049.async.js → 6016.1e6574b6.async.js} +1 -1
  124. package/static/dist/{6035.5889ddc7.async.js → 6035.32ebfad9.async.js} +1 -1
  125. package/static/dist/6339.ab305e96.async.js +1 -0
  126. package/static/dist/6569.55177f6a.async.js +1 -0
  127. package/static/dist/6610.c111af7e.async.js +1 -0
  128. package/static/dist/{3034.6413c38e.async.js → 6638.87a163d2.async.js} +1 -1
  129. package/static/dist/{6646.5fc37228.async.js → 6646.95e92533.async.js} +1 -1
  130. package/static/dist/6665.1d099ad1.async.js +1 -0
  131. package/static/dist/{7355.b7c0562f.async.js → 7355.f9f263d8.async.js} +1 -1
  132. package/static/dist/{7384.065ccae2.async.js → 7384.1bb449d5.async.js} +1 -1
  133. package/static/dist/7441.ee1bf2bb.async.js +1 -0
  134. package/static/dist/{7508.a31662a3.async.js → 7508.7dcee91c.async.js} +1 -1
  135. package/static/dist/{7802.6b73f16a.async.js → 7802.34255805.async.js} +1 -1
  136. package/static/dist/{7984.e6bb9378.async.js → 7984.594296a5.async.js} +1 -1
  137. package/static/dist/{5653.4fce7ce8.async.js → 8033.5cb31493.async.js} +1 -1
  138. package/static/dist/8147.2fb55202.async.js +1 -0
  139. package/static/dist/8187.48c130d6.async.js +1 -0
  140. package/static/dist/8495.d53e15ca.async.js +1 -0
  141. package/static/dist/8587.315b06c0.async.js +1 -0
  142. package/static/dist/8826.db34ad8d.async.js +1 -0
  143. package/static/dist/{2742.4852aac8.async.js → 8865.ed665d31.async.js} +1 -1
  144. package/static/dist/901.7ee5c6d3.async.js +1 -0
  145. package/static/dist/9271.231db2ce.async.js +1 -0
  146. package/static/dist/9323.a33f47da.async.js +1 -0
  147. package/static/dist/{9730.30083c91.async.js → 9730.801665a3.async.js} +1 -1
  148. package/static/dist/{9761.627ca3b5.async.js → 9761.360a19d8.async.js} +1 -1
  149. package/static/dist/index.html +2 -2
  150. package/static/dist/layouts__index.a7a2bfe0.async.js +1 -0
  151. package/static/dist/layouts__index.adf0692f.chunk.css +1 -0
  152. package/static/dist/preload_helper.3048fe5b.js +1 -0
  153. package/static/dist/{src__pages__config__index.622b6ee8.async.js → src__pages__config__index.a22ff7dc.async.js} +1 -1
  154. package/static/dist/{src__pages__crontab__const.323d5124.async.js → src__pages__crontab__const.aba07deb.async.js} +1 -1
  155. package/static/dist/src__pages__crontab__detail.b98f0084.async.js +1 -0
  156. package/static/dist/src__pages__crontab__index.68e78a33.async.js +1 -0
  157. package/static/dist/{src__pages__crontab__logModal.5e6a4bf2.async.js → src__pages__crontab__logModal.831d5e4b.async.js} +1 -1
  158. package/static/dist/src__pages__crontab__modal.f7041c7c.async.js +1 -0
  159. package/static/dist/src__pages__crontab__type.d7af36e5.async.js +1 -0
  160. package/static/dist/{src__pages__crontab__viewCreateModal.ffcf7a24.async.js → src__pages__crontab__viewCreateModal.4d589f66.async.js} +1 -1
  161. package/static/dist/{src__pages__crontab__viewManageModal.c2724575.async.js → src__pages__crontab__viewManageModal.0e317746.async.js} +1 -1
  162. package/static/dist/src__pages__dashboard__index.58177357.async.js +1 -0
  163. package/static/dist/src__pages__dependence__index.b7bbc795.async.js +1 -0
  164. package/static/dist/{src__pages__dependence__logModal.f123e2ac.async.js → src__pages__dependence__logModal.0681830b.async.js} +1 -1
  165. package/static/dist/src__pages__dependence__modal.f7bb47ba.async.js +1 -0
  166. package/static/dist/src__pages__env__editNameModal.48715576.async.js +1 -0
  167. package/static/dist/src__pages__env__index.452cdc47.async.js +1 -0
  168. package/static/dist/src__pages__env__modal.e1234834.async.js +1 -0
  169. package/static/dist/src__pages__error__index.dedb2b90.async.js +1 -0
  170. package/static/dist/src__pages__initialization__index.22620a77.async.js +1 -0
  171. package/static/dist/src__pages__log__index.9c66639f.async.js +1 -0
  172. package/static/dist/{src__pages__login__index.cd6e3152.async.js → src__pages__login__index.8c813eb1.async.js} +1 -1
  173. package/static/dist/{src__pages__script__components__UnsupportedFilePreview__index.39074c68.async.js → src__pages__script__components__UnsupportedFilePreview__index.c347a13a.async.js} +1 -1
  174. package/static/dist/src__pages__script__editNameModal.532a3044.async.js +1 -0
  175. package/static/dist/src__pages__script__index.1fc20f22.async.js +1 -0
  176. package/static/dist/src__pages__script__renameModal.5cdde919.async.js +1 -0
  177. package/static/dist/src__pages__script__saveModal.5ffed35f.async.js +1 -0
  178. package/static/dist/src__pages__script__setting.1a82c6d7.async.js +1 -0
  179. package/static/dist/src__pages__setting__appModal.43b7758a.async.js +1 -0
  180. package/static/dist/src__pages__setting__checkUpdate.34d773f2.async.js +1 -0
  181. package/static/dist/src__pages__setting__dependence.9c04c79a.async.js +1 -0
  182. package/static/dist/src__pages__setting__index.7e070838.async.js +1 -0
  183. package/static/dist/src__pages__setting__notification.bac481c2.async.js +1 -0
  184. package/static/dist/src__pages__setting__other.707cfafe.async.js +1 -0
  185. package/static/dist/src__pages__setting__security.b7235753.async.js +1 -0
  186. package/static/dist/src__pages__setting__systemLog.b81a8c1d.async.js +1 -0
  187. package/static/dist/{src__pages__subscription__logModal.0caa7283.async.js → src__pages__subscription__logModal.3864b37f.async.js} +1 -1
  188. package/static/dist/src__pages__subscription__modal.562448e2.async.js +1 -0
  189. package/static/dist/{umi.ef8199a4.js → umi.a54a59f6.js} +1 -1
  190. package/version.yaml +33 -4
  191. package/sample/notify.py.save +0 -1010
  192. package/static/dist/105.85a5c47a.async.js +0 -1
  193. package/static/dist/1083.f86ce804.async.js +0 -1
  194. package/static/dist/1147.32f41a88.async.js +0 -1
  195. package/static/dist/1352.ab6da08e.async.js +0 -1
  196. package/static/dist/1690.f0290540.async.js +0 -1
  197. package/static/dist/1742.6cbe5aca.async.js +0 -1
  198. package/static/dist/2208.8e3a7325.async.js +0 -1
  199. package/static/dist/3191.70bc19db.async.js +0 -1
  200. package/static/dist/5312.74b95311.async.js +0 -1
  201. package/static/dist/5691.931f59c5.async.js +0 -1
  202. package/static/dist/6159.55cb068a.async.js +0 -1
  203. package/static/dist/7025.f4080d63.async.js +0 -1
  204. package/static/dist/739.6be5552a.async.js +0 -1
  205. package/static/dist/7571.4f6240b1.async.js +0 -1
  206. package/static/dist/786.59fc381c.async.js +0 -1
  207. package/static/dist/8317.c44c1ebd.async.js +0 -1
  208. package/static/dist/8826.0291edfd.async.js +0 -1
  209. package/static/dist/955.3c9481f7.async.js +0 -1
  210. package/static/dist/layouts__index.1fce90e0.chunk.css +0 -1
  211. package/static/dist/layouts__index.8dcf1576.async.js +0 -1
  212. package/static/dist/preload_helper.116a62f6.js +0 -1
  213. package/static/dist/src__pages__crontab__detail.b07f0c0a.async.js +0 -1
  214. package/static/dist/src__pages__crontab__index.2e2e1096.async.js +0 -1
  215. package/static/dist/src__pages__crontab__modal.4d8c2a22.async.js +0 -1
  216. package/static/dist/src__pages__crontab__type.db7c1858.async.js +0 -1
  217. package/static/dist/src__pages__dependence__index.3d87ceac.async.js +0 -1
  218. package/static/dist/src__pages__dependence__modal.631ffb5b.async.js +0 -1
  219. package/static/dist/src__pages__env__editNameModal.ff85ef8c.async.js +0 -1
  220. package/static/dist/src__pages__env__index.a0a2fece.async.js +0 -1
  221. package/static/dist/src__pages__env__modal.d1004662.async.js +0 -1
  222. package/static/dist/src__pages__error__index.1bc3c90b.async.js +0 -1
  223. package/static/dist/src__pages__initialization__index.8b1cbaf9.async.js +0 -1
  224. package/static/dist/src__pages__log__index.cf00c9af.async.js +0 -1
  225. package/static/dist/src__pages__script__editNameModal.53424d49.async.js +0 -1
  226. package/static/dist/src__pages__script__index.e65df827.async.js +0 -1
  227. package/static/dist/src__pages__script__renameModal.4bbe7fb1.async.js +0 -1
  228. package/static/dist/src__pages__script__saveModal.cf449f3c.async.js +0 -1
  229. package/static/dist/src__pages__script__setting.b345d59a.async.js +0 -1
  230. package/static/dist/src__pages__setting__appModal.03faec89.async.js +0 -1
  231. package/static/dist/src__pages__setting__checkUpdate.46efe057.async.js +0 -1
  232. package/static/dist/src__pages__setting__dependence.4495c7b6.async.js +0 -1
  233. package/static/dist/src__pages__setting__index.6919c399.async.js +0 -1
  234. package/static/dist/src__pages__setting__notification.d6a3884f.async.js +0 -1
  235. package/static/dist/src__pages__setting__other.0d931d6f.async.js +0 -1
  236. package/static/dist/src__pages__setting__security.91cb545f.async.js +0 -1
  237. package/static/dist/src__pages__setting__systemLog.1d433a48.async.js +0 -1
  238. package/static/dist/src__pages__subscription__modal.0b84f6cf.async.js +0 -1
@@ -0,0 +1,120 @@
1
+ FROM node:22-slim AS nodebuilder
2
+
3
+ FROM python:3.11-slim-bookworm AS builder
4
+ COPY package.json .npmrc pnpm-lock.yaml /tmp/build/
5
+ COPY --from=nodebuilder /usr/local/bin/node /usr/local/bin/
6
+ COPY --from=nodebuilder /usr/local/lib/node_modules/. /usr/local/lib/node_modules/
7
+ RUN set -x && \
8
+ ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && \
9
+ apt-get update && \
10
+ apt-get install --no-install-recommends -y libatomic1 && \
11
+ npm i -g pnpm@8.3.1 && \
12
+ cd /tmp/build && \
13
+ pnpm install --prod
14
+
15
+ FROM python:3.11-slim-bookworm
16
+
17
+ ARG QL_MAINTAINER="whyour"
18
+ LABEL maintainer="${QL_MAINTAINER}"
19
+ ARG QL_URL=https://github.com/${QL_MAINTAINER}/qinglong.git
20
+ ARG QL_BRANCH=develop
21
+ ARG PYTHON_SHORT_VERSION=3.11
22
+
23
+ ENV QL_DIR=/ql \
24
+ QL_BRANCH=${QL_BRANCH} \
25
+ QL_CONTAINER=true \
26
+ LANG=C.UTF-8 \
27
+ SHELL=/bin/bash \
28
+ PS1="\u@\h:\w \$ "
29
+
30
+ ARG QL_UID=5432
31
+ ARG QL_GID=5432
32
+ RUN groupadd -g ${QL_GID} qinglong && \
33
+ useradd -m -u ${QL_UID} -g ${QL_GID} -s /bin/bash qinglong && \
34
+ mkdir -p /home/qinglong/bin /home/qinglong/.ssh && \
35
+ chmod 700 /home/qinglong/.ssh && \
36
+ chown -R ${QL_UID}:${QL_GID} /home/qinglong && \
37
+ mkdir -p /etc/sudoers.d && \
38
+ echo 'qinglong ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/qinglong
39
+
40
+ ENV QL_USER=qinglong
41
+ ENV QL_HOME=/home/$QL_USER
42
+
43
+ COPY --from=nodebuilder /usr/local/bin/node /usr/local/bin/
44
+ COPY --from=nodebuilder /usr/local/lib/node_modules/. /usr/local/lib/node_modules/
45
+
46
+ RUN set -x && \
47
+ ln -s /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm && \
48
+ ln -s /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx && \
49
+ apt-get update && \
50
+ apt-get upgrade -y && \
51
+ apt-get install --no-install-recommends -y git \
52
+ curl \
53
+ wget \
54
+ tzdata \
55
+ perl \
56
+ openssl \
57
+ openssh-client \
58
+ jq \
59
+ procps \
60
+ netcat-openbsd \
61
+ sudo \
62
+ unzip \
63
+ libatomic1 && \
64
+ apt-get clean && \
65
+ ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
66
+ echo "Asia/Shanghai" >/etc/timezone && \
67
+ git config --global user.email "qinglong@users.noreply.github.com" && \
68
+ git config --global user.name "qinglong" && \
69
+ git config --global http.postBuffer 524288000 && \
70
+ npm install -g pnpm@8.3.1 pm2 ts-node && \
71
+ rm -rf /root/.cache && \
72
+ rm -rf /root/.npm && \
73
+ rm -rf /etc/apt/apt.conf.d/docker-clean && \
74
+ ulimit -c 0
75
+
76
+ RUN mkdir -p ${QL_DIR} && \
77
+ chown -R ${QL_UID}:${QL_GID} ${QL_DIR}
78
+
79
+ USER qinglong
80
+ ARG SOURCE_COMMIT
81
+ RUN git clone --depth=1 -b ${QL_BRANCH} ${QL_URL} ${QL_DIR} && \
82
+ cd ${QL_DIR} && \
83
+ cp -f .env.example .env && \
84
+ chmod 777 ${QL_DIR}/shell/*.sh && \
85
+ chmod 777 ${QL_DIR}/docker/*.sh && \
86
+ git clone --depth=1 -b ${QL_BRANCH} https://github.com/${QL_MAINTAINER}/qinglong-static.git /tmp/static && \
87
+ mkdir -p ${QL_DIR}/static && \
88
+ cp -rf /tmp/static/* ${QL_DIR}/static && \
89
+ rm -rf /tmp/static
90
+
91
+ ENV PNPM_HOME=${QL_DIR}/data/dep_cache/node \
92
+ PYTHON_HOME=${QL_DIR}/data/dep_cache/python3 \
93
+ PYTHONUSERBASE=${QL_DIR}/data/dep_cache/python3 \
94
+ HOME=/home/qinglong
95
+
96
+ ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PNPM_HOME}:${PYTHON_HOME}/bin:${HOME}/bin \
97
+ NODE_PATH=/usr/local/bin:/usr/local/lib/node_modules \
98
+ PIP_CACHE_DIR=${PYTHON_HOME}/pip \
99
+ PYTHONPATH=${PYTHON_HOME}:${PYTHON_HOME}/lib/python${PYTHON_SHORT_VERSION}:${PYTHON_HOME}/lib/python${PYTHON_SHORT_VERSION}/site-packages
100
+
101
+ RUN pip3 install --prefix ${PYTHON_HOME} requests
102
+
103
+ COPY --chown=qinglong:qinglong --from=builder /tmp/build/node_modules/. /ql/node_modules/
104
+
105
+ USER root
106
+
107
+ RUN ln -sf ${QL_DIR}/shell/task.sh /usr/local/bin/task \
108
+ && ln -sf ${QL_DIR}/shell/update.sh /usr/local/bin/ql \
109
+ && chmod +x /usr/local/bin/task /usr/local/bin/ql
110
+
111
+ WORKDIR ${QL_DIR}
112
+
113
+ HEALTHCHECK --interval=5s --timeout=2s --retries=20 \
114
+ CMD curl -sf --noproxy '*' http://localhost:${QlPort:-5700}/api/health || exit 1
115
+
116
+ ENTRYPOINT ["./docker/docker-entrypoint.sh"]
117
+
118
+ VOLUME /ql/data
119
+
120
+ EXPOSE 5700
@@ -22,6 +22,7 @@ ARG PYTHON_SHORT_VERSION=3.10
22
22
 
23
23
  ENV QL_DIR=/ql \
24
24
  QL_BRANCH=${QL_BRANCH} \
25
+ QL_CONTAINER=true \
25
26
  LANG=C.UTF-8 \
26
27
  SHELL=/bin/bash \
27
28
  PS1="\u@\h:\w \$ "
@@ -32,7 +33,9 @@ RUN groupadd -g ${QL_GID} qinglong && \
32
33
  useradd -m -u ${QL_UID} -g ${QL_GID} -s /bin/bash qinglong && \
33
34
  mkdir -p /home/qinglong/bin /home/qinglong/.ssh && \
34
35
  chmod 700 /home/qinglong/.ssh && \
35
- chown -R ${QL_UID}:${QL_GID} /home/qinglong
36
+ chown -R ${QL_UID}:${QL_GID} /home/qinglong && \
37
+ mkdir -p /etc/sudoers.d && \
38
+ echo 'qinglong ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/qinglong
36
39
 
37
40
  ENV QL_USER=qinglong
38
41
  ENV QL_HOME=/home/$QL_USER
@@ -54,6 +57,7 @@ RUN set -x && \
54
57
  jq \
55
58
  procps \
56
59
  netcat-openbsd \
60
+ sudo \
57
61
  unzip \
58
62
  libatomic1 && \
59
63
  apt-get clean && \
@@ -87,10 +91,10 @@ RUN git clone --depth=1 -b ${QL_BRANCH} ${QL_URL} ${QL_DIR} && \
87
91
  ENV PNPM_HOME=${QL_DIR}/data/dep_cache/node \
88
92
  PYTHON_HOME=${QL_DIR}/data/dep_cache/python3 \
89
93
  PYTHONUSERBASE=${QL_DIR}/data/dep_cache/python3 \
90
- HOME=/root
94
+ HOME=/home/qinglong
91
95
 
92
96
  ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:${PNPM_HOME}:${PYTHON_HOME}/bin:${HOME}/bin \
93
- NODE_PATH=/usr/local/bin:/usr/local/lib/node_modules:${PNPM_HOME}/global/5/node_modules \
97
+ NODE_PATH=/usr/local/bin:/usr/local/lib/node_modules \
94
98
  PIP_CACHE_DIR=${PYTHON_HOME}/pip \
95
99
  PYTHONPATH=${PYTHON_HOME}:${PYTHON_HOME}/lib/python${PYTHON_SHORT_VERSION}:${PYTHON_HOME}/lib/python${PYTHON_SHORT_VERSION}/site-packages
96
100
 
@@ -100,13 +104,17 @@ COPY --chown=qinglong:qinglong --from=builder /tmp/build/node_modules/. /ql/node
100
104
 
101
105
  USER root
102
106
 
107
+ RUN ln -sf ${QL_DIR}/shell/task.sh /usr/local/bin/task \
108
+ && ln -sf ${QL_DIR}/shell/update.sh /usr/local/bin/ql \
109
+ && chmod +x /usr/local/bin/task /usr/local/bin/ql
110
+
103
111
  WORKDIR ${QL_DIR}
104
112
 
105
113
  HEALTHCHECK --interval=5s --timeout=2s --retries=20 \
106
- CMD curl -sf --noproxy '*' http://127.0.0.1:5700/api/health || exit 1
114
+ CMD curl -sf --noproxy '*' http://localhost:${QlPort:-5700}/api/health || exit 1
107
115
 
108
116
  ENTRYPOINT ["./docker/docker-entrypoint.sh"]
109
117
 
110
118
  VOLUME /ql/data
111
-
119
+
112
120
  EXPOSE 5700
@@ -15,9 +15,68 @@ log_with_style() {
15
15
  printf "\n[%s] [%7s] %s\n" "${timestamp}" "${level}" "${message}"
16
16
  }
17
17
 
18
+ # ============================================
19
+ # 确保当前用户对 /ql 和 /ql/data 目录有写入权限
20
+ # /ql/data 是 Docker Volume 挂载点,权限可能与 /ql 不同,需单独检测
21
+ # ============================================
22
+ ensure_ql_permissions() {
23
+ local current_uid
24
+ local current_gid
25
+ current_uid=$(id -u)
26
+ current_gid=$(id -g)
27
+
28
+ if [ "$current_uid" -eq 0 ]; then
29
+ return 0
30
+ fi
31
+
32
+ # ---- 检查 /ql 目录 ----
33
+ if ! mkdir -p "$QL_DIR/.tmp" 2>/dev/null; then
34
+ if chown -R "$current_uid:$current_gid" "$QL_DIR" 2>/dev/null; then
35
+ log_with_style "INFO" "已修正 /ql 目录权限: UID=$current_uid GID=$current_gid"
36
+ else
37
+ local ql_owner
38
+ ql_owner=$(stat -c '%u' "$QL_DIR" 2>/dev/null || stat -f '%u' "$QL_DIR" 2>/dev/null)
39
+ log_with_style "ERROR" "============================================="
40
+ log_with_style "ERROR" " 权限错误:无法写入 /ql 目录"
41
+ log_with_style "ERROR" " 当前用户 UID: $current_uid"
42
+ log_with_style "ERROR" " /ql 目录所有者 UID: ${ql_owner:-未知}"
43
+ log_with_style "ERROR" ""
44
+ log_with_style "ERROR" " 解决方案:"
45
+ log_with_style "ERROR" " 1. 使用镜像内置用户: docker run --user ${ql_owner:-5432}:${ql_owner:-5432} ..."
46
+ log_with_style "ERROR" " 2. 使用 root 运行: 移除 --user 参数"
47
+ log_with_style "ERROR" " 3. 修正宿主机数据目录: chown -R $current_uid:$current_gid /path/to/ql/data"
48
+ log_with_style "ERROR" "============================================="
49
+ exit 1
50
+ fi
51
+ fi
52
+ rmdir "$QL_DIR/.tmp" 2>/dev/null || true
53
+
54
+ # ---- 检查 /ql/data 目录(Volume 挂载点,不在用户数据卷内创建临时文件) ----
55
+ if [ ! -w "$QL_DIR/data" ] || [ ! -x "$QL_DIR/data" ]; then
56
+ if chown "$current_uid:$current_gid" "$QL_DIR/data" 2>/dev/null; then
57
+ log_with_style "INFO" "已修正 /ql/data 目录权限: UID=$current_uid GID=$current_gid"
58
+ if [ ! -w "$QL_DIR/data" ] || [ ! -x "$QL_DIR/data" ]; then
59
+ log_with_style "ERROR" "修正后仍无法写入 /ql/data,请检查挂载的数据卷权限"
60
+ log_with_style "ERROR" "确保宿主机目录: chown -R $current_uid:$current_gid /your/data"
61
+ exit 1
62
+ fi
63
+ else
64
+ local data_owner
65
+ data_owner=$(stat -c '%u' "$QL_DIR/data" 2>/dev/null || stat -f '%u' "$QL_DIR/data" 2>/dev/null)
66
+ log_with_style "ERROR" "============================================="
67
+ log_with_style "ERROR" " 权限错误:无法写入 /ql/data (Volume 挂载点)"
68
+ log_with_style "ERROR" " 当前用户 UID: $current_uid"
69
+ log_with_style "ERROR" " /ql/data 所有者 UID: ${data_owner:-未知}"
70
+ log_with_style "ERROR" ""
71
+ log_with_style "ERROR" " 请修正宿主机数据目录权限:"
72
+ log_with_style "ERROR" " chown -R $current_uid:$current_gid /your/ql/data"
73
+ log_with_style "ERROR" "============================================="
74
+ exit 1
75
+ fi
76
+ fi
77
+ }
78
+
18
79
  # Fix DNS resolution issues in Alpine Linux
19
- # Alpine uses musl libc which has known DNS resolver issues with certain domains
20
- # Adding ndots:0 prevents unnecessary search domain appending
21
80
  if [ -f /etc/alpine-release ]; then
22
81
  if ! grep -q "^options ndots:0" /etc/resolv.conf 2>/dev/null; then
23
82
  echo "options ndots:0" >> /etc/resolv.conf
@@ -25,6 +84,26 @@ if [ -f /etc/alpine-release ]; then
25
84
  fi
26
85
  fi
27
86
 
87
+ # 确保 /etc/hosts 包含 localhost 解析(应对精简镜像或仅 IPv4/IPv6 环境)
88
+ if ! grep -qE '^127\.0\.0\.1[[:space:]]+.*localhost' /etc/hosts 2>/dev/null; then
89
+ echo "127.0.0.1 localhost" >> /etc/hosts
90
+ log_with_style "INFO" "🔧 0. 已添加 IPv4 localhost 解析"
91
+ fi
92
+ if ! grep -qE '^::1[[:space:]]+.*localhost' /etc/hosts 2>/dev/null; then
93
+ echo "::1 localhost ip6-localhost ip6-loopback" >> /etc/hosts
94
+ log_with_style "INFO" "🔧 0. 已添加 IPv6 localhost 解析"
95
+ fi
96
+
97
+ # 自定义用户(非 qinglong/root)可能 HOME 为空或不可写
98
+ # 修正 HOME 确保 npm/pip/pm2 等工具有可用的缓存目录
99
+ if [ ! -w "$HOME" ]; then
100
+ mkdir -p "$QL_DIR/.tmp"
101
+ export HOME="$QL_DIR/.tmp"
102
+ fi
103
+
104
+ # 在一切操作之前检查目录权限
105
+ ensure_ql_permissions
106
+
28
107
  log_with_style "INFO" "🚀 1. 检测配置文件..."
29
108
  load_ql_envs
30
109
  export_ql_envs
@@ -50,6 +129,19 @@ fi
50
129
 
51
130
  log_with_style "SUCCESS" "🎉 容器启动成功!"
52
131
 
53
- tail -f /dev/null
132
+ # 自动检测调度模式:有 crond 二进制 → system 模式,否则 node 模式
133
+ if [ -z "$QL_SCHEDULER" ]; then
134
+ if command -v crond &>/dev/null; then
135
+ export QL_SCHEDULER="system"
136
+ else
137
+ export QL_SCHEDULER="node"
138
+ fi
139
+ fi
140
+
141
+ if [ "$QL_SCHEDULER" = "system" ]; then
142
+ crond -f > /dev/null
143
+ else
144
+ tail -f /dev/null
145
+ fi
54
146
 
55
147
  exec "$@"