diff --git a/.yakcloud/dev.py b/.yakcloud/dev.py index b643090..72d91d1 100644 --- a/.yakcloud/dev.py +++ b/.yakcloud/dev.py @@ -268,22 +268,48 @@ def bind_env(alias: str, conn: dict) -> dict: # ── 워크로드: 빌드 + kind load + Deployment/Service/Ingress ───────────────────── +def _effective_image(image: str) -> str: + """podman 은 레지스트리(도메인) 미지정 이미지에 'localhost/' 를 붙여 저장한다 → kind load·Deployment 이름 불일치. + podman 이고 첫 컴포넌트가 레지스트리(도메인 '.'·포트 ':' 포함 또는 'localhost')가 아니면 localhost/ 를 붙여 일치시킨다. + docker 는 그대로(무영향). 레지스트리 지정 이미지(gitea.yakenator.io/…)는 두 런타임 모두 그대로.""" + if RUNTIME != "podman": + return image + first = image.split("/", 1)[0] + if "/" not in image or ("." not in first and ":" not in first and first != "localhost"): + return f"localhost/{image}" + return image + + def _image_id(image: str) -> str: r = sh([RUNTIME, "image", "inspect", "--format", "{{.Id}}", image], check=False) return (r.stdout or "").strip() if r.returncode == 0 else "" def build_and_load(image: str, ctx_dir: str) -> str: + import tempfile log(f"이미지 빌드({RUNTIME}) {image} ← {ctx_dir}") sh([RUNTIME, "build", "-t", image, ctx_dir], capture=False) log(f"kind load → 클러스터 {KIND_CLUSTER}") - env = {"KIND_EXPERIMENTAL_PROVIDER": "podman"} if RUNTIME == "podman" else {} - sh(["kind", "load", "docker-image", image, "--name", KIND_CLUSTER], capture=False, env=env) + if RUNTIME == "podman": + # podman 은 'kind load docker-image' 이름 해석이 불안정('not present locally') → save → image-archive 로 안정 로드. + tar = os.path.join(tempfile.gettempdir(), f"yak-{sanitize(image)}.tar") + sh([RUNTIME, "save", "-o", tar, image], capture=False) + try: + sh(["kind", "load", "image-archive", tar, "--name", KIND_CLUSTER], + capture=False, env={"KIND_EXPERIMENTAL_PROVIDER": "podman"}) + finally: + try: + os.remove(tar) + except OSError: + pass + else: + sh(["kind", "load", "docker-image", image, "--name", KIND_CLUSTER], capture=False) return _image_id(image) def deploy_workload(project: str, ns: str, w: dict, src_conns: dict) -> tuple[str, bool]: - image = w["image"].replace("${TAG}", TAG) + # podman localhost/ 보정 — 빌드·kind load·Deployment 이미지 이름을 일치시킨다(docker 는 그대로). + image = _effective_image(w["image"].replace("${TAG}", TAG)) port = int(w.get("port", 8080)) ex = w.get("expose", {}) or {} res = w.get("resources", {}) or {} diff --git a/bin/yakcloud b/bin/yakcloud index 3c1550e..789841d 100755 --- a/bin/yakcloud +++ b/bin/yakcloud @@ -406,6 +406,12 @@ PY # dev status 로컬 배포 상태 · dev clean 이 프로젝트 리소스만 삭제 · dev down kind 클러스터 삭제 # 로컬 dev = CLI 로컬 완결(오프라인 반복). 같은 이미지를 push 하면 promote --to val/prod 로 그대로 직선. _dev_runtime() { + # 강제 지정(YAK_DEV_RUNTIME=docker|podman) 우선 — docker·podman 둘 다 있을 때 팀/머신이 고정. + case "${YAK_DEV_RUNTIME:-}" in + docker) command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1 && { echo docker; return; }; echo ""; return ;; + podman) command -v podman >/dev/null 2>&1 && podman info >/dev/null 2>&1 && { echo podman; return; }; echo ""; return ;; + esac + # 자동 감지 — docker 데몬 우선, 없으면 podman. if command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then echo docker; return; fi if command -v podman >/dev/null 2>&1 && podman info >/dev/null 2>&1; then echo podman; return; fi echo ""