From 0928291c9be395026a22ddf2b7c6a333ef9134c9 Mon Sep 17 00:00:00 2001 From: bjkim Date: Thu, 7 May 2026 16:32:39 +0900 Subject: [PATCH] =?UTF-8?q?[ADD]=20AWS=20Outposts=20EKS=20=EB=B0=B0?= =?UTF-8?q?=ED=8F=AC=20=EA=B0=80=EC=9D=B4=EB=93=9C=20=EB=B0=8F=20MariaDB?= =?UTF-8?q?=20=EC=B4=88=EA=B8=B0=ED=99=94=20SQL=20ConfigMap=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80,=20Kubernetes=20=EB=A7=A4=EB=8B=88=ED=8E=98=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=B0=8F=20=EB=A1=9C=EC=BB=AC=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=84=A4=EC=A0=95=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- deployment_guide.md | 87 +++++ kubernetes-aws.yaml | 91 ++++- mariadb-init-configmap.yaml | 324 ++++++++++++++++++ .../resources/application-local.properties | 16 +- 4 files changed, 511 insertions(+), 7 deletions(-) create mode 100644 deployment_guide.md create mode 100644 mariadb-init-configmap.yaml diff --git a/deployment_guide.md b/deployment_guide.md new file mode 100644 index 0000000..137b90c --- /dev/null +++ b/deployment_guide.md @@ -0,0 +1,87 @@ +# AWS Outposts EKS 배포 가이드 (AutoFlow) + +본 가이드는 AutoFlow 서버(Spring Boot), 웹 콘솔(Vue.js), 그리고 MariaDB를 AWS Outposts EKS 환경에 배포하는 절차를 설명합니다. + +--- + +## 1. 사전 준비 사항 + +### 1-1. 네임스페이스 생성 +모든 리소스는 `etri-aisw` 네임스페이스에 배포됩니다. +```bash +kubectl create namespace etri-aisw +``` + +### 1-2. ECR 이미지 푸시 +빌드된 이미지를 AWS ECR 레포지토리에 푸시합니다. +- **Server**: `{AWS_ACCOUNT_ID}.dkr.ecr.{REGION}.amazonaws.com/autoflow-server:latest` +- **Web**: `{AWS_ACCOUNT_ID}.dkr.ecr.{REGION}.amazonaws.com/autoflow-web:latest` + +--- + +## 2. 매니페스트 파일 수정 + +배포 전 `kubernetes-aws.yaml` 파일의 아래 항목들을 실제 환경에 맞게 수정해야 합니다. + +### 2-1. 이미지 경로 수정 +`spec.template.spec.containers.image` 항목을 위에서 푸시한 ECR 경로로 변경합니다. + +### 2-2. ALB(Ingress) 주석 수정 +Ingress 리소스의 `annotations` 섹션에서 다음 값을 수정합니다. +- `alb.ingress.kubernetes.io/subnets`: 실제 서브넷 ID들 +- `alb.ingress.kubernetes.io/security-groups`: 실제 보안 그룹 ID +- `alb.ingress.kubernetes.io/customer-owned-ipv4-pool`: 실제 CoIP 풀 ID + +--- + +## 3. 리소스 배포 절차 + +### 단계 1: MariaDB 초기화 SQL 배포 +데이터베이스 스키마 자동 생성을 위해 ConfigMap을 먼저 배포합니다. +```bash +kubectl apply -f mariadb-init-configmap.yaml +``` + +### 단계 2: 통합 리소스 배포 +MariaDB(PVC, Deployment, Service), Server(Deployment, Service, Ingress), Secret 등을 한 번에 배포합니다. +```bash +kubectl apply -f kubernetes-aws.yaml +``` + +### 단계 3: 웹 콘솔 배포 (선택 사항) +웹 콘솔 프로젝트 디렉토리로 이동하여 배포를 수행합니다. +```bash +cd ../autoflow-web-console +kubectl apply -f kubernetes-aws.yaml +``` + +--- + +## 4. 배포 확인 및 검증 + +### 4-1. Pod 상태 확인 +모든 Pod가 `Running` 상태인지 확인합니다. +```bash +kubectl get pods -n etri-aisw +``` + +### 4-2. 서비스 및 인그레스 주소 확인 +ALB 외장 주소(ADDRESS)가 할당되었는지 확인합니다. +```bash +kubectl get ingress -n etri-aisw +``` + +### 4-3. MariaDB 초기화 확인 +MariaDB 로그를 통해 SQL 스크립트가 정상 실행되었는지 확인합니다. +```bash +kubectl logs -n etri-aisw -l app=mariadb +``` + +--- + +## 5. 문제 해결 (Troubleshooting) + +- **Pod Pending**: `cpu` 노드 그룹의 자원이 부족하거나 `nodeSelector`가 일치하지 않는지 확인하세요. +- **ImagePullBackOff**: ECR 접근 권한(IAM Role) 또는 이미지 경로를 확인하세요. +- **503 Service Temporarily Unavailable**: ALB의 헬스체크 경로(`/autoflow-server-mgmt/actuator/health`)가 정상 응답(200 OK)을 주는지 확인하세요. +- **DB 접속 에러**: `RDS_HOSTNAME`이 `mariadb-svc`로 올바르게 설정되었는지 확인하세요. diff --git a/kubernetes-aws.yaml b/kubernetes-aws.yaml index 8a96919..455befb 100644 --- a/kubernetes-aws.yaml +++ b/kubernetes-aws.yaml @@ -1,8 +1,18 @@ +apiVersion: v1 +kind: Secret +metadata: + name: autoflow-secrets + namespace: etri-aisw +type: Opaque +stringData: + rds-password: "cuuva" + jwt-secret: "275511b31c520562d69802ce4a913773102563891563a24062f44b3f312ca2bd034440e81836d1b4ccf4195f43db4c81a4e489a41f1ae0967afe468c9a361f4d" +--- apiVersion: apps/v1 kind: Deployment metadata: name: autoflow-server - namespace: etri + namespace: etri-aisw spec: replicas: 1 selector: @@ -23,9 +33,9 @@ spec: - containerPort: 8080 env: - name: RDS_HOSTNAME - value: "INTERNAL_RDS_IP_HERE" + value: "mariadb-svc" - name: RDS_USERNAME - value: "admin" + value: "cuuva" - name: RDS_PASSWORD valueFrom: secretKeyRef: @@ -62,7 +72,7 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: name: autoflow-storage-pvc - namespace: etri + namespace: etri-aisw spec: accessModes: - ReadWriteOnce @@ -75,7 +85,7 @@ apiVersion: v1 kind: Service metadata: name: autoflow-server-svc - namespace: etri + namespace: etri-aisw spec: selector: app: autoflow-server @@ -85,6 +95,77 @@ spec: targetPort: 8080 type: ClusterIP --- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mariadb + namespace: etri-aisw +spec: + replicas: 1 + selector: + matchLabels: + app: mariadb + template: + metadata: + labels: + app: mariadb + spec: + nodeSelector: + nodegroup: cpu + containers: + - name: mariadb + image: mariadb:10.5 + ports: + - containerPort: 3306 + env: + - name: MYSQL_ROOT_PASSWORD + value: "root_password" + - name: MYSQL_DATABASE + value: "autoflow" + - name: MYSQL_USER + value: "cuuva" + - name: MYSQL_PASSWORD + value: "cuuva" + volumeMounts: + - name: mariadb-data + mountPath: /var/lib/mysql + - name: init-sql + mountPath: /docker-entrypoint-initdb.d + volumes: + - name: mariadb-data + persistentVolumeClaim: + claimName: mariadb-pvc + - name: init-sql + configMap: + name: mariadb-init-sql +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mariadb-pvc + namespace: etri-aisw +spec: + accessModes: + - ReadWriteOnce + storageClassName: gp2 + resources: + requests: + storage: 20Gi +--- +apiVersion: v1 +kind: Service +metadata: + name: mariadb-svc + namespace: etri +spec: + selector: + app: mariadb + ports: + - protocol: TCP + port: 3306 + targetPort: 3306 + type: ClusterIP +--- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: diff --git a/mariadb-init-configmap.yaml b/mariadb-init-configmap.yaml new file mode 100644 index 0000000..b81c5ca --- /dev/null +++ b/mariadb-init-configmap.yaml @@ -0,0 +1,324 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: mariadb-init-sql + namespace: etri-aisw +data: + init.sql: | + create table batch_job_execution_seq + ( + next_not_cached_value bigint(21) not null, + minimum_value bigint(21) not null, + maximum_value bigint(21) not null, + start_value bigint(21) not null comment 'start value when sequences is created or value if RESTART is used', + increment bigint(21) not null comment 'increment value', + cache_size bigint(21) unsigned not null, + cycle_option tinyint(1) unsigned not null comment '0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed', + cycle_count bigint(21) not null comment 'How many cycles have been done' + ); + + create table batch_job_instance + ( + JOB_INSTANCE_ID bigint not null + primary key, + VERSION bigint null, + JOB_NAME varchar(100) not null, + JOB_KEY varchar(32) not null, + constraint JOB_INST_UN + unique (JOB_NAME, JOB_KEY) + ); + + create table batch_job_execution + ( + JOB_EXECUTION_ID bigint not null + primary key, + VERSION bigint null, + JOB_INSTANCE_ID bigint not null, + CREATE_TIME datetime(6) not null, + START_TIME datetime(6) null, + END_TIME datetime(6) null, + STATUS varchar(10) null, + EXIT_CODE varchar(2500) null, + EXIT_MESSAGE varchar(2500) null, + LAST_UPDATED datetime(6) null, + constraint JOB_INST_EXEC_FK + foreign key (JOB_INSTANCE_ID) references batch_job_instance (JOB_INSTANCE_ID) + ); + + create table batch_job_execution_context + ( + JOB_EXECUTION_ID bigint not null + primary key, + SHORT_CONTEXT varchar(2500) not null, + SERIALIZED_CONTEXT text null, + constraint JOB_EXEC_CTX_FK + foreign key (JOB_EXECUTION_ID) references batch_job_execution (JOB_EXECUTION_ID) + ); + + create table batch_job_execution_params + ( + JOB_EXECUTION_ID bigint not null, + PARAMETER_NAME varchar(100) not null, + PARAMETER_TYPE varchar(100) not null, + PARAMETER_VALUE varchar(2500) null, + IDENTIFYING char not null, + constraint JOB_EXEC_PARAMS_FK + foreign key (JOB_EXECUTION_ID) references batch_job_execution (JOB_EXECUTION_ID) + ); + + create table batch_job_seq + ( + next_not_cached_value bigint(21) not null, + minimum_value bigint(21) not null, + maximum_value bigint(21) not null, + start_value bigint(21) not null comment 'start value when sequences is created or value if RESTART is used', + increment bigint(21) not null comment 'increment value', + cache_size bigint(21) unsigned not null, + cycle_option tinyint(1) unsigned not null comment '0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed', + cycle_count bigint(21) not null comment 'How many cycles have been done' + ); + + create table batch_step_execution + ( + STEP_EXECUTION_ID bigint not null + primary key, + VERSION bigint not null, + STEP_NAME varchar(100) not null, + JOB_EXECUTION_ID bigint not null, + CREATE_TIME datetime(6) not null, + START_TIME datetime(6) null, + END_TIME datetime(6) null, + STATUS varchar(10) null, + COMMIT_COUNT bigint null, + READ_COUNT bigint null, + FILTER_COUNT bigint null, + WRITE_COUNT bigint null, + READ_SKIP_COUNT bigint null, + WRITE_SKIP_COUNT bigint null, + PROCESS_SKIP_COUNT bigint null, + ROLLBACK_COUNT bigint null, + EXIT_CODE varchar(2500) null, + EXIT_MESSAGE varchar(2500) null, + LAST_UPDATED datetime(6) null, + constraint JOB_EXEC_STEP_FK + foreign key (JOB_EXECUTION_ID) references batch_job_execution (JOB_EXECUTION_ID) + ); + + create table batch_step_execution_context + ( + STEP_EXECUTION_ID bigint not null + primary key, + SHORT_CONTEXT varchar(2500) not null, + SERIALIZED_CONTEXT text null, + constraint STEP_EXEC_CTX_FK + foreign key (STEP_EXECUTION_ID) references batch_step_execution (STEP_EXECUTION_ID) + ); + + create table batch_step_execution_seq + ( + next_not_cached_value bigint(21) not null, + minimum_value bigint(21) not null, + maximum_value bigint(21) not null, + start_value bigint(21) not null comment 'start value when sequences is created or value if RESTART is used', + increment bigint(21) not null comment 'increment value', + cache_size bigint(21) unsigned not null, + cycle_option tinyint(1) unsigned not null comment '0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed', + cycle_count bigint(21) not null comment 'How many cycles have been done' + ); + + create table tb_datagroup + ( + id bigint auto_increment comment 'ID' + primary key, + mod_date datetime(6) null comment '수정 일자', + project_id bigint not null, + reg_date datetime(6) null comment '등록 일자', + ref_type varchar(50) not null comment '첨부파일 종류', + del_yn varchar(255) null comment '삭제 여부', + ds_desc varchar(255) null comment '데이터셋 설명', + ds_nm varchar(255) null comment '데이터셋 이름', + mod_user_id varchar(255) null comment '수정 유저 ID', + mod_user_nm varchar(255) null comment '수정 유저 이름', + reg_user_id varchar(255) null comment '등록 유저 ID', + reg_user_nm varchar(255) null comment '등록 유저 이름' + ) + comment '데이터그룹'; + + create table tb_experiments + ( + id bigint auto_increment + primary key, + kubeflow_created_at datetime(6) null, + kubeflow_last_run_created_at datetime(6) null, + last_update_time datetime(6) null, + mlflow_created_at datetime(6) null, + project_id bigint not null, + description varchar(255) null, + display_name varchar(255) null, + kube_flow_id varchar(255) null, + kubeflow_storage_state varchar(255) null, + ml_flow_id varchar(255) null, + mlflow_artifact_location varchar(255) null, + mlflow_lifecycle_stage varchar(255) null, + name varchar(255) null, + reg_user_id varchar(255) null + ); + + create table tb_minio_attachment + ( + version int not null comment '파일 버전', + id bigint auto_increment comment '첨부파일 ID' + primary key, + project_id bigint not null, + ref_id bigint not null comment '연관 엔티티 ID', + reg_dt datetime(6) not null comment '업로드 일시', + size bigint not null comment '파일 크기', + ref_type varchar(50) not null comment '첨부파일 종류', + reg_user_id varchar(50) not null comment '업로더 ID', + content_type varchar(100) not null comment 'MIME 타입', + title varchar(200) null comment '파일 제목', + storage_path varchar(500) not null comment '스토리지 경로', + description varchar(1000) null comment '파일 설명', + original_name varchar(255) not null comment '원본 파일명', + stored_name varchar(255) not null comment '저장된 파일명' + ) + comment 'MinIO 첨부파일'; + + create table tb_project + ( + prj_end_dt date null comment '프로젝트 종료일', + prj_start_dt date null comment '프로젝트 시작일', + id bigint auto_increment comment 'ID' + primary key, + mod_date datetime(6) null comment '수정 일자', + reg_date datetime(6) null comment '등록 일자', + del_yn varchar(255) null comment '삭제 여부', + mod_user_id varchar(255) null comment '수정 유저 ID', + mod_user_nm varchar(255) null comment '수정 유저 이름', + prj_cd varchar(255) null comment '프로젝트 코드', + prj_desc varchar(255) null comment '프로젝트 설명', + prj_nm varchar(255) null comment '프로젝트 이름', + reg_user_id varchar(255) null comment '등록 유저 ID', + reg_user_nm varchar(255) null comment '등록 유저 이름', + constraint UKr4j59jsw44w7lklim967h3y68 + unique (prj_cd) + ) + comment '프로젝트'; + + create table tb_refreshtoken_seq + ( + next_not_cached_value bigint(21) not null, + minimum_value bigint(21) not null, + maximum_value bigint(21) not null, + start_value bigint(21) not null comment 'start value when sequences is created or value if RESTART is used', + increment bigint(21) not null comment 'increment value', + cache_size bigint(21) unsigned not null, + cycle_option tinyint(1) unsigned not null comment '0 if no cycles are allowed, 1 if the sequence should begin a new cycle when maximum_value is passed', + cycle_count bigint(21) not null comment 'How many cycles have been done' + ); + + create table tb_role + ( + id int auto_increment comment '아이디' + primary key, + name enum ('ROLE_ADMIN', 'ROLE_MODERATOR', 'ROLE_USER') null comment '이름' + ) + comment '역할'; + + create table tb_runs + ( + created_at datetime(6) null, + finished_at datetime(6) null, + id bigint auto_increment + primary key, + scheduled_at datetime(6) null, + description varchar(255) null, + display_name varchar(255) null, + experiment_id varchar(255) null, + pipeline_id varchar(255) null, + pipeline_version_id varchar(255) null, + run_id varchar(255) not null, + service_account varchar(255) null, + state varchar(255) null, + storage_state varchar(255) null, + constraint UKo50j5wvoq8yfljyrwhwchrmwf + unique (run_id) + ); + + create table tb_user + ( + id bigint auto_increment comment '아이디' + primary key, + username varchar(20) not null comment '유저이름', + email varchar(50) not null, + password varchar(120) not null, + constraint UK4vih17mube9j7cqyjlfbcrk4m + unique (email), + constraint UK4wv83hfajry5tdoamn8wsqa6x + unique (username) + ) + comment '유저'; + + create table tb_refreshtoken + ( + expiry_date datetime(6) not null, + id bigint not null + primary key, + user_id bigint null, + token varchar(255) not null, + constraint UKdis2d9uh6810rtsujb61a79dh + unique (token), + constraint UKgswd16e98xyda2y0mjm1wvln6 + unique (user_id), + constraint FKpk3u23d8d7klynbhbaf9t9phw + foreign key (user_id) references tb_user (id) + ) + comment '새로고침 토큰'; + + create table tb_user_project_map + ( + id bigint auto_increment + primary key, + project_id bigint not null, + user_id bigint not null, + constraint FK9hgfnekphk923u837c4djs43d + foreign key (project_id) references tb_project (id), + constraint FKfba014j3xk0akg933ywmhry5r + foreign key (user_id) references tb_user (id) + ); + + create table tb_user_project_permission + ( + user_project_id bigint not null, + permissions enum ('CREATE', 'DELETE', 'READ', 'UPDATE') null, + constraint FKq3vj28y7guss18yhrgosbnuu7 + foreign key (user_project_id) references tb_user_project_map (id) + ); + + create table tb_user_roles + ( + role_id int not null, + user_id bigint not null, + primary key (role_id, user_id), + constraint FK19t64ocsol5x06fy2cytp7gey + foreign key (user_id) references tb_user (id), + constraint FKft1jmfcluls775jqp5142wvl8 + foreign key (role_id) references tb_role (id) + ); + + create table tb_workflows + ( + version int null, + id bigint auto_increment comment 'ID' + primary key, + mod_dt datetime(6) null, + project_id bigint not null, + reg_dt datetime(6) null, + description varchar(255) null, + display_name varchar(255) null, + kubeflow_status varchar(255) null, + name varchar(255) null, + namespace varchar(255) null, + pipeline_id varchar(255) null, + reg_user_id varchar(255) null + ); diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index a6c6999..714063e 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -4,6 +4,18 @@ springdoc.swagger-ui.url=/v3/api-docs springdoc.swagger-ui.doc-expansion=none springdoc.swagger-ui.disable-swagger-default-url=true +# Local MariaDB +spring.datasource.url=jdbc:mariadb://localhost:3306/autoflow +spring.datasource.username=cuuva +spring.datasource.password=cuuva + +# Local MinIO +storage.provider=minio +minio.endpoint=http://localhost:9000 +minio.access-key=minio +minio.secret-key=minio123 +minio.bucket=mlpipeline + +spring.jpa.hibernate.ddl-auto=update +spring.sql.init.mode=always -spring.jpa.hibernate.ddl-auto=none -spring.sql.init.mode=never