fix(dev): dev down 안전화 + dev ls 신설(엉뚱한 삭제 방지) — 0.21.3
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
116
bin/yakcloud
116
bin/yakcloud
@ -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.21.2"
|
||||
VERSION="0.21.3"
|
||||
# 로컬 개발 클러스터(kind) — 개발 후 운영까지 '직선 배포'의 dev 구간.
|
||||
DEV_CTX="${YAK_DEV_CONTEXT:-kind-yak-dev}"
|
||||
DEV_CLUSTER="${YAK_DEV_CLUSTER:-yak-dev}"
|
||||
@ -568,42 +568,46 @@ _dev_deregister() {
|
||||
return 0
|
||||
}
|
||||
|
||||
cmd_dev() {
|
||||
local sub="${1:-}"; [ "$#" -gt 0 ] && shift
|
||||
# --name 미지정 + 프로젝트 폴더면 매니페스트 environments.dev 값을 강제 주입(입력값이 클러스터·등록명에 반영).
|
||||
# → 'yakcloud dev up/deploy' 를 이름 없이 실행해도 항상 environments.dev.cluster 로 뜬다(호스트명만 등록되던 문제 차단).
|
||||
case " $* " in
|
||||
*" --name"*|*" --cluster"*) : ;; # 명시 지정이 있으면 존중
|
||||
*)
|
||||
if [ -f yakcloud.yaml ]; then
|
||||
local _mn _mp; _mn="$(_manifest_env dev cluster 2>/dev/null)"; _mp="$(_manifest_env dev port 2>/dev/null)"
|
||||
if [ -n "$_mn" ]; then
|
||||
local _inj=(--name "$_mn")
|
||||
{ [ -n "$_mp" ] && [ "$_mp" != "80" ]; } && _inj+=(--port "$_mp")
|
||||
set -- "${_inj[@]}" "$@"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
_dev_resolve "$@" # --name/--port 파싱 → DEV_NAME/DEV_CLUSTER/DEV_CTX/DEV_HTTP_PORT/DEV_ARGS
|
||||
_podman_auth_fix "$(_dev_runtime)" # podman + Docker Desktop credHelpers(https://) 충돌 자동 우회(공개 이미지)
|
||||
case "$sub" in
|
||||
up) cmd_dev_up ;;
|
||||
deploy|status|clean)
|
||||
[ -f yakcloud.yaml ] || die "프로젝트 폴더가 아닙니다 — 'yakcloud project init' 먼저"
|
||||
ensure_pyyaml
|
||||
local rt tag=""; rt="$(_dev_runtime)"
|
||||
for a in "${DEV_ARGS[@]+"${DEV_ARGS[@]}"}"; do case "$a" in -*) : ;; *) [ -z "$tag" ] && tag="$a" ;; esac; done
|
||||
local pysub="$sub"; [ "$sub" = clean ] && pysub="down"
|
||||
YAK_DEV_CONTEXT="$DEV_CTX" YAK_DEV_CLUSTER="$DEV_CLUSTER" YAK_DEV_NAME="$DEV_NAME" \
|
||||
YAK_DEV_RUNTIME="${rt:-docker}" YAK_DEV_HTTP_PORT="$DEV_HTTP_PORT" \
|
||||
YAK_REG_NAME="$(_local_reg_name)" TAG="${tag:-${TAG:-dev}}" python3 "$(_engine dev)" "$pysub" yakcloud.yaml
|
||||
[ "$sub" = deploy ] && _dev_register || true
|
||||
;;
|
||||
down)
|
||||
# 로컬 dev 클러스터 목록 — kind 이름 / --name / 콘솔 등록명 매핑. 파괴적 명령(down) 전 대상 확인용.
|
||||
# 콘솔에 보이는 '등록명'(예 imac192)이 아니라 여기 '--name'(예 dev) 으로 지정해야 한다.
|
||||
cmd_dev_ls() {
|
||||
command -v kind >/dev/null 2>&1 || die "kind 필요"
|
||||
local rt kenv=""; rt="$(_dev_runtime)"; [ "$rt" = podman ] && kenv="KIND_EXPERIMENTAL_PROVIDER=podman"
|
||||
info "kind 클러스터 '$DEV_CLUSTER' 삭제…"
|
||||
local cs; cs="$(env $kenv kind get clusters 2>/dev/null | grep '^yak-' || true)"
|
||||
[ -z "$cs" ] && { echo "로컬 dev 클러스터 없음 — 'yakcloud dev up' 으로 생성."; return 0; }
|
||||
printf " %-18s %-14s %s\n" "kind 클러스터" "--name" "콘솔 등록명"
|
||||
local c nm
|
||||
while IFS= read -r c; do
|
||||
[ -z "$c" ] && continue
|
||||
nm="${c#yak-}"; DEV_NAME="$nm"
|
||||
printf " %-18s %-14s %s\n" "$c" "$nm" "$(_local_reg_name)"
|
||||
done <<EOF
|
||||
$cs
|
||||
EOF
|
||||
}
|
||||
|
||||
# 로컬 dev 클러스터 삭제 — 파괴적. 대상을 안전 해석: --name 없으면 0/1/다수 판정, 없는 클러스터면 가짜 삭제 금지.
|
||||
cmd_dev_down() {
|
||||
local name_given="$1"
|
||||
command -v kind >/dev/null 2>&1 || die "kind 필요"
|
||||
local rt kenv=""; rt="$(_dev_runtime)"; [ "$rt" = podman ] && kenv="KIND_EXPERIMENTAL_PROVIDER=podman"
|
||||
if [ "$name_given" = 0 ]; then
|
||||
# --name 미지정: 정확히 하나면 그것, 여럿이면 지정 요구(엉뚱한 삭제 방지). 매니페스트 자동선택 안 함(파괴적).
|
||||
local all n; all="$(env $kenv kind get clusters 2>/dev/null | grep '^yak-' || true)"
|
||||
n="$(printf '%s\n' "$all" | grep -c . 2>/dev/null || echo 0)"
|
||||
if [ "$n" -eq 0 ]; then die "로컬 dev 클러스터가 없습니다 — 'yakcloud dev ls'."; fi
|
||||
if [ "$n" -gt 1 ]; then
|
||||
echo "로컬 클러스터가 여러 개입니다 — 삭제할 것을 --name 으로 지정하세요:"; echo; cmd_dev_ls
|
||||
die "예: yakcloud dev down --name <이름>"
|
||||
fi
|
||||
DEV_CLUSTER="$(printf '%s' "$all" | head -1)"; DEV_NAME="${DEV_CLUSTER#yak-}"; DEV_CTX="kind-$DEV_CLUSTER"
|
||||
fi
|
||||
# 존재 확인 — 없으면 가짜 삭제/해제 금지(오타·'등록명 vs --name' 혼동 방지).
|
||||
if ! env $kenv kind get clusters 2>/dev/null | grep -qx "$DEV_CLUSTER"; then
|
||||
echo "로컬 클러스터 '$DEV_CLUSTER' (--name $DEV_NAME) 이(가) 없습니다."; echo; cmd_dev_ls
|
||||
die "콘솔 '등록명'(예 imac192)이 아니라 위 '--name' 값으로 지정하세요."
|
||||
fi
|
||||
info "kind 클러스터 '$DEV_CLUSTER' 삭제 (콘솔 등록명 '$(_local_reg_name)')…"
|
||||
env $kenv kind delete cluster --name "$DEV_CLUSTER" && echo "✓ 삭제 완료"
|
||||
# 이 클러스터의 릴레이 에이전트만 정리(pidfile <name>.pid, 클러스터 단위). 다른 dev 클러스터는 건드리지 않음.
|
||||
local agd="${YAK_CONFIG_DIR:-$HOME/.config/yakcloud}/agent"
|
||||
@ -620,7 +624,6 @@ cmd_dev() {
|
||||
else
|
||||
local scs; scs="$("${rt:-docker}" ps -aq -f label=yakcloud.dev/shared=1 2>/dev/null)"
|
||||
[ -n "$scs" ] && { info "공유 소스 컨테이너 정리(마지막 dev 클러스터)…"; echo "$scs" | xargs "${rt:-docker}" rm -f >/dev/null 2>&1; }
|
||||
# 마지막 클러스터 → 남은 모든 에이전트 pidfile 정리(구 <ns>.pid 명명 포함 — 전부 고아).
|
||||
if [ -d "$agd" ]; then
|
||||
for pf in "$agd"/*.pid; do
|
||||
[ -f "$pf" ] || continue
|
||||
@ -630,8 +633,44 @@ cmd_dev() {
|
||||
fi
|
||||
fi
|
||||
_dev_deregister
|
||||
}
|
||||
|
||||
cmd_dev() {
|
||||
local sub="${1:-}"; [ "$#" -gt 0 ] && shift
|
||||
local name_given=0
|
||||
case " $* " in *" --name"*|*" --cluster"*) name_given=1 ;; esac # 명시 지정 여부
|
||||
# 프로젝트 폴더 + --name 미지정이면 매니페스트 environments.dev 값을 자동 주입 — 단, **비파괴적 프로젝트 명령만**
|
||||
# (up/deploy/status/clean). down(클러스터 삭제)은 자동 선택 안 함 → 엉뚱한 삭제 방지.
|
||||
case "$sub" in
|
||||
up|deploy|status|clean)
|
||||
if [ "$name_given" = 0 ] && [ -f yakcloud.yaml ]; then
|
||||
local _mn _mp; _mn="$(_manifest_env dev cluster 2>/dev/null)"; _mp="$(_manifest_env dev port 2>/dev/null)"
|
||||
if [ -n "$_mn" ]; then
|
||||
local _inj=(--name "$_mn")
|
||||
{ [ -n "$_mp" ] && [ "$_mp" != "80" ]; } && _inj+=(--port "$_mp")
|
||||
set -- "${_inj[@]}" "$@"; name_given=1
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
*) echo "yakcloud dev <up [--name N --port P] | deploy [--name N] [tag] | status [--name N] | clean | down [--name N]>"; exit 1 ;;
|
||||
esac
|
||||
_dev_resolve "$@" # --name/--port 파싱 → DEV_NAME/DEV_CLUSTER/DEV_CTX/DEV_HTTP_PORT/DEV_ARGS
|
||||
_podman_auth_fix "$(_dev_runtime)" # podman + Docker Desktop credHelpers(https://) 충돌 자동 우회(공개 이미지)
|
||||
case "$sub" in
|
||||
up) cmd_dev_up ;;
|
||||
ls|list) cmd_dev_ls ;;
|
||||
deploy|status|clean)
|
||||
[ -f yakcloud.yaml ] || die "프로젝트 폴더가 아닙니다 — 'yakcloud project init' 먼저"
|
||||
ensure_pyyaml
|
||||
local rt tag=""; rt="$(_dev_runtime)"
|
||||
for a in "${DEV_ARGS[@]+"${DEV_ARGS[@]}"}"; do case "$a" in -*) : ;; *) [ -z "$tag" ] && tag="$a" ;; esac; done
|
||||
local pysub="$sub"; [ "$sub" = clean ] && pysub="down"
|
||||
YAK_DEV_CONTEXT="$DEV_CTX" YAK_DEV_CLUSTER="$DEV_CLUSTER" YAK_DEV_NAME="$DEV_NAME" \
|
||||
YAK_DEV_RUNTIME="${rt:-docker}" YAK_DEV_HTTP_PORT="$DEV_HTTP_PORT" \
|
||||
YAK_REG_NAME="$(_local_reg_name)" TAG="${tag:-${TAG:-dev}}" python3 "$(_engine dev)" "$pysub" yakcloud.yaml
|
||||
[ "$sub" = deploy ] && _dev_register || true
|
||||
;;
|
||||
down) cmd_dev_down "$name_given" ;;
|
||||
*) echo "yakcloud dev <up | deploy [tag] | status | clean | down | ls> [--name N --port P]"; exit 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
@ -699,8 +738,9 @@ yakcloud $VERSION — YakCloud 프로젝트 CLI (개발·검증·운영 모두
|
||||
── 로컬 개발 클러스터(kind) — 개발 후 운영까지 직선 배포의 dev 구간 ──
|
||||
dev up 로컬 kind 생성 + 인그레스(80/443) — 최초 1회
|
||||
dev deploy [tag] 매니페스트대로 로컬 리컨실(이미지 빌드+load, 소스/워크로드/인그레스; 콘솔 API 불필요)
|
||||
dev ls 로컬 클러스터 목록(kind 이름 / --name / 콘솔 등록명) — 삭제 전 대상 확인
|
||||
dev status | dev clean 로컬 배포 상태 / 이 프로젝트 리소스 삭제
|
||||
dev down 로컬 kind 클러스터 삭제
|
||||
dev down [--name N] 로컬 kind 클러스터 삭제(여럿이면 --name 필수). 대상은 콘솔 등록명이 아니라 'dev ls' 의 --name
|
||||
project init [name] 빈 폴더에 스타터 스캐폴딩(대화형 마법사) + 자격 프롬프트
|
||||
project deploy [tag] **개발 배포 = 로컬 kind**(environments.dev). 로컬 클러스터 없으면 자동 생성 후 배포(오프라인·무료·CI 불필요)
|
||||
project promote [vX.Y.Z] --to val|prod **관리형** 검증/운영으로 승격 — 이미지 build+push(이미 있으면 재빌드 없이) 후 리컨실. 기본 --to prod
|
||||
|
||||
Reference in New Issue
Block a user