cli v0.11.0: 로컬 dev/migrate 제거, 개발/운영 클러스터 승격 모델. environments.{dev,prod} 매니페스트; project deploy=개발 클러스터, project promote=재빌드 없이 운영 클러스터+운영 도메인. CI=dev 환경. dev/prod dry-run 검증
This commit is contained in:
@ -31,7 +31,9 @@ URL = os.environ["YAKCLOUD_URL"].rstrip("/")
|
||||
TOKEN = os.environ["YAKCLOUD_TOKEN"]
|
||||
CLUSTER_REF = os.environ.get("YAKCLOUD_CLUSTER")
|
||||
CLUSTER = "" # main 에서 이름→id 로 해석해 채운다
|
||||
CLUSTER_HOST = "" # 클러스터 기본 도메인 — expose.host(s) 미지정 시 여기로 노출
|
||||
CLUSTER_HOST = "" # 클러스터 기본 도메인 — 항상 노출(운영은 여기 + 운영 도메인)
|
||||
ENV = os.environ.get("YAKCLOUD_ENV", "dev") # 대상 환경 environments.<env> (기본 dev). promote=prod
|
||||
ENV_DOMAINS: list = [] # main 에서 environments.<env>.domains 로 채움(운영 도메인)
|
||||
TAG = os.environ.get("TAG", "latest")
|
||||
DRY = "--dry-run" in sys.argv[1:]
|
||||
|
||||
@ -163,24 +165,25 @@ def deploy_workload(w: dict) -> tuple[str | None, bool]:
|
||||
"healthPath": w.get("health"),
|
||||
"path": ex.get("path", "/"), "pathType": "Prefix", "rewritePrefix": bool(ex.get("rewrite", False)),
|
||||
}
|
||||
# 노출 도메인: 여러 개(hosts) > 단일(host) > 클러스터 기본 도메인.
|
||||
hosts = ex.get("hosts")
|
||||
if hosts:
|
||||
body["exposeHosts"] = hosts
|
||||
# 노출 도메인 = 워크로드 지정 host(s) + 환경 도메인(운영). 커스텀이 있으면 기본 도메인도 함께 노출.
|
||||
wl_hosts = ex.get("hosts") or ([ex["host"]] if ex.get("host") else [])
|
||||
custom = list(dict.fromkeys(wl_hosts + ENV_DOMAINS))
|
||||
if custom:
|
||||
body["exposeHosts"] = list(dict.fromkeys(custom + ([CLUSTER_HOST] if CLUSTER_HOST else [])))
|
||||
else:
|
||||
body["exposeHost"] = ex.get("host") or (CLUSTER_HOST or None)
|
||||
body["exposeHost"] = CLUSTER_HOST or None
|
||||
# 환경변수(선언적): 리스트[{key,value,secret?}] 또는 맵{KEY: VALUE}.
|
||||
env = w.get("env") or []
|
||||
if isinstance(env, dict):
|
||||
env = [{"key": k, "value": v} for k, v in env.items()]
|
||||
body["env"] = [{"key": e["key"], "value": str(e.get("value", "")),
|
||||
"secret": bool(e.get("secret", False))} for e in env]
|
||||
# 도메인 리컨실 — expose 에 명시한 host(들)를 레지스트리에 등록(없으면). 배포 하나로 '도달 가능한 앱'이 되게.
|
||||
for h in (ex.get("hosts") or ([ex["host"]] if ex.get("host") else [])):
|
||||
# 도메인 리컨실 — 워크로드 host(들) + 환경(운영) 도메인을 레지스트리에 등록(없으면).
|
||||
for h in custom:
|
||||
reconcile_domain(h)
|
||||
if DRY:
|
||||
log(f"deploy '{w['name']}' 예정: image={image} port={body['port']} path={body['path']} "
|
||||
f"replicas={body['replicasDesired']} hosts={hosts or body.get('exposeHost')}")
|
||||
f"replicas={body['replicasDesired']} hosts={body.get('exposeHosts') or body.get('exposeHost')}")
|
||||
return None, False
|
||||
# 멱등: 기존 배포면 PATCH(이미지 갱신 → kubectl apply = 무중단 롤링). 없으면 신규 생성.
|
||||
existing = next((d for d in cluster_deployments() if d.get("name") == w["name"]), None)
|
||||
@ -202,15 +205,22 @@ def bind(dep_id: str | None, alias: str, service_id: str | None, source: str) ->
|
||||
|
||||
|
||||
def main() -> None:
|
||||
global CLUSTER, CLUSTER_HOST
|
||||
global CLUSTER, CLUSTER_HOST, ENV_DOMAINS
|
||||
path = next((a for a in sys.argv[1:] if not a.startswith("--")), "yakcloud.yaml")
|
||||
m = yaml.safe_load(open(path))
|
||||
ref = CLUSTER_REF or m.get("cluster")
|
||||
# 환경 해석: environments.<ENV>.{cluster,domains}. 하위호환: 없으면 top-level cluster:.
|
||||
envs = m.get("environments") or {}
|
||||
env_cfg = envs.get(ENV) or {}
|
||||
ref = CLUSTER_REF or env_cfg.get("cluster") or m.get("cluster")
|
||||
if not ref:
|
||||
raise SystemExit("대상 클러스터 미지정 — YAKCLOUD_CLUSTER 환경변수 또는 매니페스트 cluster: 필드")
|
||||
raise SystemExit(
|
||||
f"환경 '{ENV}' 대상 클러스터 미지정 — 매니페스트 environments.{ENV}.cluster (또는 YAKCLOUD_CLUSTER). "
|
||||
f"등록된 환경: {', '.join(envs) or '(없음)'}")
|
||||
ENV_DOMAINS = env_cfg.get("domains") or []
|
||||
CLUSTER, cname = resolve_cluster(ref)
|
||||
CLUSTER_HOST = (unwrap(api("GET", f"/clusters/{CLUSTER}")) or {}).get("defaultHostname") or ""
|
||||
log(f"project '{m.get('project')}' → cluster '{cname}' ({CLUSTER}) (tag {TAG}){' [DRY-RUN]' if DRY else ''}")
|
||||
dom = f" +도메인 {ENV_DOMAINS}" if ENV_DOMAINS else ""
|
||||
log(f"[{ENV}] project '{m.get('project')}' → cluster '{cname}' ({CLUSTER}){dom} (tag {TAG}){' [DRY-RUN]' if DRY else ''}")
|
||||
src_ids: dict[str, str | None] = {}
|
||||
for req in m.get("requires", []):
|
||||
src_ids[req["name"]] = reconcile_source(req)
|
||||
|
||||
Reference in New Issue
Block a user