From cae77e2a1263a2a63a49f8c111ea10cd19152228 Mon Sep 17 00:00:00 2001 From: bjkim Date: Mon, 13 Apr 2026 11:21:02 +0900 Subject: [PATCH] =?UTF-8?q?=EC=8A=A4=ED=86=A0=EB=A6=AC=EC=A7=80=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20?= =?UTF-8?q?=EA=B8=B0=EC=A1=B4=20MinIO=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=EC=A0=84=ED=99=98,=20=EB=B0=B0=ED=8F=AC=20=EB=B0=8F=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=ED=8C=8C=EC=9D=BC=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.prod | 2 +- Dockerfile_queenclient | 9 -- kubernetes-aws.yaml | 38 ++++++ package-lock.json | 127 +----------------- .../atoms/organisms/DeploymentDialog.vue | 10 +- .../management/ExternalAuthController.ts | 2 +- .../ExternalAuthControllerService.ts | 4 +- .../service/management/StorageService.ts | 22 +++ .../run/executions/ViewComponent.vue | 4 +- 9 files changed, 72 insertions(+), 146 deletions(-) delete mode 100644 Dockerfile_queenclient create mode 100644 kubernetes-aws.yaml create mode 100644 src/components/service/management/StorageService.ts diff --git a/.env.prod b/.env.prod index fa9edf1..014d35c 100644 --- a/.env.prod +++ b/.env.prod @@ -1,3 +1,3 @@ NODE_ENV = "prod" -VITE_APP_API_SERVER_URL = "http://cuuva.com:2481/autoflow-server-mgmt" +VITE_APP_API_SERVER_URL = "/autoflow-server-mgmt" VITE_ROOT_PATH = "/autoflow" \ No newline at end of file diff --git a/Dockerfile_queenclient b/Dockerfile_queenclient deleted file mode 100644 index 4fe1aef..0000000 --- a/Dockerfile_queenclient +++ /dev/null @@ -1,9 +0,0 @@ -FROM nginx:stable-alpine - -RUN apk --no-cache add tzdata && cp /usr/share/zoneinfo/Asia/Seoul /etc/localtime - -COPY default.conf /etc/nginx/conf.d/default.conf - -COPY dist/. /usr/share/nginx/html/autoflow -EXPOSE 80 -ENTRYPOINT ["nginx", "-g", "daemon off;"] diff --git a/kubernetes-aws.yaml b/kubernetes-aws.yaml new file mode 100644 index 0000000..ed3667d --- /dev/null +++ b/kubernetes-aws.yaml @@ -0,0 +1,38 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: autoflow-web + namespace: autoflow +spec: + replicas: 1 + selector: + matchLabels: + app: autoflow-web + template: + metadata: + labels: + app: autoflow-web + spec: + containers: + - name: autoflow-web + # [수정] 외부 레지스트리 주소를 제거하고 로컬 태그만 사용 + image: autoflow-web:latest + # [추가] 외부에서 이미지를 다운로드하지 않고 로컬 이미지를 사용하도록 강제 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 80 +--- +apiVersion: v1 +kind: Service +metadata: + name: autoflow-web-svc + namespace: autoflow +spec: + # Outpost EKS 환경에 따라 LoadBalancer 또는 NodePort를 선택하세요. + type: LoadBalancer + selector: + app: autoflow-web + ports: + - protocol: TCP + port: 80 + targetPort: 80 diff --git a/package-lock.json b/package-lock.json index a7f125a..dbde56f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -873,59 +873,12 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", - "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.10.tgz", - "integrity": "sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "license": "MIT" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.29", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", - "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "node_modules/@jsdevtools/ono": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz", @@ -1321,17 +1274,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/node": { - "version": "24.0.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.12.tgz", - "integrity": "sha512-LtOrbvDf5ndC9Xi+4QZjVL0woFymF/xSTKZKPgrrl7H7XoeDvnD+E2IclKVDyaK9UM756W/3BXqSU+JEHopA9g==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "undici-types": "~7.8.0" - } - }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", @@ -2082,7 +2024,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -2327,14 +2269,6 @@ "devOptional": true, "license": "MIT/X11" }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/builtin-modules": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.0.0.tgz", @@ -2535,14 +2469,6 @@ "node": ">= 0.8" } }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/comment-parser": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", @@ -5540,17 +5466,6 @@ "dev": true, "license": "MIT" }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -5560,18 +5475,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, "node_modules/spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -5742,26 +5645,6 @@ "url": "https://opencollective.com/synckit" } }, - "node_modules/terser": { - "version": "5.43.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", - "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", - "license": "BSD-2-Clause", - "optional": true, - "peer": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.14.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/tinyexec": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", @@ -5890,14 +5773,6 @@ "dev": true, "license": "MIT" }, - "node_modules/undici-types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", - "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/unicorn-magic": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", diff --git a/src/components/atoms/organisms/DeploymentDialog.vue b/src/components/atoms/organisms/DeploymentDialog.vue index d2f7baf..db01c1e 100644 --- a/src/components/atoms/organisms/DeploymentDialog.vue +++ b/src/components/atoms/organisms/DeploymentDialog.vue @@ -3,13 +3,13 @@ import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue"; import { ExternalAuthControllerService } from "@/components/service/management/ExternalAuthControllerService"; import { AddFileParamsSwagger, - AddMinioParamsSwagger, + AddStorageParamsSwagger, EdgePkgInfoVOModel, } from "@/components/models/management/ExternalAuthController"; type PackageOption = { label: string; value: string; raw: any }; -type MinioRegisterModel = EdgePkgInfoVOModel & { +type StorageRegisterModel = EdgePkgInfoVOModel & { objectName: string; type: "type1" | "type2"; localPath: string; @@ -227,7 +227,7 @@ const toInt = (v: unknown, fallback = 1) => { const n = parseInt(String(v ?? "").trim(), 10); return Number.isFinite(n) ? n : fallback; }; -const minioType = ref<"type1" | "type2">("type2"); +const storageType = ref<"type1" | "type2">("type2"); async function submit() { errorMsg.value = ""; @@ -291,10 +291,10 @@ async function submit() { const params: AddMinioParamsSwagger = { ...common, objectName: props.artifactPath || "", - type: minioType.value, + type: storageType.value, localPath: (form.value.install_location || "").trim(), }; - res = await ExternalAuthControllerService.addMinio(params); + res = await ExternalAuthControllerService.addStorage(params); } const ok = diff --git a/src/components/models/management/ExternalAuthController.ts b/src/components/models/management/ExternalAuthController.ts index 39a1ca9..b89bbb9 100644 --- a/src/components/models/management/ExternalAuthController.ts +++ b/src/components/models/management/ExternalAuthController.ts @@ -28,7 +28,7 @@ export type AddFileParamsSwagger = { creation_datetime: string; }; -export type AddMinioParamsSwagger = AddFileParamsSwagger & { +export type AddStorageParamsSwagger = AddFileParamsSwagger & { objectName: string; type: "type1" | "type2"; localPath: string; diff --git a/src/components/service/management/ExternalAuthControllerService.ts b/src/components/service/management/ExternalAuthControllerService.ts index 7662932..f7520bc 100644 --- a/src/components/service/management/ExternalAuthControllerService.ts +++ b/src/components/service/management/ExternalAuthControllerService.ts @@ -1,6 +1,6 @@ import { AddFileParamsSwagger, - AddMinioParamsSwagger, + AddStorageParamsSwagger, } from "@/components/models/management/ExternalAuthController"; import { request } from "@/components/service/index"; @@ -20,7 +20,7 @@ export const ExternalAuthControllerService = { }); }, - addMinio: (params: AddMinioParamsSwagger) => { + addStorage: (params: AddStorageParamsSwagger) => { return request.postWithConfig( "/api/external-auth/register-with-minio-file", {}, diff --git a/src/components/service/management/StorageService.ts b/src/components/service/management/StorageService.ts new file mode 100644 index 0000000..f215b82 --- /dev/null +++ b/src/components/service/management/StorageService.ts @@ -0,0 +1,22 @@ +import { request } from "@/components/service/index"; + +import { saveBlob, filenameFromContentDisposition } from "@/utils/download"; + +/** + * 전역 스토리지 서비스 (MinIO, S3, FileSystem 통합 지원) + */ +export const StorageService = { + async download(objectName: string) { + const res = await request.getFile("/api/minio/download", { + objectName, + type: "type2", // Mlflow artifacts 등 대용량 다운로드용 + }); + + const blob: Blob = res.data; + const cd = res.headers?.["content-disposition"]; + const fallback = objectName.split("/").pop() || "download.bin"; + const filename = filenameFromContentDisposition(cd, fallback); + + saveBlob(blob, filename); + }, +}; diff --git a/src/components/templates/run/executions/ViewComponent.vue b/src/components/templates/run/executions/ViewComponent.vue index 6bd9143..e3ef781 100644 --- a/src/components/templates/run/executions/ViewComponent.vue +++ b/src/components/templates/run/executions/ViewComponent.vue @@ -13,7 +13,7 @@ import { import Plotly from "plotly.js-dist-min"; import CompareRunsDialog from "@/components/atoms/organisms/CompareRunDialog.vue"; import DeploymentDialog from "@/components/atoms/organisms/DeploymentDialog.vue"; -import { MinioService } from "@/components/service/management/MinioService"; +import { StorageService } from "@/components/service/management/StorageService"; import IconDownloadBtn from "@/components/atoms/button/IconDownloadBtn.vue"; import IconDeployBtn from "@/components/atoms/button/IconDeployBtn.vue"; @@ -293,7 +293,7 @@ async function onClickArtifact(fullPath: string) { const objectName = buildArtifactUri(fullPath); try { artifactsLoading.value = true; - await MinioService.download(objectName); + await StorageService.download(objectName); } finally { artifactsLoading.value = false; }