From 7728fbccfedb429ee4d92d7c7314823c0f521965 Mon Sep 17 00:00:00 2001 From: bjkim Date: Wed, 20 May 2026 17:06:44 +0900 Subject: [PATCH] chore: merge patched updates from patched folder --- Dockerfile_queenclient | 9 + default.conf | 3 +- kubernetes-aws.yaml | 56 +- .../atoms/organisms/AutoScriptDialog.vue | 1042 +++++++++++++++++ .../atoms/organisms/ScriptCompileDialog.vue | 430 +++++++ .../service/management/adminService.ts | 112 ++ src/pages/AdminPageWrapper.vue | 268 +++++ src/pages/AdminView.vue | 217 ++++ vite.config.mjs | 7 + 9 files changed, 2137 insertions(+), 7 deletions(-) create mode 100644 Dockerfile_queenclient create mode 100644 src/components/atoms/organisms/AutoScriptDialog.vue create mode 100644 src/components/atoms/organisms/ScriptCompileDialog.vue create mode 100644 src/components/service/management/adminService.ts create mode 100644 src/pages/AdminPageWrapper.vue create mode 100644 src/pages/AdminView.vue diff --git a/Dockerfile_queenclient b/Dockerfile_queenclient new file mode 100644 index 0000000..4fe1aef --- /dev/null +++ b/Dockerfile_queenclient @@ -0,0 +1,9 @@ +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/default.conf b/default.conf index a7bf56b..f861d9d 100644 --- a/default.conf +++ b/default.conf @@ -10,7 +10,8 @@ server { # 백엔드 API 프록시 location /autoflow-server-mgmt/ { - proxy_pass http://backend:8080; + proxy_pass http://autoflow-server-mgmt-svc:80; + proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; diff --git a/kubernetes-aws.yaml b/kubernetes-aws.yaml index ed3667d..c8a8030 100644 --- a/kubernetes-aws.yaml +++ b/kubernetes-aws.yaml @@ -2,7 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: autoflow-web - namespace: autoflow + namespace: etri-aisw spec: replicas: 1 selector: @@ -13,26 +13,70 @@ spec: labels: app: autoflow-web spec: + nodeSelector: + nodegroup: cpu containers: - name: autoflow-web - # [수정] 외부 레지스트리 주소를 제거하고 로컬 태그만 사용 image: autoflow-web:latest - # [추가] 외부에서 이미지를 다운로드하지 않고 로컬 이미지를 사용하도록 강제 imagePullPolicy: IfNotPresent ports: - containerPort: 80 + livenessProbe: + httpGet: + path: /autoflow/index.html + port: 80 + initialDelaySeconds: 30 + periodSeconds: 15 + readinessProbe: + httpGet: + path: /autoflow/index.html + port: 80 + initialDelaySeconds: 30 + periodSeconds: 15 --- apiVersion: v1 kind: Service metadata: name: autoflow-web-svc - namespace: autoflow + namespace: etri-aisw spec: - # Outpost EKS 환경에 따라 LoadBalancer 또는 NodePort를 선택하세요. - type: LoadBalancer selector: app: autoflow-web ports: - protocol: TCP port: 80 targetPort: 80 + type: ClusterIP +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: autoflow-web-ingress + namespace: etri-aisw + annotations: + alb.ingress.kubernetes.io/scheme: internet-facing + alb.ingress.kubernetes.io/target-type: ip + alb.ingress.kubernetes.io/backend-protocol: HTTP + # [수정 필요] 실제 서브넷 ID 및 보안 그룹 ID 입력 필요 + alb.ingress.kubernetes.io/subnets: subnet-xxxx, subnet-yyyy + alb.ingress.kubernetes.io/group.name: etri-group + alb.ingress.kubernetes.io/security-groups: sg-xxxx + alb.ingress.kubernetes.io/customer-owned-ipv4-pool: ipv4pool-xxxx + alb.ingress.kubernetes.io/healthcheck-protocol: HTTP + alb.ingress.kubernetes.io/healthcheck-path: /autoflow/index.html + alb.ingress.kubernetes.io/healthcheck-interval-seconds: "15" + alb.ingress.kubernetes.io/healthy-threshold-count: "2" + alb.ingress.kubernetes.io/unhealthy-threshold-count: "3" + alb.ingress.kubernetes.io/success-codes: "200" +spec: + ingressClassName: alb + rules: + - http: + paths: + - path: /autoflow + pathType: Prefix + backend: + service: + name: autoflow-web-svc + port: + number: 80 diff --git a/src/components/atoms/organisms/AutoScriptDialog.vue b/src/components/atoms/organisms/AutoScriptDialog.vue new file mode 100644 index 0000000..8c37039 --- /dev/null +++ b/src/components/atoms/organisms/AutoScriptDialog.vue @@ -0,0 +1,1042 @@ + + + + + diff --git a/src/components/atoms/organisms/ScriptCompileDialog.vue b/src/components/atoms/organisms/ScriptCompileDialog.vue new file mode 100644 index 0000000..615ef81 --- /dev/null +++ b/src/components/atoms/organisms/ScriptCompileDialog.vue @@ -0,0 +1,430 @@ + + + + + diff --git a/src/components/service/management/adminService.ts b/src/components/service/management/adminService.ts new file mode 100644 index 0000000..8d1fbc3 --- /dev/null +++ b/src/components/service/management/adminService.ts @@ -0,0 +1,112 @@ +import { request } from "@/components/service/index"; + +export type ServiceStatus = "ok" | "error" | "skip"; + +export interface ComponentStatus { + status: ServiceStatus; + message?: string; +} + +export interface PodStatusItem { + name: string | null; + phase: string | null; +} + +export interface PodStatus { + ok: boolean; + message: string; + running: number; + total: number; + pods?: PodStatusItem[]; +} + +export interface AdminStatusResponse { + kfp: ComponentStatus; + mlflow: ComponentStatus; + minio: ComponentStatus; + updatedAt?: string; +} + +export interface AdminPodStatusResponse { + namespace?: string; + kfp?: PodStatus; + mlflow?: PodStatus; + minio?: PodStatus; + updatedAt?: string; + message?: string; +} + +export interface RestartResponse { + success: boolean; + message: string; +} + +/** 상태 조회 타임아웃(ms). 백엔드 없을 때 오래 기다리지 않도록 */ +const STATUS_REQUEST_TIMEOUT_MS = 6_000; + +export const AdminService = { + getStatus: (): Promise<{ data: AdminStatusResponse }> => + request.get("/api/admin/status", {}, { timeout: STATUS_REQUEST_TIMEOUT_MS }), + + getPodStatus: (): Promise<{ data: AdminPodStatusResponse }> => + request.get("/api/admin/pods/status", {}, { timeout: STATUS_REQUEST_TIMEOUT_MS }), + + restart: (service: string): Promise<{ data: RestartResponse }> => + request.postNoParam(`/api/admin/restart/${encodeURIComponent(service)}`) as Promise<{ + data: RestartResponse; + }>, + + /** Run별 Pod 목록 (Executions 상세 로그 버튼용). 응답: { namespace, pods: [{ name, phase }], message } */ + getPodsByRunId: (runId: string) => + request.get("/api/admin/pods/by-run", { runId }, { timeout: 30_000 }), + + /** 응답은 axios response. 로그 텍스트는 response.data */ + getPodLog: (params: { + namespace: string; + pod: string; + container?: string; + tailLines?: number; + }) => + request.get("/api/admin/pods/logs", params as Record, { + timeout: 120_000, + responseType: "text", + }), + + /** + * Run 로그. 기본: KFP처럼 한 스텝(실패 우선). allSteps=true 이면 전체 스텝. + */ + getPodLogsByRunId: ( + runId: string, + opts?: { + tailLines?: number; + allSteps?: boolean; + podName?: string; + stepName?: string; + workflowName?: string; + workflowNamespace?: string; + }, + ) => { + const q: Record = { runId }; + if (opts?.tailLines !== undefined) q.tailLines = opts.tailLines; + if (opts?.allSteps) q.allSteps = true; + if (opts?.podName) q.podName = opts.podName; + if (opts?.stepName) q.stepName = opts.stepName; + if (opts?.workflowName) q.workflowName = opts.workflowName; + if (opts?.workflowNamespace) q.workflowNamespace = opts.workflowNamespace; + return request.get("/api/admin/pods/logs-by-run", q, { + timeout: 120_000, + responseType: "text", + }); + }, + + /** 관리자 Pod 카드: 같은 카드의 Pod 이름들 로그를 한 덩어리로 (pod 쿼리 반복) */ + getPodLogsAggregate: (namespace: string, podNames: string[], tailLines?: number) => { + const q = new URLSearchParams(); + q.set("namespace", namespace); + podNames.forEach((n) => { + if (n) q.append("pod", n); + }); + if (tailLines !== undefined) q.set("tailLines", String(tailLines)); + return request.get(`/api/admin/pods/logs-aggregate?${q.toString()}`, {}, { timeout: 120_000, responseType: "text" }); + }, +}; diff --git a/src/pages/AdminPageWrapper.vue b/src/pages/AdminPageWrapper.vue new file mode 100644 index 0000000..e75dd4b --- /dev/null +++ b/src/pages/AdminPageWrapper.vue @@ -0,0 +1,268 @@ + + + + + diff --git a/src/pages/AdminView.vue b/src/pages/AdminView.vue new file mode 100644 index 0000000..b667613 --- /dev/null +++ b/src/pages/AdminView.vue @@ -0,0 +1,217 @@ + + + + + diff --git a/vite.config.mjs b/vite.config.mjs index 3f08628..1f847c5 100644 --- a/vite.config.mjs +++ b/vite.config.mjs @@ -73,7 +73,14 @@ export default defineConfig({ }, server: { port: 3000, + proxy: { + "/autoflow-server-mgmt": { + target: "http://localhost:8080", + changeOrigin: true, + }, + }, }, + css: { preprocessorOptions: { sass: {