refactor(cli): 엔진 전역화(.yakcloud 다운로드 소스) + 스캐폴드 최소화 + shared 기본 — 0.18.0
엔진(deploy/ctl/dev.py)은 install.sh 가 ~/.config/yakcloud/lib 로 설치, CLI 가 전역 실행. project init 스캐폴드 = 앱+매니페스트+얇은 .gitea CI 만. 데이터소스 기본 shared. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -54,5 +54,7 @@ jobs:
|
||||
subprocess.check_call(["docker", "push", img])
|
||||
PY
|
||||
|
||||
# 5) YakCloud 리컨실 배포(콘솔 API, PAT 인증)
|
||||
TAG="$TAG" python3 scripts/yakcloud_deploy.py yakcloud.yaml
|
||||
# 5) YakCloud 리컨실 배포(콘솔 API, PAT 인증) — 엔진은 전역(프로젝트 미포함),
|
||||
# 스타터에서 받아 실행(버전 파편화 없음).
|
||||
curl -fsSL "https://gitea.yakenator.io/yakenator/yakcloud-starter/raw/branch/main/.yakcloud/deploy.py" -o /tmp/yc-deploy.py
|
||||
TAG="$TAG" python3 /tmp/yc-deploy.py yakcloud.yaml
|
||||
|
||||
@ -99,7 +99,7 @@ def reconcile_source(req: dict) -> str | None:
|
||||
if match and match.get("status") == "READY":
|
||||
log(f"source '{name}' ({stype}) 이미 READY → 스킵 (id={match['id']})")
|
||||
return match["id"]
|
||||
mode = req.get("mode", "local") # local=인클러스터 프로비저닝 · shared=공유 외부(백엔드가 클러스터별 격리 DB 민팅)
|
||||
mode = req.get("mode", "shared") # shared(기본)=공유 외부 서버에 격리 DB 민팅 · local=인클러스터 프로비저닝(옵션, size 사용)
|
||||
if DRY:
|
||||
if match:
|
||||
log(f"source '{name}' 상태={match.get('status')} — READY 대기 필요")
|
||||
105
bin/yakcloud
105
bin/yakcloud
@ -16,15 +16,27 @@ set -uo pipefail # -e 미사용: 'test && action' 관용구가 값 없을 때
|
||||
|
||||
REPO="${YAKCLOUD_STARTER_REPO:-https://gitea.yakenator.io/yakenator/yakcloud-starter}"
|
||||
BRANCH="${YAKCLOUD_STARTER_BRANCH:-main}"
|
||||
VERSION="0.17.0"
|
||||
VERSION="0.18.0"
|
||||
# 로컬 개발 클러스터(kind) — 개발 후 운영까지 '직선 배포'의 dev 구간.
|
||||
DEV_CTX="${YAK_DEV_CONTEXT:-kind-yak-dev}"
|
||||
DEV_CLUSTER="${YAK_DEV_CLUSTER:-yak-dev}"
|
||||
INGRESS_MANIFEST="${YAK_DEV_INGRESS:-https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.3/deploy/static/provider/kind/deploy.yaml}"
|
||||
CONFIG_DIR="${YAKCLOUD_CONFIG_DIR:-$HOME/.config/yakcloud}"
|
||||
CONFIG_FILE="$CONFIG_DIR/config"
|
||||
LIB_DIR="${YAKCLOUD_LIB_DIR:-$CONFIG_DIR/lib}" # 전역 엔진(deploy/ctl/dev.py) — 프로젝트에 복제하지 않음
|
||||
|
||||
die() { echo "✗ $*" >&2; exit 1; }
|
||||
|
||||
# 전역 엔진 경로 반환 — 없으면 스타터에서 내려받는다(자가 치유). install.sh·upgrade 가 미리 깐다.
|
||||
_engine() {
|
||||
local f="$LIB_DIR/$1.py"
|
||||
if [ ! -f "$f" ]; then
|
||||
mkdir -p "$LIB_DIR" 2>/dev/null || true
|
||||
curl -fsSL "$REPO/raw/branch/$BRANCH/.yakcloud/$1.py" -o "$f" 2>/dev/null \
|
||||
|| echo " ⚠ 엔진 '$1' 다운로드 실패 — 네트워크 확인 또는 'yakcloud upgrade'" >&2
|
||||
fi
|
||||
printf '%s' "$f"
|
||||
}
|
||||
info() { echo "▸ $*"; }
|
||||
|
||||
ensure_pyyaml() {
|
||||
@ -36,9 +48,9 @@ ensure_pyyaml() {
|
||||
|
||||
# 설정/조회 커맨드는 프로젝트의 ctl 엔진에 위임(현재 폴더 = 프로젝트).
|
||||
ctl() {
|
||||
[ -f scripts/yakcloud_ctl.py ] || die "프로젝트 폴더가 아닙니다 — 'yakcloud project init' 로 초기화하세요."
|
||||
[ -f yakcloud.yaml ] || die "프로젝트 폴더가 아닙니다 — 'yakcloud project init' 로 초기화하세요."
|
||||
ensure_pyyaml
|
||||
python3 scripts/yakcloud_ctl.py "$@"
|
||||
python3 "$(_engine ctl)" "$@"
|
||||
}
|
||||
|
||||
# ── 자격 저장 ── 비밀(배포토큰·Gitea토큰)=OS 키체인(암호화), 그 외(URL·사용자)=config 파일(600) ──
|
||||
@ -149,10 +161,13 @@ cmd_project_init() {
|
||||
rm -rf "$tmp/s/.git"
|
||||
cp -R "$tmp/s/." .
|
||||
rm -rf "$tmp"
|
||||
# 사용자 프로젝트에 불필요한 배포/전역/문서 파일은 스캐폴드에서 제거 — 앱+엔진+CI+SKILL 만 깔끔히 남긴다.
|
||||
# bin·install.sh=CLI 배포용 · .claude/commands=전역 슬래시명령(중복) · README/DATA-SOURCES=스타터 문서.
|
||||
rm -rf bin install.sh .claude/commands README.md DATA-SOURCES.md
|
||||
[ -n "$name" ] && [ -f yakcloud.yaml ] && { sed -i.bak "s/^project: .*/project: $name/" yakcloud.yaml && rm -f yakcloud.yaml.bak; }
|
||||
# 스캐폴드는 '앱 + 매니페스트 + 얇은 CI'만 남긴다 — 엔진·스킬·명령은 전역(프로젝트에 미포함).
|
||||
# bin·install.sh=CLI · .yakcloud=엔진(전역) · .claude=스킬·명령(전역) · README/DATA-SOURCES=스타터 문서.
|
||||
rm -rf bin install.sh .yakcloud .claude README.md DATA-SOURCES.md
|
||||
# 전역 엔진/스킬/명령 준비(최초 init 시에도 보장).
|
||||
install_global_assets 2>/dev/null || true
|
||||
# 프로젝트명을 project·워크로드(배포)명·image 에 일괄 반영(고정 'web' 대신 프로젝트명).
|
||||
[ -n "$name" ] && [ -f yakcloud.yaml ] && { sed -i.bak "s/my-app/$name/g" yakcloud.yaml && rm -f yakcloud.yaml.bak; }
|
||||
git rev-parse --git-dir >/dev/null 2>&1 || git init -q
|
||||
echo "✓ 스캐폴딩 완료 ($(pwd))"
|
||||
# 대화형 마법사(TTY + not --yes): 클러스터·앱·포트·헬스·CPU·메모리·replicas·env 를 물어 매니페스트에 반영.
|
||||
@ -178,21 +193,20 @@ _init_wizard() {
|
||||
printf "메모리 요청 [64Mi]: "; read -r mem; mem="${mem:-64Mi}"
|
||||
printf "replicas [2]: "; read -r reps; reps="${reps:-2}"
|
||||
printf "노출 경로(ingress path) [/]: "; read -r path; path="${path:-/}"
|
||||
sed -i.bak "s/^project: .*/project: $app/" yakcloud.yaml && rm -f yakcloud.yaml.bak
|
||||
sed -i.bak "s/yakcloud-starter-web/${app}-web/" yakcloud.yaml 2>/dev/null; rm -f yakcloud.yaml.bak
|
||||
[ -n "${GITEA_USER:-}" ] && { sed -i.bak "s#/yakenator/#/${GITEA_USER}/#" yakcloud.yaml 2>/dev/null; rm -f yakcloud.yaml.bak; }
|
||||
sed -i.bak "s/my-app/$app/g" yakcloud.yaml && rm -f yakcloud.yaml.bak # project·워크로드명·image = 앱(프로젝트)명
|
||||
[ -n "${GITEA_USER:-}" ] && { sed -i.bak "s#CHANGE_ME_GITEA_USER#${GITEA_USER}#" yakcloud.yaml 2>/dev/null; rm -f yakcloud.yaml.bak; }
|
||||
[ -n "$devc" ] && { sed -i.bak "s#my-dev-cluster#$devc#" yakcloud.yaml && rm -f yakcloud.yaml.bak; }
|
||||
[ -n "$prodc" ] && { sed -i.bak "s#my-prod-cluster#$prodc#" yakcloud.yaml && rm -f yakcloud.yaml.bak; }
|
||||
[ -n "$pdom" ] && { sed -i.bak "s#domains: \[\]#domains: [$pdom]#" yakcloud.yaml && rm -f yakcloud.yaml.bak; }
|
||||
if [ -n "$valc" ]; then sed -i.bak "s#my-val-cluster#$valc#" yakcloud.yaml && rm -f yakcloud.yaml.bak
|
||||
else sed -i.bak "/my-val-cluster/d" yakcloud.yaml && rm -f yakcloud.yaml.bak; fi # 검증 생략 시 val 줄 제거
|
||||
ensure_pyyaml
|
||||
YAKCLOUD_TOKEN= python3 scripts/yakcloud_ctl.py set web --port "$port" --health "$health" --cpu "$cpu" --mem "$mem" --path "$path" >/dev/null 2>&1 || true
|
||||
YAKCLOUD_TOKEN= python3 scripts/yakcloud_ctl.py scale web "$reps" >/dev/null 2>&1 || true
|
||||
YAKCLOUD_TOKEN= python3 "$(_engine ctl)" set "$app" --port "$port" --health "$health" --cpu "$cpu" --mem "$mem" --path "$path" >/dev/null 2>&1 || true
|
||||
YAKCLOUD_TOKEN= python3 "$(_engine ctl)" scale "$app" "$reps" >/dev/null 2>&1 || true
|
||||
echo "환경변수(KEY=VALUE, 빈 줄=종료):"
|
||||
while :; do
|
||||
printf " env> "; read -r kv || break; [ -z "$kv" ] && break
|
||||
YAKCLOUD_TOKEN= python3 scripts/yakcloud_ctl.py env web "$kv" >/dev/null 2>&1 || echo " (형식: KEY=VALUE)"
|
||||
YAKCLOUD_TOKEN= python3 "$(_engine ctl)" env "$app" "$kv" >/dev/null 2>&1 || echo " (형식: KEY=VALUE)"
|
||||
done
|
||||
echo "✓ 매니페스트 반영: app=$app dev=${devc:-<미지정>} val=${valc:-<생략>} prod=${prodc:-<미지정>} port=$port path=$path cpu=$cpu mem=$mem replicas=$reps"
|
||||
}
|
||||
@ -273,21 +287,21 @@ for w in m.get("workloads", []) or []:
|
||||
subprocess.check_call(["docker", "push", img])
|
||||
PY
|
||||
info "리컨실 배포(콘솔 API)…"
|
||||
TAG="$tag" python3 scripts/yakcloud_deploy.py yakcloud.yaml
|
||||
TAG="$tag" python3 "$(_engine deploy)" yakcloud.yaml
|
||||
echo "✓ 로컬 배포 완료(tag=$tag) — CI 없이 직접 리컨실."
|
||||
}
|
||||
|
||||
cmd_project_check() {
|
||||
[ -f scripts/yakcloud_deploy.py ] || die "'yakcloud project init' 먼저"
|
||||
[ -f yakcloud.yaml ] || die "'yakcloud project init' 먼저"
|
||||
: "${YAKCLOUD_URL:?YAKCLOUD_URL 필요}"; : "${YAKCLOUD_TOKEN:?YAKCLOUD_TOKEN 필요}"
|
||||
ensure_pyyaml
|
||||
local env=""; for a in "$@"; do case "$a" in --env=*) env="${a#--env=}" ;; --prod) env=prod ;; esac; done
|
||||
YAKCLOUD_ENV="${env:-dev}" python3 scripts/yakcloud_deploy.py yakcloud.yaml --dry-run
|
||||
YAKCLOUD_ENV="${env:-dev}" python3 "$(_engine deploy)" yakcloud.yaml --dry-run
|
||||
}
|
||||
|
||||
# 운영 승격 — 개발에서 검증한 그 태그의 이미지를 **재빌드 없이** 운영 클러스터로 리컨실 + 운영 도메인 부착.
|
||||
cmd_project_promote() {
|
||||
[ -f scripts/yakcloud_deploy.py ] || die "'yakcloud project init' 먼저"
|
||||
[ -f yakcloud.yaml ] || die "'yakcloud project init' 먼저"
|
||||
: "${YAKCLOUD_URL:?YAKCLOUD_URL 필요 — 'yakcloud login'}"; : "${YAKCLOUD_TOKEN:?YAKCLOUD_TOKEN 필요 — 'yakcloud login'}"
|
||||
ensure_pyyaml
|
||||
local tag="" env="prod"
|
||||
@ -305,7 +319,7 @@ cmd_project_promote() {
|
||||
[ -n "$tag" ] || die "승격할 태그가 없습니다 — 'yakcloud project promote vX.Y.Z' (개발 배포된 태그)"
|
||||
case "$tag" in v*) : ;; *) tag="v$tag" ;; esac
|
||||
info "'$env' 승격: $tag → '$env' 환경(재빌드 없이 개발에서 빌드된 그 이미지를 리컨실)"
|
||||
YAKCLOUD_ENV="$env" TAG="$tag" python3 scripts/yakcloud_deploy.py yakcloud.yaml
|
||||
YAKCLOUD_ENV="$env" TAG="$tag" python3 "$(_engine deploy)" yakcloud.yaml
|
||||
echo "✓ 승격 완료: $tag → '$env' 클러스터 + 도메인(기본 도메인은 자동)"
|
||||
}
|
||||
|
||||
@ -463,14 +477,14 @@ cmd_dev() {
|
||||
case "$sub" in
|
||||
up) cmd_dev_up "$@" ;;
|
||||
deploy|status|clean)
|
||||
[ -f scripts/yakcloud_dev.py ] || die "프로젝트 폴더가 아닙니다 — 'yakcloud project init' 먼저"
|
||||
[ -f yakcloud.yaml ] || die "프로젝트 폴더가 아닙니다 — 'yakcloud project init' 먼저"
|
||||
[ -f yakcloud.yaml ] || die "yakcloud.yaml 없음"
|
||||
ensure_pyyaml
|
||||
local rt tag=""; rt="$(_dev_runtime)"
|
||||
for a in "$@"; 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_RUNTIME="${rt:-docker}" \
|
||||
YAK_REG_NAME="$(_local_reg_name)" TAG="${tag:-${TAG:-dev}}" python3 scripts/yakcloud_dev.py "$pysub" yakcloud.yaml
|
||||
YAK_REG_NAME="$(_local_reg_name)" TAG="${tag:-${TAG:-dev}}" python3 "$(_engine dev)" "$pysub" yakcloud.yaml
|
||||
[ "$sub" = deploy ] && _dev_register || true
|
||||
;;
|
||||
down)
|
||||
@ -484,20 +498,24 @@ cmd_dev() {
|
||||
esac
|
||||
}
|
||||
|
||||
# 전역 CLI 자기 갱신 — 버전이 같아도 항상 최신 파일을 강제로 다시 받아 덮어쓴다(캐시 우회).
|
||||
# Claude Code 전역 슬래시 명령(/yakcloud) 설치/최신화 — 설치·업그레이드 시 함께 실행.
|
||||
# opt-out: YAKCLOUD_NO_CLAUDE_CMD=1. 실패해도 CLI 동작엔 지장 없음(비치명적).
|
||||
install_claude_command() {
|
||||
# 전역 자산 설치/최신화 — 엔진(deploy/ctl/dev.py → $LIB_DIR) + Claude 스킬 + /yakcloud 슬래시명령.
|
||||
# 프로젝트엔 복제하지 않는다(전역 1벌, 버전 파편화 없음). Claude 자산 opt-out: YAKCLOUD_NO_CLAUDE_CMD=1.
|
||||
install_global_assets() {
|
||||
local bust; bust="$(date +%s 2>/dev/null || echo 0)" n ok=1
|
||||
mkdir -p "$LIB_DIR" 2>/dev/null || true
|
||||
for n in deploy ctl dev; do
|
||||
curl -fsSL -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' \
|
||||
"$REPO/raw/branch/$BRANCH/.yakcloud/$n.py?nocache=$bust" -o "$LIB_DIR/$n.py" 2>/dev/null || ok=0
|
||||
done
|
||||
[ "$ok" = 1 ] && echo "✓ 엔진 → $LIB_DIR (deploy/ctl/dev.py)" || echo " ⚠ 엔진 일부 다운로드 실패(무시 가능 — 필요 시 자동 재시도)"
|
||||
[ -z "${YAKCLOUD_NO_CLAUDE_CMD:-}" ] || return 0
|
||||
local dir="${CLAUDE_COMMANDS_DIR:-$HOME/.claude/commands}"
|
||||
local bust; bust="$(date +%s 2>/dev/null || echo 0)"
|
||||
if mkdir -p "$dir" 2>/dev/null && \
|
||||
curl -fsSL -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' \
|
||||
"$REPO/raw/branch/$BRANCH/.claude/commands/yakcloud.md?nocache=$bust" -o "$dir/yakcloud.md" 2>/dev/null; then
|
||||
echo "✓ Claude Code 전역 슬래시 명령 → $dir/yakcloud.md (Claude Code에서 /yakcloud)"
|
||||
else
|
||||
echo " ⚠ /yakcloud 슬래시 명령 설치 건너뜀(무시 가능) — 터미널 yakcloud 는 정상"
|
||||
fi
|
||||
local sdir="${CLAUDE_SKILLS_DIR:-$HOME/.claude/skills}/yakcloud-deploy"
|
||||
local cdir="${CLAUDE_COMMANDS_DIR:-$HOME/.claude/commands}"
|
||||
mkdir -p "$sdir" "$cdir" 2>/dev/null || true
|
||||
curl -fsSL -H 'Cache-Control: no-cache' "$REPO/raw/branch/$BRANCH/.claude/skills/yakcloud-deploy/SKILL.md?nocache=$bust" -o "$sdir/SKILL.md" 2>/dev/null \
|
||||
&& echo "✓ 배포 스킬 → $sdir/SKILL.md" || echo " ⚠ 스킬 설치 건너뜀(무시 가능)"
|
||||
curl -fsSL -H 'Cache-Control: no-cache' "$REPO/raw/branch/$BRANCH/.claude/commands/yakcloud.md?nocache=$bust" -o "$cdir/yakcloud.md" 2>/dev/null \
|
||||
&& echo "✓ /yakcloud 슬래시 명령 → $cdir/yakcloud.md" || echo " ⚠ 슬래시 명령 설치 건너뜀(무시 가능)"
|
||||
}
|
||||
|
||||
cmd_upgrade() {
|
||||
@ -517,28 +535,23 @@ cmd_upgrade() {
|
||||
mv "$tmp" "$self" 2>/dev/null || { rm -f "$tmp"; die "설치 실패(권한) — 'DEST=<dir> 재설치' 또는 sudo"; }
|
||||
hash -r 2>/dev/null || true # 셸 명령 해시 캐시 초기화(새 바이너리 즉시 반영)
|
||||
echo "✓ 업그레이드 완료: $before → $("$self" version 2>/dev/null || echo yakcloud)"
|
||||
install_claude_command # /yakcloud 슬래시 명령도 최신화
|
||||
install_global_assets # 전역 엔진(deploy/ctl/dev) + 스킬 + /yakcloud 명령도 최신화
|
||||
}
|
||||
|
||||
# 기존 프로젝트의 플러밍(엔진·CI·스킬)만 최신화. 앱/매니페스트/Dockerfile 등 사용자 파일은 보존.
|
||||
cmd_project_update() {
|
||||
[ -f yakcloud.yaml ] || die "프로젝트 폴더가 아닙니다 — 'yakcloud project init' 먼저"
|
||||
command -v git >/dev/null 2>&1 || die "git 이 필요합니다."
|
||||
info "프로젝트 플러밍 최신화(앱·매니페스트 보존)… ($REPO @ $BRANCH)"
|
||||
info "CI(.gitea) 최신화 + 전역 엔진/스킬 갱신(앱·매니페스트 보존)… ($REPO @ $BRANCH)"
|
||||
local tmp; tmp="$(mktemp -d)"
|
||||
git clone -q --depth 1 -b "$BRANCH" "$REPO.git" "$tmp/s" || { rm -rf "$tmp"; die "클론 실패"; }
|
||||
mkdir -p scripts .gitea/workflows .claude/skills
|
||||
cp "$tmp/s/scripts/yakcloud_deploy.py" scripts/ 2>/dev/null || true
|
||||
cp "$tmp/s/scripts/yakcloud_ctl.py" scripts/ 2>/dev/null || true
|
||||
cp "$tmp/s/scripts/yakcloud_dev.py" scripts/ 2>/dev/null || true # 로컬 kind 리컨실 엔진(직선 dev)
|
||||
rm -f scripts/yakcloud_migrate.py # 옛 migrate 잔재 제거
|
||||
cp "$tmp/s/.gitea/workflows/deploy.yml" .gitea/workflows/ 2>/dev/null || true
|
||||
rm -rf .claude/skills/yakcloud-deploy
|
||||
cp -R "$tmp/s/.claude/skills/yakcloud-deploy" .claude/skills/ 2>/dev/null || true
|
||||
mkdir -p .gitea/workflows
|
||||
cp "$tmp/s/.gitea/workflows/deploy.yml" .gitea/workflows/ 2>/dev/null || true # 얇은 CI(전역 엔진 받아 실행)
|
||||
rm -rf "$tmp"
|
||||
# 비프로젝트 파일 정리(스캐폴드 최소화): CLI 배포용 + 전역 슬래시명령 + 스타터 문서.
|
||||
rm -rf bin install.sh .claude/commands README.md DATA-SOURCES.md
|
||||
echo "✓ 최신화 완료 — scripts/·.gitea/·.claude/skills 갱신(app.py·yakcloud.yaml·Dockerfile 그대로)"
|
||||
# 엔진·스킬·명령은 전역(프로젝트에 복제 안 함). 옛 per-project 잔재 제거.
|
||||
rm -rf scripts .yakcloud .claude bin install.sh README.md DATA-SOURCES.md
|
||||
install_global_assets # 전역 엔진(deploy/ctl/dev) + 스킬 + /yakcloud 명령 최신화
|
||||
echo "✓ 최신화 완료 — .gitea CI + 전역 엔진/스킬 갱신(app.py·yakcloud.yaml·Dockerfile 그대로)"
|
||||
}
|
||||
|
||||
usage() {
|
||||
|
||||
27
install.sh
27
install.sh
@ -14,16 +14,27 @@ curl -fsSL -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' \
|
||||
"$REPO/raw/branch/$BRANCH/bin/yakcloud?nocache=$BUST" -o "$DEST/yakcloud"
|
||||
chmod +x "$DEST/yakcloud"
|
||||
|
||||
# Claude Code 전역 슬래시 명령(/yakcloud) 설치 — opt-out: YAKCLOUD_NO_CLAUDE_CMD=1
|
||||
# 전역 엔진(deploy/ctl/dev.py) → ~/.config/yakcloud/lib — 프로젝트에 복제하지 않는다(전역 1벌).
|
||||
LIB_DIR="${YAKCLOUD_LIB_DIR:-$HOME/.config/yakcloud/lib}"
|
||||
mkdir -p "$LIB_DIR"
|
||||
for n in deploy ctl dev; do
|
||||
curl -fsSL -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' \
|
||||
"$REPO/raw/branch/$BRANCH/.yakcloud/$n.py?nocache=$BUST" -o "$LIB_DIR/$n.py" 2>/dev/null \
|
||||
|| echo " ⚠ 엔진 $n 다운로드 실패(무시 가능 — CLI 가 자동 재시도)"
|
||||
done
|
||||
echo "✓ 엔진 설치 → $LIB_DIR (deploy/ctl/dev.py)"
|
||||
|
||||
# Claude Code 전역 스킬 + 슬래시 명령(/yakcloud) 설치 — opt-out: YAKCLOUD_NO_CLAUDE_CMD=1
|
||||
if [ -z "${YAKCLOUD_NO_CLAUDE_CMD:-}" ]; then
|
||||
SKILL_DIR="${CLAUDE_SKILLS_DIR:-$HOME/.claude/skills}/yakcloud-deploy"
|
||||
CMD_DIR="${CLAUDE_COMMANDS_DIR:-$HOME/.claude/commands}"
|
||||
if mkdir -p "$CMD_DIR" 2>/dev/null && \
|
||||
curl -fsSL -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' \
|
||||
"$REPO/raw/branch/$BRANCH/.claude/commands/yakcloud.md?nocache=$BUST" -o "$CMD_DIR/yakcloud.md" 2>/dev/null; then
|
||||
echo "✓ Claude Code 전역 슬래시 명령 설치 → $CMD_DIR/yakcloud.md"
|
||||
else
|
||||
echo " ⚠ /yakcloud 슬래시 명령 설치 건너뜀(무시 가능) — 터미널 yakcloud 는 정상"
|
||||
fi
|
||||
mkdir -p "$SKILL_DIR" "$CMD_DIR" 2>/dev/null || true
|
||||
curl -fsSL -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' \
|
||||
"$REPO/raw/branch/$BRANCH/.claude/skills/yakcloud-deploy/SKILL.md?nocache=$BUST" -o "$SKILL_DIR/SKILL.md" 2>/dev/null \
|
||||
&& echo "✓ 배포 스킬 설치 → $SKILL_DIR/SKILL.md" || echo " ⚠ 스킬 설치 건너뜀(무시 가능)"
|
||||
curl -fsSL -H 'Cache-Control: no-cache' -H 'Pragma: no-cache' \
|
||||
"$REPO/raw/branch/$BRANCH/.claude/commands/yakcloud.md?nocache=$BUST" -o "$CMD_DIR/yakcloud.md" 2>/dev/null \
|
||||
&& echo "✓ /yakcloud 슬래시 명령 설치 → $CMD_DIR/yakcloud.md" || echo " ⚠ 슬래시 명령 설치 건너뜀(무시 가능)"
|
||||
fi
|
||||
|
||||
echo "✓ 완료. PATH 에 $DEST 가 있는지 확인하세요:"
|
||||
|
||||
@ -17,22 +17,19 @@ environments:
|
||||
val: { cluster: my-val-cluster } # promote --to val
|
||||
prod: { cluster: my-prod-cluster, domains: [] } # promote --to prod (domains 예: [app.example.com])
|
||||
|
||||
# 필요한 데이터 소스(논리 이름). 없으면 [] 로 둬도 됨.
|
||||
# type ∈ postgresql·mysql·mariadb·mongodb·redis·minio·rabbitmq·solr·oracle, plan ∈ small·medium·large
|
||||
# ⚠ 이름이 클러스터의 기존 READY 소스와 일치하면 스킵·바인딩.
|
||||
# - 인클러스터(local) 소스: 배포 토큰에 생성 권한이 있으면 자동 프로비저닝(없으면 405 → 콘솔에서 먼저 만들고 이 name 사용).
|
||||
# - 공유 외부(shared) 소스(소용량 S 클러스터용): 아래처럼 mode: shared 로 선언(또는 'yakcloud source add <name> mongodb --shared').
|
||||
# 배포 시 백엔드가 클러스터별 격리 DB/계정을 민팅(인클러스터 StatefulSet 불필요). 콘솔/API 등록도 가능. 예:
|
||||
# - { name: appdb, type: mongodb, mode: shared }
|
||||
# ('yakcloud project check' 로 미리 확인·리스팅)
|
||||
# 필요한 데이터 소스(논리 이름). 없으면 [] 로. 기본 = **공유(shared)** — 이미 있는 공유 소스에 연결 + 격리 DB 민팅.
|
||||
# type ∈ postgresql·mysql·mariadb·mongodb·redis·minio·rabbitmq·solr·oracle
|
||||
# - 기본(shared, mode 생략): 공유 외부 서버에 클러스터/프로젝트별 **격리 DB·계정** 민팅(인클러스터 리소스 생성 없음).
|
||||
# - 인클러스터(옵션): 정말 전용 인스턴스가 필요할 때만 `mode: local, plan: small|medium|large`.
|
||||
# - 이름이 클러스터의 기존 READY 소스와 일치하면 스킵·바인딩. ('yakcloud project check' 로 미리 확인)
|
||||
requires:
|
||||
- { name: appdb, type: postgresql, plan: small }
|
||||
- { name: appdb, type: postgresql } # 기본 shared. 전용 인스턴스는 { …, mode: local, plan: small }
|
||||
|
||||
# 워크로드(앱 컨테이너). CI 는 각 workload.build 를 도커 빌드해 image 로 push 한다(${TAG}=릴리스 태그).
|
||||
workloads:
|
||||
- name: web
|
||||
- name: my-app # 배포(워크로드)명 = 프로젝트명(권장). 'project init <name>' 이 프로젝트명으로 설정.
|
||||
build: ./ # 도커 빌드 컨텍스트(Dockerfile 위치). 예: ./ 또는 ./api
|
||||
image: gitea.yakenator.io/CHANGE_ME_GITEA_USER/my-app-web:${TAG}
|
||||
image: gitea.yakenator.io/CHANGE_ME_GITEA_USER/my-app:${TAG}
|
||||
port: 8080
|
||||
replicas: 2 # ≥2 → 무중단 롤링(readiness 게이트)
|
||||
health: /healthz
|
||||
|
||||
Reference in New Issue
Block a user