From 73bb047199e9041ba3bb0f4751394357cfd0357f Mon Sep 17 00:00:00 2001 From: simGPT Date: Thu, 28 May 2026 15:11:25 +0900 Subject: [PATCH 1/9] =?UTF-8?q?:wrench:Settings:=20=EB=84=A4=EC=9E=84?= =?UTF-8?q?=EC=8A=A4=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EB=B6=84=EB=A6=AC=20?= =?UTF-8?q?=EB=B0=8F=20MLflow=20=ED=92=80=20DNS=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- k8s/mlflow-db/deployment.yaml | 1 + k8s/mlflow-db/pvc.yaml | 1 + k8s/mlflow-db/service.yaml | 1 + k8s/mlflow/deployment.yaml | 1 + k8s/mlflow/service.yaml | 1 + k8s/model-api/base/deployment.yaml | 2 +- k8s/model-api/overlays/local/kustomization.yaml | 2 ++ .../overlays/production/kustomization.yaml | 2 ++ k8s/namespaces.yaml | 14 ++++++++++++++ services/model-api/app/models/loader.py | 2 +- 10 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 k8s/namespaces.yaml diff --git a/k8s/mlflow-db/deployment.yaml b/k8s/mlflow-db/deployment.yaml index c9fa14e..0def4c2 100644 --- a/k8s/mlflow-db/deployment.yaml +++ b/k8s/mlflow-db/deployment.yaml @@ -2,6 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: mlflow-db + namespace: mlflow spec: replicas: 1 selector: diff --git a/k8s/mlflow-db/pvc.yaml b/k8s/mlflow-db/pvc.yaml index 7e94201..82c7fdb 100644 --- a/k8s/mlflow-db/pvc.yaml +++ b/k8s/mlflow-db/pvc.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mlflow-db-pvc + namespace: mlflow spec: accessModes: - ReadWriteOnce diff --git a/k8s/mlflow-db/service.yaml b/k8s/mlflow-db/service.yaml index 14a21be..2e9b85c 100644 --- a/k8s/mlflow-db/service.yaml +++ b/k8s/mlflow-db/service.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Service metadata: name: mlflow-db + namespace: mlflow spec: type: ClusterIP selector: diff --git a/k8s/mlflow/deployment.yaml b/k8s/mlflow/deployment.yaml index a76773d..9c48731 100644 --- a/k8s/mlflow/deployment.yaml +++ b/k8s/mlflow/deployment.yaml @@ -2,6 +2,7 @@ apiVersion: apps/v1 kind: Deployment metadata: name: mlflow + namespace: mlflow spec: replicas: 1 selector: diff --git a/k8s/mlflow/service.yaml b/k8s/mlflow/service.yaml index 4d0618c..fa231d4 100644 --- a/k8s/mlflow/service.yaml +++ b/k8s/mlflow/service.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: Service metadata: name: mlflow + namespace: mlflow spec: type: NodePort selector: diff --git a/k8s/model-api/base/deployment.yaml b/k8s/model-api/base/deployment.yaml index 5b6126e..ba274c5 100644 --- a/k8s/model-api/base/deployment.yaml +++ b/k8s/model-api/base/deployment.yaml @@ -19,7 +19,7 @@ spec: - containerPort: 8000 env: - name: MLFLOW_TRACKING_URI - value: http://mlflow:5000 + value: http://mlflow.mlflow.svc.cluster.local:5000 - name: AWS_ACCESS_KEY_ID valueFrom: secretKeyRef: diff --git a/k8s/model-api/overlays/local/kustomization.yaml b/k8s/model-api/overlays/local/kustomization.yaml index fd7d7d0..4288430 100644 --- a/k8s/model-api/overlays/local/kustomization.yaml +++ b/k8s/model-api/overlays/local/kustomization.yaml @@ -1,6 +1,8 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization +namespace: model-api + resources: - ../../base # base 가져다 쓴다 - service.yaml diff --git a/k8s/model-api/overlays/production/kustomization.yaml b/k8s/model-api/overlays/production/kustomization.yaml index 6b08fd8..7f51c21 100644 --- a/k8s/model-api/overlays/production/kustomization.yaml +++ b/k8s/model-api/overlays/production/kustomization.yaml @@ -1,6 +1,8 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization +namespace: model-api # 네임스페이스 추가(일부러 deployment.yaml에서 네임스페이스 안쓰고 여기서만 씀) + resources: - ../../base - service.yaml diff --git a/k8s/namespaces.yaml b/k8s/namespaces.yaml new file mode 100644 index 0000000..7f86098 --- /dev/null +++ b/k8s/namespaces.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: mlflow +--- +apiVersion: v1 +kind: Namespace +metadata: + name: model-api +--- +apiVersion: v1 +kind: Namespace +metadata: + name: monitoring diff --git a/services/model-api/app/models/loader.py b/services/model-api/app/models/loader.py index 7e4c388..e0f5549 100644 --- a/services/model-api/app/models/loader.py +++ b/services/model-api/app/models/loader.py @@ -11,7 +11,7 @@ def load_model(model_name: str, version: str): if cache_key in _model_cache: return _model_cache[cache_key] - mlflow_uri = os.getenv("MLFLOW_TRACKING_URI", "http://mlflow:5000") + mlflow_uri = os.getenv("MLFLOW_TRACKING_URI", "http://mlflow:5000") # 환경변수에서 mlflow tracking uri 가져오기, 없으면 기본값으로 http://mlflow:5000 사용 mlflow.set_tracking_uri(mlflow_uri) model_uri = f"models:/{model_name}-{version}/latest" From df170297cb9fa8e9d964008239aef2ba730ca5f9 Mon Sep 17 00:00:00 2001 From: simGPT Date: Thu, 28 May 2026 15:18:25 +0900 Subject: [PATCH 2/9] =?UTF-8?q?:wrench:Settings:=20MLflow=20=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=20NodePort=20=E2=86=92=20ClusterIP=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- k8s/mlflow/service.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/k8s/mlflow/service.yaml b/k8s/mlflow/service.yaml index fa231d4..b498a78 100644 --- a/k8s/mlflow/service.yaml +++ b/k8s/mlflow/service.yaml @@ -4,10 +4,9 @@ metadata: name: mlflow namespace: mlflow spec: - type: NodePort + type: ClusterIP selector: app: mlflow ports: - port: 5000 targetPort: 5000 - nodePort: 30050 From d7fd00e0b32d6f3e914978a63b09171f7f206e64 Mon Sep 17 00:00:00 2001 From: simGPT Date: Sat, 30 May 2026 21:03:22 +0900 Subject: [PATCH 3/9] =?UTF-8?q?:sparkles:Feat:=20cert-manager=20ClusterIss?= =?UTF-8?q?uer=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- k8s/cert-manager/cluster-issuer.yaml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 k8s/cert-manager/cluster-issuer.yaml diff --git a/k8s/cert-manager/cluster-issuer.yaml b/k8s/cert-manager/cluster-issuer.yaml new file mode 100644 index 0000000..ec8d848 --- /dev/null +++ b/k8s/cert-manager/cluster-issuer.yaml @@ -0,0 +1,14 @@ +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer # 인증서 발급, 클러스터 전체에서 사용 가능 +metadata: + name: swmlops-issuer +spec: + acme: # acme 프로토콜이 Let’s Encrypt와 통신하기 위한 표준 프로토콜 + server: https://acme-v02.api.letsencrypt.org/directory + email: simgpt02@gmail.com + privateKeySecretRef: + name: swmlops-issuer + solvers: + - http01: + ingress: + ingressClassName: traefik # k3s 에서 기본 제공해주는 ingress controller From 8f987f46211d14475763562eb7e4f856863e9f1f Mon Sep 17 00:00:00 2001 From: simGPT Date: Sat, 30 May 2026 21:04:27 +0900 Subject: [PATCH 4/9] =?UTF-8?q?:wrench:Settings:=20Ingress=20=EB=A6=AC?= =?UTF-8?q?=EC=86=8C=EC=8A=A4=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- k8s/mlflow/ingress.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 k8s/mlflow/ingress.yaml diff --git a/k8s/mlflow/ingress.yaml b/k8s/mlflow/ingress.yaml new file mode 100644 index 0000000..4d2b93e --- /dev/null +++ b/k8s/mlflow/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: mlflow + namespace: mlflow + annotations: + cert-manager.io/cluster-issuer: swmlops-issuer # cert-manager에서 인증서를 발급받을 때 사용할 ClusterIssuer 지정 +spec: + ingressClassName: traefik # k3s 에서 기본 제공해주는 ingress controller + tls: + - hosts: + - mlflow.swmlops.site # 이 도메인으로 접속할 때 TLS 인증서 사용 + secretName: mlflow-tls + rules: + - host: mlflow.swmlops.site # 이 도메인으로 접속할 때 아래의 http 경로로 라우팅 + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: mlflow # mlflow 서비스로 이동 + 5000 포트로 이동 + port: + number: 5000 From 3d3da21b52811fecdca03c691786516cca410631 Mon Sep 17 00:00:00 2001 From: simGPT Date: Sat, 30 May 2026 21:05:00 +0900 Subject: [PATCH 5/9] =?UTF-8?q?:wrench:Settings:=20=ED=92=80=20DNS=20?= =?UTF-8?q?=ED=97=88=EC=9A=A9=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- k8s/mlflow/deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/k8s/mlflow/deployment.yaml b/k8s/mlflow/deployment.yaml index 9c48731..51d060b 100644 --- a/k8s/mlflow/deployment.yaml +++ b/k8s/mlflow/deployment.yaml @@ -40,5 +40,5 @@ spec: - --port=5000 - --default-artifact-root=s3://kube-ml-bucket/mlflow-artifacts # 모델 저장 - --backend-store-uri=postgresql://mlflow:1234@mlflow-db:5432/mlflow - - --allowed-hosts=mlflow,mlflow:5000,mlflow.default.svc.cluster.local,localhost,localhost:5000 # 실제 운영 환경에서는 실제 도메인을 입력하면 될 듯 + - --allowed-hosts=mlflow.mlflow.svc.cluster.local,localhost,localhost:5000,mlflow.swmlops.site # 풀 DNS, localhost, 도메인 허용 From 8b19af331fa2daa6c8da40b22e6fe2f8ff1a7920 Mon Sep 17 00:00:00 2001 From: simGPT Date: Sat, 30 May 2026 22:09:04 +0900 Subject: [PATCH 6/9] =?UTF-8?q?:recycle:Refactor:=20mlflow=20uri=20?= =?UTF-8?q?=EA=B8=B0=EB=B3=B8=EA=B0=92=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- services/model-api/training/churn/train.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/model-api/training/churn/train.py b/services/model-api/training/churn/train.py index 99434dd..fa1190b 100644 --- a/services/model-api/training/churn/train.py +++ b/services/model-api/training/churn/train.py @@ -64,7 +64,7 @@ def main(args): parser.add_argument('--version', type=str, default='v1') parser.add_argument('--C', type=float, default=1.0) parser.add_argument('--data_dir', type=str, default='../data/churn') - parser.add_argument('--mlflow_uri', type=str, default='http://localhost:5000') + parser.add_argument('--mlflow_uri', type=str, default='https://mlflow.swmlops.site') # 로컬에서 실행해도 등록되도록 기본값 변경 args = parser.parse_args() main(args) From e2c87a34560753603f617a597fe76e01c2d224ea Mon Sep 17 00:00:00 2001 From: simGPT Date: Sat, 30 May 2026 22:14:35 +0900 Subject: [PATCH 7/9] =?UTF-8?q?:recycle:Refactor:=20=EB=84=A4=EC=9E=84?= =?UTF-8?q?=EC=8A=A4=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EB=B6=84=EB=A6=AC?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20cd=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A6=BD=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cd-production.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cd-production.yaml b/.github/workflows/cd-production.yaml index fff9229..25749fc 100644 --- a/.github/workflows/cd-production.yaml +++ b/.github/workflows/cd-production.yaml @@ -24,7 +24,7 @@ jobs: run: kubectl apply -k k8s/model-api/overlays/production/ - name: 파드 재시작 # (이미지 태그가 계속 latest여도 새 이미지로 배포되도록) - run: kubectl rollout restart deployment/model-api + run: kubectl rollout restart deployment/model-api -n model-api # 네임스페이스 지정 - name: 배포 확인 - run: kubectl rollout status deployment/model-api + run: kubectl rollout status deployment/model-api -n model-api # 네임스페이스 지정 From 5dfe5466a0ab98afe26d640f56f3447cc025bd52 Mon Sep 17 00:00:00 2001 From: simGPT Date: Sat, 30 May 2026 22:16:07 +0900 Subject: [PATCH 8/9] =?UTF-8?q?:recycle:Refactor:=20model-api=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20Ingress=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- k8s/model-api/overlays/production/ingress.yaml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/k8s/model-api/overlays/production/ingress.yaml b/k8s/model-api/overlays/production/ingress.yaml index f4feba1..e2a8225 100644 --- a/k8s/model-api/overlays/production/ingress.yaml +++ b/k8s/model-api/overlays/production/ingress.yaml @@ -2,9 +2,18 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: model-api + namespace: model-api + annotations: + cert-manager.io/cluster-issuer: swmlops-issuer # cert-manager에서 인증서를 발급받을 때 사용할 ClusterIssuer 지정 spec: + ingressClassName: traefik # k3s 에서 기본 제공해주는 ingress controller + tls: + - hosts: + - model.swmlops.site # 이 도메인으로 접속할 때 TLS 인증서 사용 + secretName: model-api-tls rules: - - http: + - host: model.swmlops.site # 이 도메인으로 접속할 때 아래의 http 경로로 라우팅 + http: paths: - path: / pathType: Prefix From 30e11307c7bf688f20a2998eecf3289113ecfa3d Mon Sep 17 00:00:00 2001 From: simGPT Date: Sat, 30 May 2026 22:24:26 +0900 Subject: [PATCH 9/9] =?UTF-8?q?:wrench:Settings:=20Grafana=20Ingress=20?= =?UTF-8?q?=EB=B0=8F=20model-api=20=ED=92=80=20DNS=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- k8s/monitoring/values.yaml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/k8s/monitoring/values.yaml b/k8s/monitoring/values.yaml index 45592f6..e6d476f 100644 --- a/k8s/monitoring/values.yaml +++ b/k8s/monitoring/values.yaml @@ -4,4 +4,17 @@ prometheus: - job_name: model-api static_configs: - targets: - - model-api.default.svc.cluster.local:8000 + - model-api.model-api.svc.cluster.local:8000 # 다른 네임스페이스에 있는 model-api의 클러스터 내부 주소와 포트 + +grafana: + ingress: + enabled: true + ingressClassName: traefik + annotations: + cert-manager.io/cluster-issuer: swmlops-issuer + hosts: + - monitoring.swmlops.site + tls: + - secretName: grafana-tls + hosts: + - monitoring.swmlops.site