feat(dev): 다중 로컬 dev 클러스터(--name/--port) + 노드 리소스 사용현황 릴레이
`yakcloud dev up --name dev2 --port 8081` 로 머신에 여러 kind dev 클러스터(공유 소스 컨테이너 재사용). agent 가 노드 CPU/MEM/DISK(예약·실측)를 릴레이 → 콘솔이 원격과 동일한 노드 리소스 카드로 표시. dev up 이 metrics-server 자동 설치(실측용). 리뷰 반영(pidfile 정리·포트 범위·phase·디스크). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -41,6 +41,8 @@ CTX = os.environ.get("YAK_DEV_CONTEXT", "kind-yak-dev")
|
||||
KIND_CLUSTER = os.environ.get("YAK_DEV_CLUSTER", "yak-dev")
|
||||
RUNTIME = os.environ.get("YAK_DEV_RUNTIME", "docker")
|
||||
HOST_SUFFIX = os.environ.get("YAK_DEV_HOST_SUFFIX", "dev.localhost")
|
||||
DEV_NAME = os.environ.get("YAK_DEV_NAME", "dev") # 여러 dev 클러스터 구분(에이전트 pidfile 키)
|
||||
HTTP_PORT = os.environ.get("YAK_DEV_HTTP_PORT", "80") # 인그레스 host 포트(이름 붙은 클러스터는 비80)
|
||||
TAG = os.environ.get("TAG", "dev")
|
||||
|
||||
# 로컬 데이터 소스 = kind '밖'의 **공유** 도커/포드만 컨테이너(타입별 1개) + 프로젝트별 격리 DB.
|
||||
@ -364,6 +366,12 @@ def _wl_hosts(project: str, w: dict) -> list:
|
||||
return hosts or [f"{project}.{HOST_SUFFIX}"]
|
||||
|
||||
|
||||
def _disp_hosts(project: str, w: dict) -> list:
|
||||
"""콘솔 표시용 호스트 — 비80 인그레스 포트면 host:port(인그레스 규칙 자체엔 포트 안 붙임)."""
|
||||
sfx = "" if HTTP_PORT == "80" else f":{HTTP_PORT}"
|
||||
return [h + sfx for h in _wl_hosts(project, w)]
|
||||
|
||||
|
||||
def _report_to_console(project: str, reqs: list, wls: list) -> None:
|
||||
"""dev deploy 결과(소스·워크로드 요약)를 콘솔에 best-effort 리포트 — LOCAL 클러스터 데이터소스·앱 탭 렌더용.
|
||||
로그인(URL+TOKEN)+등록명(YAK_REG_NAME) 없으면 조용히 스킵(오프라인 dev 불변식)."""
|
||||
@ -378,9 +386,9 @@ def _report_to_console(project: str, reqs: list, wls: list) -> None:
|
||||
"sources": [{"name": r["name"], "type": str(r.get("type", "")).upper(),
|
||||
"secret": f"yak-dev-src-{sanitize(r['name'])}"} for r in reqs],
|
||||
"workloads": [{"name": sanitize(w["name"]), "image": w["image"].replace("${TAG}", TAG),
|
||||
"hosts": _wl_hosts(project, w), "port": int(w.get("port", 8080))} for w in wls],
|
||||
"hosts": _disp_hosts(project, w), "port": int(w.get("port", 8080))} for w in wls],
|
||||
}
|
||||
body = json.dumps({"name": name, "displayName": "로컬 개발 (kind)", "report": report}).encode()
|
||||
body = json.dumps({"name": name, "displayName": name, "report": report}).encode()
|
||||
req = urllib.request.Request(url.rstrip("/") + "/api/v1/clusters/local", data=body, method="POST",
|
||||
headers={"Authorization": "Bearer " + tok, "content-type": "application/json"})
|
||||
try:
|
||||
@ -398,7 +406,8 @@ def _agent_dir() -> str:
|
||||
|
||||
|
||||
def _agent_pidfile(ns: str) -> str:
|
||||
return os.path.join(_agent_dir(), f"{ns}.pid")
|
||||
# 클러스터별 구분 — 서로 다른 dev 클러스터가 같은 ns(프로젝트)를 가져도 pidfile 이 안 겹치게.
|
||||
return os.path.join(_agent_dir(), f"{DEV_NAME}-{ns}.pid")
|
||||
|
||||
|
||||
def _stop_agent(ns: str) -> None:
|
||||
@ -493,8 +502,9 @@ def cmd_deploy(m: dict) -> None:
|
||||
log("✓ 로컬 배포 완료(직선 dev). 접속:")
|
||||
first_host = results[0][0] if results else None
|
||||
if first_host:
|
||||
print(f" http://{first_host}/ (kind 인그레스 80 포트)")
|
||||
print(f" curl -s http://{first_host}/ | python3 -m json.tool")
|
||||
psfx = "" if HTTP_PORT == "80" else f":{HTTP_PORT}"
|
||||
print(f" http://{first_host}{psfx}/ (kind 인그레스 포트 {HTTP_PORT})")
|
||||
print(f" curl -s http://{first_host}{psfx}/ | python3 -m json.tool")
|
||||
print(f" ↑ 응답의 bound_sources 에 바인딩 소스 <ALIAS>_URL 키가 보이면 직선 파리티 성립")
|
||||
print(f" kubectl --context {CTX} -n {ns} get deploy,svc,ing,pods")
|
||||
print(f" 승격: yakcloud project deploy --local <tag> (레지스트리 push) → yakcloud project promote --to val")
|
||||
|
||||
Reference in New Issue
Block a user