feat(cli): 헬스체크 경로 동기화(경로+/healthz) — 콘솔 정합 · v0.31.0

deploy.py: health 미지정 시 healthPath=경로+/healthz 기본(명시=커스텀)
ctl.py: set --path 시 커스텀 아니면 healthPath 동반 갱신
dev.py: 로컬 kind도 동일(readiness+liveness, 백엔드 정합)
bin/yakcloud: VERSION 0.30.0 → 0.31.0
This commit is contained in:
2026-09-05 13:07:39 +09:00
parent 68bedebb1c
commit 789aaee5b4
4 changed files with 35 additions and 5 deletions

View File

@ -180,6 +180,12 @@ def cmd_scale(a) -> None:
_apply_workload_patch(m, _cid(m), w, {"replicasDesired": int(a.replicas)}, "replicas=%s" % a.replicas)
def synced_health_path(path: str) -> str:
"""경로 동기화 기본: healthPath = 경로 + '/healthz' (콘솔 '경로 동기화'와 정합)."""
base = (path or "/").strip().rstrip("/")
return base + "/healthz"
def cmd_set(a) -> None:
m = load_manifest(); w = find_workload(m, a.workload)
patch, changed = {}, []
@ -199,6 +205,10 @@ def cmd_set(a) -> None:
ex = w.get("expose", {}) or {}; w["expose"] = ex
if a.path is not None:
ex["path"] = a.path; patch["path"] = a.path; changed.append("path")
# 헬스체크가 커스텀(매니페스트 health 명시)이 아니고 이번에 --health 도 안 주면
# 경로와 동기화 — healthPath 도 경로+/healthz 로 갱신.
if a.health is None and not w.get("health"):
patch["healthPath"] = synced_health_path(a.path); changed.append("health(sync)")
if a.rewrite is not None:
rw = a.rewrite.lower() in ("1", "true", "yes", "on")
ex["rewrite"] = rw; patch["rewritePrefix"] = rw; changed.append("rewrite")

View File

@ -174,6 +174,13 @@ def _repo(img: str) -> str:
return img.rsplit(":", 1)[0] if ":" in seg else img
def synced_health_path(path: str) -> str:
"""경로 동기화 기본: healthPath = 경로 + '/healthz' (예: '/b21''/b21/healthz', '/''/healthz').
콘솔 '경로 동기화'(기본 ON)와 정합 — 매니페스트에 health 를 명시하면 그 값을 그대로 쓴다."""
base = (path or "/").strip().rstrip("/")
return base + "/healthz"
def deploy_workload(w: dict) -> tuple[str | None, bool]:
image = w["image"].replace("${TAG}", TAG)
ex = w.get("expose", {}) or {}
@ -183,7 +190,8 @@ def deploy_workload(w: dict) -> tuple[str | None, bool]:
"port": w.get("port"),
"replicasDesired": w.get("replicas", 1),
"cpuRequest": res.get("cpu", "25m"), "memRequest": res.get("mem", "96Mi"),
"healthPath": w.get("health"),
# health 미지정 시 경로와 동기화(경로+/healthz). 명시하면 그 값(커스텀).
"healthPath": w.get("health") or synced_health_path(ex.get("path", "/")),
"path": ex.get("path", "/"), "pathType": "Prefix", "rewritePrefix": bool(ex.get("rewrite", False)),
}
# 노출 도메인 = 워크로드 지정 host(s) + 환경 도메인(운영). 커스텀이 있으면 기본 도메인도 함께 노출.

View File

@ -67,6 +67,12 @@ SUPPORTED = set(_SVC_PORT)
MANAGED = "app.kubernetes.io/managed-by=yakcloud-dev"
def synced_health_path(path: str) -> str:
"""경로 동기화 기본: healthPath = 경로 + '/healthz' (콘솔 '경로 동기화'·백엔드와 정합). '/' 더블슬래시 방지."""
base = (path or "/").strip().rstrip("/")
return base + "/healthz"
def log(m: str) -> None:
print("\033[36m▸\033[0m " + m, flush=True)
@ -463,9 +469,15 @@ def deploy_workload(project: str, ns: str, w: dict, src_conns: dict) -> tuple[st
container = {"name": name, "image": image, "imagePullPolicy": "IfNotPresent",
"ports": [{"containerPort": port}], "env": env,
"resources": {"requests": {"cpu": res.get("cpu", "25m"), "memory": res.get("mem", "96Mi")}}}
if w.get("health"):
container["readinessProbe"] = {"httpGet": {"path": w["health"], "port": port},
"initialDelaySeconds": 3, "periodSeconds": 5, "failureThreshold": 30}
# health 미지정 시 경로와 동기화(경로+/healthz) — 콘솔 '경로 동기화' 기본·백엔드와 정합.
# 백엔드처럼 readiness + liveness 둘 다(로컬에서 prod 동일 동작을 조기 검증).
_ex = w.get("expose", {}) or {}
_health = w.get("health") or synced_health_path(_ex.get("path", "/"))
if _health and port:
_probe = {"httpGet": {"path": _health, "port": port},
"initialDelaySeconds": 10, "periodSeconds": 10}
container["readinessProbe"] = _probe
container["livenessProbe"] = {**_probe, "initialDelaySeconds": 20}
dep = {"apiVersion": "apps/v1", "kind": "Deployment",
"metadata": {"name": name, "namespace": ns, "labels": labels},
"spec": {"replicas": int(w.get("replicas", 1)),

View File

@ -16,7 +16,7 @@ set -uo pipefail # -e 미사용: 'test && action' 관용구가 값 없을 때
REPO="${YAKCLOUD_STARTER_REPO:-https://gitea.yakenator.io/yakenator/yakcloud-starter}"
BRANCH="${YAKCLOUD_STARTER_BRANCH:-main}"
VERSION="0.30.0"
VERSION="0.31.0"
# 로컬 개발 클러스터(kind) — 개발 후 운영까지 '직선 배포'의 dev 구간.
DEV_CTX="${YAK_DEV_CONTEXT:-kind-yak-dev}"
DEV_CLUSTER="${YAK_DEV_CLUSTER:-yak-dev}"