cli v0.12.2: 개발→검증→운영 3단계 — promote --to <env> 일반화, environments 템플릿 dev/val/prod, init 마법사 검증 클러스터
This commit is contained in:
@ -20,8 +20,8 @@ allowed-tools: Bash, Read, Write, Edit, Glob, Grep, AskUserQuestion
|
|||||||
- **`login`** → 비밀 입력이라 여기서 실행하지 말고, 터미널에서 `yakcloud login` 하라고 한 줄 안내.
|
- **`login`** → 비밀 입력이라 여기서 실행하지 말고, 터미널에서 `yakcloud login` 하라고 한 줄 안내.
|
||||||
(사용자가 값을 직접 주면 `YAKCLOUD_URL=… YAKCLOUD_TOKEN=… GITEA_USER=… GITEA_TOKEN=… yakcloud config` 로 저장하되 **값은 화면에 출력 금지**.)
|
(사용자가 값을 직접 주면 `YAKCLOUD_URL=… YAKCLOUD_TOKEN=… GITEA_USER=… GITEA_TOKEN=… yakcloud config` 로 저장하되 **값은 화면에 출력 금지**.)
|
||||||
- **`cluster create <name> …`** → 배포토큰으로 클러스터 프로비저닝(5~8분 대기). 실행 전 무엇을(템플릿·노드 수) 만드는지 한 줄 알리고 진행. `cluster ls` = 목록.
|
- **`cluster create <name> …`** → 배포토큰으로 클러스터 프로비저닝(5~8분 대기). 실행 전 무엇을(템플릿·노드 수) 만드는지 한 줄 알리고 진행. `cluster ls` = 목록.
|
||||||
- **`project promote [vX.Y.Z]`** → 개발에서 검증한 그 이미지를 **재빌드 없이 운영 클러스터로** 승격 + 운영 도메인.
|
- **`project promote [vX.Y.Z] [--to val|prod]`** → 그 이미지를 **재빌드 없이 상위 환경으로** 승격(개발→검증→운영, 기본 --to prod).
|
||||||
파괴적/외부노출이므로 실행 전 무엇을(어느 태그를 어느 운영 클러스터로) 하는지 한 줄 알리고 진행.
|
파괴적/외부노출이므로 실행 전 무엇을(어느 태그를 어느 환경 클러스터로) 하는지 한 줄 알리고 진행.
|
||||||
- **그 외 전부**(`project deploy|info|check|update`, `datasource ls`, `domain`, `scale`, `set`, `env`,
|
- **그 외 전부**(`project deploy|info|check|update`, `datasource ls`, `domain`, `scale`, `set`, `env`,
|
||||||
`source`, `bind`, `unbind`, `config`, `upgrade`) → `yakcloud $ARGUMENTS` 를 실행하고 **출력을 그대로** 보여준 뒤,
|
`source`, `bind`, `unbind`, `config`, `upgrade`) → `yakcloud $ARGUMENTS` 를 실행하고 **출력을 그대로** 보여준 뒤,
|
||||||
필요할 때만 한 줄로 해석. 배포/승격/삭제성(`deploy`·`promote`·`source rm`·`unbind`·`domain`)은 실행 전 무엇을 하는지 한 줄 알리고 진행.
|
필요할 때만 한 줄로 해석. 배포/승격/삭제성(`deploy`·`promote`·`source rm`·`unbind`·`domain`)은 실행 전 무엇을 하는지 한 줄 알리고 진행.
|
||||||
|
|||||||
@ -26,7 +26,7 @@ YakCloud 콘솔 API로 **데이터소스 리컨실 + 워크로드 배포 + 바
|
|||||||
- **"클러스터 생성"** → `yakcloud cluster create <name> [--template S|M] [--nodes N] [--golden]` (배포토큰으로 프로비저닝, 완료까지 대기). `yakcloud cluster ls` 로 목록. 개발/운영 각각 만들어 매니페스트 environments 에 지정.
|
- **"클러스터 생성"** → `yakcloud cluster create <name> [--template S|M] [--nodes N] [--golden]` (배포토큰으로 프로비저닝, 완료까지 대기). `yakcloud cluster ls` 로 목록. 개발/운영 각각 만들어 매니페스트 environments 에 지정.
|
||||||
- **"프로젝트 초기화"** → 빈 폴더에서 `yakcloud project init [name]` (스타터+CI+매니페스트+이 스킬)
|
- **"프로젝트 초기화"** → 빈 폴더에서 `yakcloud project init [name]` (스타터+CI+매니페스트+이 스킬)
|
||||||
- **"개발 배포"** → `yakcloud project deploy` (자동 버전업 → 태그 push → CI 빌드 → **개발 클러스터**). 기본 도메인으로 확인.
|
- **"개발 배포"** → `yakcloud project deploy` (자동 버전업 → 태그 push → CI 빌드 → **개발 클러스터**). 기본 도메인으로 확인.
|
||||||
- **"운영 승격"** → `yakcloud project promote [vX.Y.Z]` (개발에서 검증한 **그 이미지를 재빌드 없이 운영 클러스터로** + 운영 도메인)
|
- **"승격"**(개발→검증→운영) → `yakcloud project promote [vX.Y.Z] [--to val|prod]` (그 이미지를 **재빌드 없이 상위 환경으로**; `--to prod` 는 운영 도메인 부착). 검증계(val)는 선택 — `environments` 에 없으면 개발→운영 2단계
|
||||||
- **"프로젝트 개괄"** → `yakcloud project info` · 사전 점검 → `yakcloud project check [--prod]`
|
- **"프로젝트 개괄"** → `yakcloud project info` · 사전 점검 → `yakcloud project check [--prod]`
|
||||||
- 매니페스트 `environments.{dev,prod}.cluster` (+ `prod.domains`). 로컬 개발/로컬 데이터소스는 없음 — 개발도 클러스터 배포로 확인.
|
- 매니페스트 `environments.{dev,prod}.cluster` (+ `prod.domains`). 로컬 개발/로컬 데이터소스는 없음 — 개발도 클러스터 배포로 확인.
|
||||||
|
|
||||||
|
|||||||
30
bin/yakcloud
30
bin/yakcloud
@ -3,7 +3,7 @@
|
|||||||
#
|
#
|
||||||
# yakcloud project init [name] 빈 폴더에 스타터 스캐폴딩(앱+CI+매니페스트+Claude 스킬)
|
# yakcloud project init [name] 빈 폴더에 스타터 스캐폴딩(앱+CI+매니페스트+Claude 스킬)
|
||||||
# yakcloud project deploy [vX.Y.Z] 커밋 + 태그 push → CI 빌드 → 개발 클러스터 배포
|
# yakcloud project deploy [vX.Y.Z] 커밋 + 태그 push → CI 빌드 → 개발 클러스터 배포
|
||||||
# yakcloud project promote [vX.Y.Z] 그 이미지를 재빌드 없이 운영 클러스터로 승격 + 운영 도메인
|
# yakcloud project promote [vX.Y.Z] [--to val|prod] 그 이미지를 재빌드 없이 상위 환경으로 승격(개발→검증→운영)
|
||||||
# yakcloud project info 프로젝트 개괄(매니페스트 + dev/prod 라이브 상태)
|
# yakcloud project info 프로젝트 개괄(매니페스트 + dev/prod 라이브 상태)
|
||||||
# yakcloud project check [--prod] dry-run(직접 API 계획만)
|
# yakcloud project check [--prod] dry-run(직접 API 계획만)
|
||||||
#
|
#
|
||||||
@ -14,7 +14,7 @@ set -uo pipefail # -e 미사용: 'test && action' 관용구가 값 없을 때
|
|||||||
|
|
||||||
REPO="${YAKCLOUD_STARTER_REPO:-https://gitea.yakenator.io/yakenator/yakcloud-starter}"
|
REPO="${YAKCLOUD_STARTER_REPO:-https://gitea.yakenator.io/yakenator/yakcloud-starter}"
|
||||||
BRANCH="${YAKCLOUD_STARTER_BRANCH:-main}"
|
BRANCH="${YAKCLOUD_STARTER_BRANCH:-main}"
|
||||||
VERSION="0.12.1"
|
VERSION="0.12.2"
|
||||||
CONFIG_DIR="${YAKCLOUD_CONFIG_DIR:-$HOME/.config/yakcloud}"
|
CONFIG_DIR="${YAKCLOUD_CONFIG_DIR:-$HOME/.config/yakcloud}"
|
||||||
CONFIG_FILE="$CONFIG_DIR/config"
|
CONFIG_FILE="$CONFIG_DIR/config"
|
||||||
|
|
||||||
@ -158,10 +158,11 @@ cmd_project_init() {
|
|||||||
|
|
||||||
# 매니페스트 채우기 마법사 — ctl 은 API 미접속(YAKCLOUD_TOKEN 비움)으로 매니페스트만 편집.
|
# 매니페스트 채우기 마법사 — ctl 은 API 미접속(YAKCLOUD_TOKEN 비움)으로 매니페스트만 편집.
|
||||||
_init_wizard() {
|
_init_wizard() {
|
||||||
local dflt_app="$1" app devc prodc pdom port health cpu mem reps path kv
|
local dflt_app="$1" app devc valc prodc pdom port health cpu mem reps path kv
|
||||||
echo "── 프로젝트 설정 (엔터=기본값) ──"
|
echo "── 프로젝트 설정 (엔터=기본값) · 개발 → 검증 → 운영 3단계 ──"
|
||||||
printf "앱 이름 [%s]: " "$dflt_app"; read -r app; app="${app:-$dflt_app}"
|
printf "앱 이름 [%s]: " "$dflt_app"; read -r app; app="${app:-$dflt_app}"
|
||||||
printf "개발 클러스터(이름 또는 콘솔 id): "; read -r devc
|
printf "개발 클러스터(이름 또는 콘솔 id): "; read -r devc
|
||||||
|
printf "검증 클러스터(선택, 엔터=생략): "; read -r valc
|
||||||
printf "운영 클러스터 [%s]: " "${devc:-개발과 동일}"; read -r prodc; prodc="${prodc:-$devc}"
|
printf "운영 클러스터 [%s]: " "${devc:-개발과 동일}"; read -r prodc; prodc="${prodc:-$devc}"
|
||||||
printf "운영 도메인(선택, 예 app.example.com): "; read -r pdom
|
printf "운영 도메인(선택, 예 app.example.com): "; read -r pdom
|
||||||
printf "컨테이너 포트 [8080]: "; read -r port; port="${port:-8080}"
|
printf "컨테이너 포트 [8080]: "; read -r port; port="${port:-8080}"
|
||||||
@ -176,6 +177,8 @@ _init_wizard() {
|
|||||||
[ -n "$devc" ] && { sed -i.bak "s#my-dev-cluster#$devc#" yakcloud.yaml && 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 "$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; }
|
[ -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
|
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 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 scripts/yakcloud_ctl.py scale web "$reps" >/dev/null 2>&1 || true
|
||||||
@ -184,7 +187,7 @@ _init_wizard() {
|
|||||||
printf " env> "; read -r kv || break; [ -z "$kv" ] && break
|
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 scripts/yakcloud_ctl.py env web "$kv" >/dev/null 2>&1 || echo " (형식: KEY=VALUE)"
|
||||||
done
|
done
|
||||||
echo "✓ 매니페스트 반영: app=$app dev=${devc:-<미지정>} prod=${prodc:-<미지정>} port=$port path=$path cpu=$cpu mem=$mem replicas=$reps"
|
echo "✓ 매니페스트 반영: app=$app dev=${devc:-<미지정>} val=${valc:-<생략>} prod=${prodc:-<미지정>} port=$port path=$path cpu=$cpu mem=$mem replicas=$reps"
|
||||||
}
|
}
|
||||||
|
|
||||||
_maybe_login_prompt() {
|
_maybe_login_prompt() {
|
||||||
@ -280,16 +283,23 @@ cmd_project_promote() {
|
|||||||
[ -f scripts/yakcloud_deploy.py ] || die "'yakcloud project init' 먼저"
|
[ -f scripts/yakcloud_deploy.py ] || die "'yakcloud project init' 먼저"
|
||||||
: "${YAKCLOUD_URL:?YAKCLOUD_URL 필요 — 'yakcloud login'}"; : "${YAKCLOUD_TOKEN:?YAKCLOUD_TOKEN 필요 — 'yakcloud login'}"
|
: "${YAKCLOUD_URL:?YAKCLOUD_URL 필요 — 'yakcloud login'}"; : "${YAKCLOUD_TOKEN:?YAKCLOUD_TOKEN 필요 — 'yakcloud login'}"
|
||||||
ensure_pyyaml
|
ensure_pyyaml
|
||||||
local tag=""; for a in "$@"; do case "$a" in -*) : ;; *) [ -z "$tag" ] && tag="$a" ;; esac; done
|
local tag="" env="prod"
|
||||||
|
while [ "$#" -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
--to|--env) env="${2:-prod}"; shift 2 || shift ;;
|
||||||
|
-*) shift ;;
|
||||||
|
*) [ -z "$tag" ] && tag="$1"; shift ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
if [ -z "$tag" ]; then
|
if [ -z "$tag" ]; then
|
||||||
git fetch -q --tags origin 2>/dev/null || true
|
git fetch -q --tags origin 2>/dev/null || true
|
||||||
tag="$(git tag -l 'v*' --sort=-v:refname 2>/dev/null | head -1)"
|
tag="$(git tag -l 'v*' --sort=-v:refname 2>/dev/null | head -1)"
|
||||||
fi
|
fi
|
||||||
[ -n "$tag" ] || die "승격할 태그가 없습니다 — 'yakcloud project promote vX.Y.Z' (개발 배포된 태그)"
|
[ -n "$tag" ] || die "승격할 태그가 없습니다 — 'yakcloud project promote vX.Y.Z' (개발 배포된 태그)"
|
||||||
case "$tag" in v*) : ;; *) tag="v$tag" ;; esac
|
case "$tag" in v*) : ;; *) tag="v$tag" ;; esac
|
||||||
info "운영 승격: $tag → prod 환경(재빌드 없이 개발에서 빌드된 그 이미지를 운영 클러스터로 리컨실)"
|
info "'$env' 승격: $tag → '$env' 환경(재빌드 없이 개발에서 빌드된 그 이미지를 리컨실)"
|
||||||
YAKCLOUD_ENV=prod TAG="$tag" python3 scripts/yakcloud_deploy.py yakcloud.yaml
|
YAKCLOUD_ENV="$env" TAG="$tag" python3 scripts/yakcloud_deploy.py yakcloud.yaml
|
||||||
echo "✓ 승격 완료: $tag → 운영 클러스터 + 운영 도메인(기본 도메인은 자동)"
|
echo "✓ 승격 완료: $tag → '$env' 클러스터 + 도메인(기본 도메인은 자동)"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 클러스터 — 계정 배포토큰으로 생성/조회(프로젝트 폴더 불필요). POST /clusters(템플릿) + 프로비저닝 폴.
|
# 클러스터 — 계정 배포토큰으로 생성/조회(프로젝트 폴더 불필요). POST /clusters(템플릿) + 프로비저닝 폴.
|
||||||
@ -433,7 +443,7 @@ yakcloud $VERSION — YakCloud 프로젝트 CLI (개발·운영 모두 yakcloud
|
|||||||
project init [name] 빈 폴더에 스타터 스캐폴딩(대화형 마법사) + 자격 프롬프트
|
project init [name] 빈 폴더에 스타터 스캐폴딩(대화형 마법사) + 자격 프롬프트
|
||||||
project deploy [vX.Y.Z] 커밋 + 태그 push → CI 빌드 → **개발 클러스터** 배포(버전 생략=자동 버전업)
|
project deploy [vX.Y.Z] 커밋 + 태그 push → CI 빌드 → **개발 클러스터** 배포(버전 생략=자동 버전업)
|
||||||
project deploy --local 러너 없이 로컬 build/push/리컨실(CI 대안, 개발 클러스터)
|
project deploy --local 러너 없이 로컬 build/push/리컨실(CI 대안, 개발 클러스터)
|
||||||
project promote [vX.Y.Z] 개발에서 검증한 그 이미지를 재빌드 없이 **운영 클러스터**로 승격 + 운영 도메인
|
project promote [vX.Y.Z] [--to val|prod] 그 이미지를 재빌드 없이 상위 환경으로 승격(개발→검증→운영). 기본 --to prod
|
||||||
project info 프로젝트 개괄(매니페스트 + dev/prod 라이브 상태)
|
project info 프로젝트 개괄(매니페스트 + dev/prod 라이브 상태)
|
||||||
project check [--prod] dry-run(직접 API 계획만)
|
project check [--prod] dry-run(직접 API 계획만)
|
||||||
project update 이 프로젝트의 엔진·CI·스킬만 최신화(앱·매니페스트 보존)
|
project update 이 프로젝트의 엔진·CI·스킬만 최신화(앱·매니페스트 보존)
|
||||||
|
|||||||
@ -6,11 +6,14 @@
|
|||||||
apiVersion: yakcloud/v1
|
apiVersion: yakcloud/v1
|
||||||
project: my-app # 프로젝트 이름(이미지 경로/표시에 사용) — 소문자·숫자·하이픈
|
project: my-app # 프로젝트 이름(이미지 경로/표시에 사용) — 소문자·숫자·하이픈
|
||||||
|
|
||||||
# 환경 — 개발/운영 클러스터. 'yakcloud project deploy'=dev 로 배포, 'yakcloud project promote'=그 이미지를
|
# 환경 — 개발 → 검증 → 운영 3단계. 각 환경 = 별도 클러스터. 검증계(val)가 필요 없으면 그 줄을 지워도 됩니다.
|
||||||
# 재빌드 없이 prod 로 승격(운영 도메인 부착; 기본 도메인 c-xxxx.yakenator.io 은 두 환경 모두 자동).
|
# deploy → dev (태그 push → CI 빌드 → 개발 클러스터, 기본 도메인으로 확인)
|
||||||
|
# promote --to val→ 그 이미지를 재빌드 없이 검증 클러스터로
|
||||||
|
# promote --to prod→ 검증 통과분을 운영 클러스터로 + 운영 도메인(기본 도메인 c-xxxx.yakenator.io 은 자동)
|
||||||
environments:
|
environments:
|
||||||
dev: { cluster: my-dev-cluster } # 태그 push → CI 빌드 → 개발 클러스터
|
dev: { cluster: my-dev-cluster } # deploy 대상(기본)
|
||||||
prod: { cluster: my-prod-cluster, domains: [] } # promote → 운영 클러스터 + domains(예: [app.example.com])
|
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
|
# type ∈ postgresql·mysql·mariadb·mongodb·redis·minio·rabbitmq·solr·oracle, plan ∈ small·medium·large
|
||||||
|
|||||||
Reference in New Issue
Block a user