From 446d70d3dc9466b7f10219a3a6c95afb8a797ab9 Mon Sep 17 00:00:00 2001 From: Denozordec Date: Sat, 21 Mar 2026 01:27:26 +0700 Subject: [PATCH] =?UTF-8?q?docker:=20minimal=20runtime=20image=20=E2=80=94?= =?UTF-8?q?=20UI=20in=20devDeps,=20distroless=20final,=20slim=20bundle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Made-with: Cursor --- Dockerfile | 14 +++++++------- package-lock.json | 26 ++++++++++++++++++++------ package.json | 18 +++++++++--------- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/Dockerfile b/Dockerfile index bb4b881..0ffd9e3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1 -# Сборка фронта (devDependencies только здесь) +# Сборка фронта (все devDependencies + UI) FROM node:22-alpine AS build WORKDIR /app COPY package.json package-lock.json ./ @@ -11,7 +11,7 @@ COPY public ./public COPY src ./src RUN npm run build -# Production node_modules + server + dist +# Только runtime-deps: express, cors, sql.js (+ транзитивные) FROM node:22-alpine AS prod WORKDIR /app COPY package.json package-lock.json ./ @@ -20,17 +20,17 @@ RUN --mount=type=cache,target=/root/.npm \ COPY server ./server COPY --from=build /app/dist ./dist -# Слой приложения одним COPY в финальный образ (меньше слоёв в image) +# Артефакты без package.json / lock — не нужны для node server/index.js FROM node:22-alpine AS bundle WORKDIR /out COPY --from=prod /app/node_modules ./node_modules COPY --from=prod /app/server ./server COPY --from=prod /app/dist ./dist -COPY --from=prod /app/package.json ./package.json -FROM node:22-alpine +# Минимальный runtime (см. https://github.com/GoogleContainerTools/distroless/blob/main/nodejs/README.md) +FROM gcr.io/distroless/nodejs22-debian13:nonroot WORKDIR /app ENV NODE_ENV=production -COPY --from=bundle /out/ . +COPY --from=bundle --chown=nonroot:nonroot /out/ . EXPOSE 3001 -CMD ["node", "server/index.js"] +CMD ["server/index.js"] diff --git a/package-lock.json b/package-lock.json index a7dd084..3e14514 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,26 +8,26 @@ "name": "vps-tracker", "version": "0.0.0", "dependencies": { - "@tabler/core": "^1.4.0", - "@tabler/icons-react": "^3.40.0", - "chart.js": "^4.5.1", "cors": "^2.8.5", "express": "^4.21.1", - "react": "^19.2.0", - "react-dom": "^19.2.0", - "react-router-dom": "^7.13.1", "sql.js": "^1.14.0" }, "devDependencies": { "@eslint/js": "^9.39.1", + "@tabler/core": "^1.4.0", + "@tabler/icons-react": "^3.40.0", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.1", + "chart.js": "^4.5.1", "concurrently": "^9.1.0", "eslint": "^9.39.1", "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.24", "globals": "^16.5.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-router-dom": "^7.13.1", "vite": "^7.3.1" } }, @@ -1018,12 +1018,14 @@ "version": "0.3.4", "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==", + "dev": true, "license": "MIT" }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "dev": true, "license": "MIT", "funding": { "type": "opencollective", @@ -1391,6 +1393,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/@tabler/core/-/core-1.4.0.tgz", "integrity": "sha512-5BigzOlbOH9N0Is4u0rYNRCiwtnUXWO57K9zwuscygcicAa8UV9MGaS4zTgQsZEtZ9tsNANhN/YD8gCBGKYCiw==", + "dev": true, "license": "MIT", "dependencies": { "@popperjs/core": "^2.11.8", @@ -1408,6 +1411,7 @@ "version": "3.40.0", "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.40.0.tgz", "integrity": "sha512-V/Q4VgNPKubRTiLdmWjV/zscYcj5IIk+euicUtaVVqF6luSC9rDngYWgST5/yh3Mrg/mYUwRv1YVTk71Jp0twQ==", + "dev": true, "license": "MIT", "funding": { "type": "github", @@ -1418,6 +1422,7 @@ "version": "3.40.0", "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.40.0.tgz", "integrity": "sha512-oO5+6QCnna4a//mYubx4euZfECtzQZFDGsDMIdzZUhbdyBCT+3bRVFBPueGIcemWld4Vb/0UQ39C/cmGfGylAg==", + "dev": true, "license": "MIT", "dependencies": { "@tabler/icons": "3.40.0" @@ -1685,6 +1690,7 @@ "version": "5.3.7", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.7.tgz", "integrity": "sha512-7KgiD8UHjfcPBHEpDNg+zGz8L3LqR3GVwqZiBRFX04a1BCArZOz1r2kjly2HQ0WokqTO0v1nF+QAt8dsW4lKlw==", + "dev": true, "funding": [ { "type": "github", @@ -1835,6 +1841,7 @@ "version": "4.5.1", "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.1.tgz", "integrity": "sha512-GIjfiT9dbmHRiYi6Nl2yFCq7kkwdkp1W/lp2J99rX0yo9tgJGn3lKQATztIjb5tVtevcBtIdICNWqlq5+E8/Pw==", + "dev": true, "license": "MIT", "dependencies": { "@kurkle/color": "^0.3.0" @@ -1958,6 +1965,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -3408,6 +3416,7 @@ "version": "19.2.4", "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3417,6 +3426,7 @@ "version": "19.2.4", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "dev": true, "license": "MIT", "dependencies": { "scheduler": "^0.27.0" @@ -3439,6 +3449,7 @@ "version": "7.13.1", "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.13.1.tgz", "integrity": "sha512-td+xP4X2/6BJvZoX6xw++A2DdEi++YypA69bJUV5oVvqf6/9/9nNlD70YO1e9d3MyamJEBQFEzk6mbfDYbqrSA==", + "dev": true, "license": "MIT", "dependencies": { "cookie": "^1.0.1", @@ -3461,6 +3472,7 @@ "version": "7.13.1", "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.13.1.tgz", "integrity": "sha512-UJnV3Rxc5TgUPJt2KJpo1Jpy0OKQr0AjgbZzBFjaPJcFOb2Y8jA5H3LT8HUJAiRLlWrEXWHbF1Z4SCZaQjWDHw==", + "dev": true, "license": "MIT", "dependencies": { "react-router": "7.13.1" @@ -3578,6 +3590,7 @@ "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "dev": true, "license": "MIT" }, "node_modules/semver": { @@ -3648,6 +3661,7 @@ "version": "2.7.2", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "dev": true, "license": "MIT" }, "node_modules/setprototypeof": { diff --git a/package.json b/package.json index e35251c..7fbadc1 100644 --- a/package.json +++ b/package.json @@ -11,26 +11,26 @@ "preview": "vite preview" }, "dependencies": { - "@tabler/core": "^1.4.0", - "@tabler/icons-react": "^3.40.0", - "chart.js": "^4.5.1", - "react": "^19.2.0", - "react-dom": "^19.2.0", - "react-router-dom": "^7.13.1", - "sql.js": "^1.14.0", "cors": "^2.8.5", - "express": "^4.21.1" + "express": "^4.21.1", + "sql.js": "^1.14.0" }, "devDependencies": { "@eslint/js": "^9.39.1", + "@tabler/core": "^1.4.0", + "@tabler/icons-react": "^3.40.0", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.1", + "chart.js": "^4.5.1", + "concurrently": "^9.1.0", "eslint": "^9.39.1", "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-react-refresh": "^0.4.24", - "concurrently": "^9.1.0", "globals": "^16.5.0", + "react": "^19.2.0", + "react-dom": "^19.2.0", + "react-router-dom": "^7.13.1", "vite": "^7.3.1" } }