@bifos/nhncloud-cli 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,897 +5,249 @@
5
5
  [![CI](https://github.com/jon890/nhncloud-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/jon890/nhncloud-cli/actions/workflows/ci.yml)
6
6
  [![license](https://img.shields.io/npm/l/@bifos/nhncloud-cli.svg)](https://github.com/jon890/nhncloud-cli/blob/main/LICENSE)
7
7
 
8
- NHN Cloud 서비스를 AWS CLI 방식으로 호출하는 통합 CLI.
9
- 현재 147개 command catalog 항목을 지원한다.
10
- `configure`, `commands`, `logncrash search/send/export`, `deploy`, `instance`, `network`, `volume`, `floatingip` 명령을 지원한다.
11
- `loadbalancer`, `ncr`, `nks`, `ncs` 명령으로 NHN Cloud 서비스를 조회·운영할 수 있다.
12
- `skills`/`doctor` 로 Claude Code 스킬 설치와 상태 진단을 지원한다.
8
+ [NHN Cloud](https://www.nhncloud.com) 를 AI 에이전트가 다룰 수 있게 만든 CLI 다.
13
9
 
14
- ## 설치
10
+ Compute·Network·Block Storage·Load Balancer·Container Registry·Kubernetes·Container Service·Log & Crash·Deploy 를 명령 한 줄로 다루고, 결과를 `--json` 으로 내보낸다.
11
+ Claude Code 같은 에이전트에 스킬로 설치하면 "인스턴스 목록 보여줘" 같은 자연어 지시를 그대로 처리한다.
15
12
 
16
13
  ```bash
17
14
  npm install -g @bifos/nhncloud-cli
15
+ nhncloud configure
16
+ nhncloud skills install
18
17
  ```
19
18
 
20
- ## 초기 설정
19
+ ## 설치와 설정
21
20
 
22
- `nhncloud configure` 를 실행하면 대화형 마법사가 자격증명을 안내한다.
21
+ Node.js 20 이상이 필요하다.
23
22
 
24
23
  ```bash
25
- nhncloud configure
24
+ npm install -g @bifos/nhncloud-cli
26
25
  ```
27
26
 
28
- - profile → UAK(id/secret) → logncrash appkey/secret → iaas 자격증명 → ncr appkey → ncs appkey 순으로 입력한다.
29
- - profile 은 프로젝트 단위다 — 여러 NHN Cloud 프로젝트를 쓰면 profile 을 분리하되, 같은 UAK 를 쓴다면
30
- 대화형 마법사가 기존 profile 의 UAK 재사용 여부를 먼저 물어 재입력을 줄여준다.
31
- - 저장 전 연결 테스트를 자동으로 수행한다 (`--no-verify` 로 생략 가능).
32
- - CI/자동화는 flag 로 비대화형 설정이 가능하다.
27
+ `nhncloud configure` 가 profile 과 서비스별 자격증명을 대화형으로 받는다.
28
+ 공통 UAK, Log & Crash appkey, iaas 자격증명, NCR appkey, NCS appkey 순으로 입력한다.
29
+ 저장 전 연결 테스트를 자동으로 수행한다 (`--no-verify` 로 생략).
33
30
 
34
31
  ```bash
35
- # UAK + logncrash + ncs 비대화형 설정
36
- nhncloud configure \
37
- --uak-id <id> --uak-secret <secret> \
38
- --logncrash-appkey <key> --logncrash-secret <secret> \
39
- [--ncs-appkey <appkey>] \
40
- --no-verify
41
-
42
- # iaas (Compute) 비대화형 설정 — API 비밀번호는 env 권장
43
- NHNCLOUD_IAAS_PASSWORD=<api-password> nhncloud configure \
44
- --iaas-tenant-id <tenant-id> \
45
- --iaas-username <iam-username> \
46
- --iaas-region kr1 \
47
- --no-verify
32
+ nhncloud configure
33
+ nhncloud doctor # 설정이 제대로 됐는지 확인
48
34
  ```
49
35
 
50
- > **iaas password 안내**: `--iaas-password` 에 입력하는 값은 NHN Cloud 콘솔 IAM 의 **API 비밀번호**입니다.
51
- > 로그인 비밀번호와 다릅니다.
52
- > IAM 사용자 상세 페이지 → "API 비밀번호 설정"에서 별도로 발급하세요.
53
- >
54
- > **iaas username 안내**: `--iaas-username` 은 NHN Cloud 계정 이메일 또는 IAM 계정 ID(사번)입니다.
55
- > tenantId 와 비슷한 "API 사용자 ID"(UUID)가 아닙니다.
56
-
57
- 저장 경로: `~/.nhncloud/credentials.json` (mode 0600), `~/.nhncloud/config.json`.
36
+ 자격증명은 `~/.nhncloud/credentials.json`(mode 0600), 설정은 `~/.nhncloud/config.json` 에 저장한다.
37
+ profile 우선순위는 `--profile` > `NHNCLOUD_PROFILE` > `config.defaultProfile` > `default` 다.
58
38
 
59
- profile 해석 우선순위: `--profile` 옵션 > `NHNCLOUD_PROFILE` 환경변수 > `config.defaultProfile` > `"default"`.
60
-
61
- ### Claude Code 스킬 설치 (선택)
39
+ > **iaas 자격증명의 함정 두 가지**
40
+ >
41
+ > `--iaas-password` 는 NHN Cloud 콘솔 IAM 의 **API 비밀번호**다. 로그인 비밀번호와 다르다.
42
+ > IAM 사용자 상세 페이지의 "API 비밀번호 설정"에서 따로 발급한다.
43
+ >
44
+ > `--iaas-username` 은 계정 이메일 또는 **IAM 계정 ID(사번)** 다.
45
+ > tenantId 와 비슷하게 생긴 "API 사용자 ID"(UUID) 가 아니다.
62
46
 
63
- Claude Code 에서 이 CLI 를 AI 에이전트 스킬로 쓰려면 스킬을 `~/.claude/skills` 에 설치한다.
47
+ CI·자동화는 flag 로 비대화형 설정한다. 비밀번호는 환경변수를 권장한다.
64
48
 
65
49
  ```bash
66
- # 심볼릭 링크로 설치 (전역 설치 전제 — npx 환경은 불가)
67
- nhncloud skills install
68
-
69
- # 설치 상태 확인
70
- nhncloud skills
71
-
72
- # 제거
73
- nhncloud skills uninstall
50
+ NHNCLOUD_IAAS_PASSWORD=<api-password> nhncloud configure \
51
+ --uak-id <uak-id> --uak-secret <uak-secret> \
52
+ --logncrash-appkey <appkey> \
53
+ --iaas-tenant-id <tenant-id> --iaas-username <iam-username> --iaas-region kr1 \
54
+ --no-verify
74
55
  ```
75
56
 
76
- ### 상태 진단
57
+ 에이전트에서 쓰려면 스킬을 설치한다. Claude Code 가 이 CLI 의 사용법을 알게 된다.
77
58
 
78
59
  ```bash
79
- # 자격증명·스킬 설치 상태를 오프라인으로 진단
80
- nhncloud doctor
81
- ```
82
-
83
- ## 사용 예
84
-
85
- ### 배포 (Deploy)
86
-
87
- `nhncloud configure --uak-id <id> --uak-secret <secret>` 으로 UAK 를 설정한 뒤,
88
- `~/.nhncloud/config.json` 에 deploy target (배포 좌표)을 추가한다.
89
-
90
- ```json
91
- {
92
- "version": 1,
93
- "deploy": {
94
- "targets": {
95
- "my-service": {
96
- "appKey": "<appKey>",
97
- "artifactId": "<artifactId>",
98
- "serverGroupId": "<serverGroupId>",
99
- "scenarioIds": "<id1,id2>"
100
- }
101
- }
102
- }
103
- }
60
+ nhncloud skills install
61
+ nhncloud skills status
104
62
  ```
105
63
 
106
- ```bash
107
- # 배포 실행 (동기 완료 대기)
108
- nhncloud deploy run my-service
109
-
110
- # 즉시 반환 (비동기)
111
- nhncloud deploy run my-service --async
112
-
113
- # 특정 호스트만 배포
114
- nhncloud deploy run my-service --target-hosts host1,host2
115
-
116
- # 아티팩트 목록 조회
117
- nhncloud deploy artifacts my-service
64
+ 전역 설치 없이 `npx --yes @bifos/nhncloud-cli@latest skills install` 로도 설치된다 — 관리 저장소에 복사되므로 임시 패키지 경로가 사라져도 남는다.
65
+ CLI 를 새 버전으로 올린 뒤에는 `nhncloud skills update` 를 실행해야 스킬도 갱신된다.
118
66
 
119
- # 서버그룹 목록 조회
120
- nhncloud deploy server-groups my-service
67
+ 상태는 `current`, `missing`, `outdated`, `broken`, `unmanaged`, `modified`, `corrupt` 중 하나이고, 출력에 딸린 복구 명령을 따르면 된다.
68
+ 사용자 항목이나 수정·손상된 저장소는 자동으로 덮어쓰지 않는다.
121
69
 
122
- # 배포 이력 조회
123
- nhncloud deploy histories my-service
70
+ ## 사용법
124
71
 
125
- # 바이너리 그룹 목록 — 그룹 key 확인
126
- nhncloud deploy binary-groups my-service
72
+ 설정을 마치면 에이전트에게 한국어로 시키면 된다.
127
73
 
128
- # 위에서 확인한 key 로 바이너리 목록 조회
129
- nhncloud deploy binaries my-service --binary-group <key>
74
+ ```
75
+ "인스턴스 목록 보여줘"
76
+ "kr1 리전에 인스턴스 만들고 ACTIVE 될 때까지 기다려줘"
77
+ "최근 1시간 에러 로그 찾아줘"
78
+ "배포 실행하고 완료되면 알려줘"
79
+ "이 로드밸런서에 IP ACL 그룹 붙여줘"
80
+ "클러스터 kubeconfig 받아줘"
81
+ "레지스트리 이미지 태그 목록 보여줘"
82
+ ```
130
83
 
131
- # 업로드 최신순 정렬 + 전체 필드는 --json
132
- nhncloud deploy binaries my-service --binary-group <key> --sort-key UPLOAD_DATE --sort-direction DESC --json
84
+ 에이전트가 알맞은 `nhncloud` 명령으로 옮기고, 필요하면 인스턴스 id 나 VPC id 를 먼저 조회한다.
133
85
 
134
- # 바이너리 업로드 — binary-groups 로 확인한 그룹 key 에 파일 올리기
135
- nhncloud deploy upload <target> --file ./build/app.jar --binary-group <key> --description "release build"
86
+ 에이전트가 쓰는 명령 카탈로그와 판단 기준은 [스킬 문서](skills/nhncloud-cli/SKILL.md)에 있다.
87
+ 서비스별 상세는 [references/](skills/nhncloud-cli/references/) 아래 파일로 나뉘어 있다.
136
88
 
137
- # 업로드 응답의 binaryKey 만 필요하면 --quiet
138
- nhncloud deploy upload <target> --file ./build/app.jar --binary-group <key> --quiet
89
+ ## 에이전트 없이 직접 쓰기
139
90
 
140
- # 바이너리 다운로드 — 파일로 저장 (기본 덮어쓰기 거부, --force 로 강제)
141
- nhncloud deploy download <target> --binary-group <key> --binary-key <binary-key> -o ./app.jar
142
- ```
143
-
144
- ### 로그 검색
91
+ 터미널에서 바로 쓸 수도 있다.
145
92
 
146
93
  ```bash
147
- # 최근 1시간 NORMAL 로그
148
- nhncloud logncrash search \
149
- --query 'logType:"NORMAL"' \
150
- --from 1h \
151
- --to now
152
-
153
- # body 필드 키워드 검색
154
- nhncloud logncrash search \
155
- --query 'body:request_received' \
156
- --from 1h \
157
- --to now
158
-
159
- # body 부분 문자열 검색
160
- nhncloud logncrash search \
161
- --query 'body:*request_received*' \
162
- --from 1h \
163
- --to now
94
+ nhncloud instance list # 인스턴스 목록
95
+ nhncloud instance get <instance-id> # 인스턴스 상세
96
+ nhncloud network list # VPC 목록
97
+ nhncloud volume list # 블록 스토리지 볼륨
98
+ nhncloud floatingip list # Floating IP
99
+ nhncloud loadbalancer list # 로드밸런서
100
+ nhncloud ncr list # 컨테이너 레지스트리
101
+ nhncloud nks cluster list # Kubernetes 클러스터
102
+ nhncloud deploy artifacts # 배포 아티팩트
103
+ nhncloud logncrash search --query '*' --from 1h --to now # 최근 1시간 로그
104
+ nhncloud apigateway service list # API Gateway 서비스
164
105
  ```
165
106
 
166
- `--query` 는 콘솔의 간편 검색어가 아니라 Log & Crash Search API 의 Lucene 쿼리다.
167
- body 검색 의도가 명확하면 `body:<keyword>` 또는 `body:*<keyword>*` 처럼 필드를 지정한다.
168
-
169
- 시간은 상대시간 (`1h` / `30m` / `2d` / `now`) 또는 ISO8601 (`2026-05-01T00:00:00+09:00`) 로 입력한다.
170
- API 제약상 검색 시작은 최근 90일 이내, 검색 범위는 31일 이하여야 한다 (초과 시 입력 오류로 거절).
171
- 전송 직후에는 인덱싱 지연으로 잠시 0건이 나올 수 있다.
172
- 반복 검색이나 넓은 wildcard 검색은 API rate limit 에 걸릴 수 있으므로 시간 범위를 좁혀 확인한다.
173
-
174
- ### 로그 대량 추출 (export)
107
+ 전체 명령과 옵션은 `--help` 로 본다. 현재 164개다.
175
108
 
176
109
  ```bash
177
- # 검색 결과 전체를 파일로 추출 (JSON Lines, scroll 순회)
178
- nhncloud logncrash export \
179
- --query 'logType:"ERROR"' \
180
- --from 1h --to now \
181
- --output errors.jsonl
182
-
183
- # JSON 배열 형식으로 추출
184
- nhncloud logncrash export --query 'logType:"ERROR"' --from 1h --to now \
185
- --output errors.json --format json
110
+ nhncloud --help
111
+ nhncloud instance --help
112
+ nhncloud instance create --help
186
113
  ```
187
114
 
188
- 단발 검색(`search`)과 달리 scroll API 로 전체 결과(최대 10만 건)를 순회해 파일로 저장한다.
189
- 진행 상황은 stderr, 데이터는 파일에만 기록된다(stdout 비움).
190
- scrollKey 유효기간은 1분이므로 데이터가 많을 때는 `--size` 를 키워 페이지 수를 줄이는 것을 권장한다.
191
- 시간 범위 제한은 search 와 동일(90일 이내·31일 이하).
192
-
193
- #### export 옵션
194
-
195
- | 옵션 | 필수 | 설명 |
196
- |------|:---:|------|
197
- | `--query <lucene>` | 예 | Lucene 질의 문자열 |
198
- | `--from <time>` | 예 | 검색 시작 (ISO8601 또는 상대시간 `1h`/`30m`/`2d`/`now`) |
199
- | `--to <time>` | 예 | 검색 끝 |
200
- | `--output <file>` | 예 | 출력 파일 경로 |
201
- | `--format <fmt>` | 아니오 | `jsonl`(기본, 한 줄당 한 로그) 또는 `json`(배열) |
202
- | `--size <n>` | 아니오 | scroll pageSize — 범위 10~100, 기본 100 |
203
- | `--force` | 아니오 | 출력 파일이 있으면 덮어쓴다 (기본 거부) |
204
- | `--profile <name>` | 아니오 | 사용할 profile 이름 |
205
-
206
- ### 로그 전송
115
+ 기계가 읽을 카탈로그가 필요하면 `commands` 를 쓴다. 외부 API 를 호출하지 않고 Commander 트리 메타데이터만 출력한다.
207
116
 
208
117
  ```bash
209
- # 로그 한 건 전송 — 본문 직접
210
- nhncloud logncrash send --body "결제 완료" --level INFO
211
-
212
- # 파일에서 본문 읽어 전송
213
- nhncloud logncrash send --file ./error.log --level ERROR
214
-
215
- # 파이프(stdin)로 전송
216
- echo "배치 작업 종료" | nhncloud logncrash send --level INFO
217
-
218
- # 프로젝트 버전·소스 지정
219
- nhncloud logncrash send --body "deploy 시작" --app-version 2.3.0 --source batch
118
+ nhncloud commands --json | jq '.commands[] | select(.path=="nks cluster list")'
220
119
  ```
221
120
 
222
- > logncrash send 는 검색과 다른 collector 로 전송하며 appkey 만 사용한다 (secret 불요). 단일 로그 본문은 8MB 까지.
223
-
224
- ### 출력 모드
225
-
226
- | 모드 | 옵션 | 용도 |
227
- |------|------|------|
228
- | 테이블 | (기본) | 사람이 읽는 고정 컬럼 출력 |
229
- | JSON | `--json` | 자동화·AI 에이전트용 raw 데이터 + 페이지 메타 |
230
- | quiet | `--quiet` | 행별 최소 출력 |
121
+ 출력은 세 가지 모드다.
231
122
 
232
- `--json`은 CLI가 가공한 출력 계약이다.
233
- NHN Cloud 또는 OpenStack 원본 응답의 최상위 래퍼를 그대로 보존하지 않을 수 있다.
123
+ | 플래그 | 출력 | 쓰는 곳 |
124
+ | --- | --- | --- |
125
+ | (없음) | 사람이 읽는 표 | 터미널 |
126
+ | `--json` | JSON | 파싱, 명령 연결 |
127
+ | `--quiet` | 식별자만 | 스크립트 |
234
128
 
235
- ### 자동화와 AI 에이전트
129
+ 전역 옵션이라 모든 명령에 붙일 수 있다. `--no-color` 와 `--request-timeout <sec>` 도 같은 자리에서 쓴다.
130
+ 요청 타임아웃은 초 단위이며 기본값은 30초, 허용 범위는 1~3600초다.
131
+ `NHNCLOUD_REQUEST_TIMEOUT` 환경변수로도 지정할 수 있으며 명령줄 옵션이 환경변수보다 우선한다.
236
132
 
237
- 명령 경로, 인수, 옵션은 `nhncloud commands --json`으로 확인한다.
238
- 이 명령은 외부 API를 호출하지 않고 Commander tree metadata만 stdout에 출력한다.
133
+ `--json` 은 CLI 가 가공한 출력 계약이라 원본 응답의 최상위 래퍼를 그대로 보존하지 않는다.
134
+ 예를 들어 `instance get --json` 은 `.server.status` 가 아니라 `.status` 를 읽는다.
135
+ 명령별 shape 는 [common.md 의 JSON shape 요약](skills/nhncloud-cli/references/common.md)에 있다.
239
136
 
240
137
  ```bash
241
- nhncloud commands --json | jq '.commands[] | select(.path=="nks cluster list")'
242
- ```
243
-
244
- root와 주요 service group의 `--help`에는 짧은 agent hint가 포함된다.
245
- 긴 사용법은 README와 공개 skill reference를 기준으로 확인한다.
246
-
247
- | 명령 | `--json` 출력 shape |
248
- |------|---------------------|
249
- | `commands` | `{ commands: [{ path, description, arguments, options, subcommands }] }` |
250
- | `logncrash search` | `{ totalItems, pageNumber, pageSize, data }` 객체 |
251
- | `logncrash export` | 파일 출력 전용. stdout JSON 없음 |
252
- | `deploy artifacts` | Deploy API `body` 객체 |
253
- | `deploy server-groups` | Deploy API `body` 객체 |
254
- | `deploy histories` | Deploy API `body` 객체 |
255
- | `deploy binary-groups` | `binaryGroups` 래퍼를 언랩한 배열 |
256
- | `deploy binaries` | `{ totalCount, binaries }` 객체 |
257
- | `deploy upload` | `{ downloadUrl, binaryKey }` 객체 |
258
- | `instance list` | `servers` 래퍼를 언랩한 server 배열 |
259
- | `instance get` | `server` 래퍼를 언랩한 단일 server 객체 |
260
- | `instance create --wait` | `server` 래퍼를 언랩한 단일 server 객체 |
261
- | `instance flavors` | `flavors` 래퍼를 언랩한 flavor 배열 |
262
- | `instance images` | `images` 래퍼를 언랩한 image 배열 |
263
- | `instance availability-zones` | `availabilityZoneInfo` 래퍼를 언랩한 배열 |
264
- | `instance keypairs` | `keypairs[].keypair`를 flatten한 keypair 배열 |
265
- | `instance volumes` | `volumeAttachments` 래퍼를 언랩한 attachment 배열 |
266
- | `network list` | VPC 배열 |
267
- | `network subnet list` | subnet 배열 |
268
- | `volume list` | volume 배열 |
269
- | `volume get` | 단일 volume 객체 |
270
- | `volume create` | 단일 volume 객체 |
271
- | `floatingip list` | floating IP 배열 |
272
- | `floatingip create` | 단일 floating IP 객체 |
273
- | `loadbalancer list` | Load Balancer 배열 |
274
- | `loadbalancer get` | 단일 Load Balancer 객체 |
275
- | `loadbalancer ipacl list` | IP ACL 그룹 배열 |
276
- | `loadbalancer ipacl get` | 단일 IP ACL 그룹 객체 |
277
- | `loadbalancer ipacl target list` | IP ACL 대상 배열 |
278
- | `loadbalancer ipacl create/delete` | 작업 상태와 IP ACL 그룹 UUID 객체 |
279
- | `loadbalancer ipacl target add/remove` | 대상 UUID와 재바인딩 결과 객체 |
280
- | `loadbalancer set-ipacl/clear-ipacl` | 작업 상태와 Load Balancer UUID·그룹 UUID 객체 |
281
- | `ncr list` | `registries` 래퍼를 언랩한 registry 배열 |
282
- | `ncr get` | `registry` 래퍼를 언랩한 단일 registry 객체 |
283
- | `ncr images` | repository 배열 |
284
- | `ncr tags` | tag 배열 |
285
- | `nks supports` | 지원 Kubernetes version / event type 객체 |
286
- | `nks cluster list` | cluster 배열 |
287
- | `nks cluster events` | event 배열 |
288
- | `nks nodegroup list` | nodegroup 배열 |
289
- | `nks addon-type list` | addon type 배열 |
290
- | `nks addon list` | addon 배열 |
291
- | `nks cluster addon list` | cluster addon 배열 |
292
-
293
- NKS의 단건 조회는 API 객체를 그대로 반환한다.
294
- 예를 들어 `nks cluster get`, `nks cluster event`, `nks nodegroup get`, `nks addon-type get`, `nks addon get`, `nks cluster addon get`, `nks cluster ipacl`, `nks nodegroup autoscale` 은 table 출력용 최소 컬럼을 만들고 `--json` 에서는 raw 객체를 보존한다.
295
- NKS 쓰기 명령 중 생성·resize·설정 변경·노드 action·애드온 변경은 `{ uuid }` 응답을 반환한다.
296
- 삭제 명령은 성공 메시지만 stderr에 쓰고 stdout은 비운다.
297
- `nks cluster kubeconfig` 는 kubeconfig 문자열을 stdout 또는 파일로 저장한다.
298
-
299
- 예를 들어 `instance get --json`은 `.server.status`가 아니라 `.status`를 읽는다.
300
-
301
- ### 체이닝 예시
302
-
303
- ```bash
304
- # 인스턴스 상태 확인
305
138
  nhncloud instance get <instance-id> --json | jq -r '.status'
306
-
307
- # 검색 결과에서 logBody 만 추출
308
139
  nhncloud logncrash search --query '*' --from 1h --to now --json | jq -r '.data[].logBody'
309
-
310
- # 전체 건수 확인
311
- nhncloud logncrash search --query '*' --from 1d --to now --json | jq '.totalItems'
312
140
  ```
313
141
 
314
- ## 옵션
315
-
316
- | 옵션 | 필수 | 설명 |
317
- |------|:---:|------|
318
- | `--query <lucene>` | 예 | Lucene 질의 문자열 |
319
- | `--from <time>` | 예 | 검색 시작 (ISO8601 또는 상대시간) |
320
- | `--to <time>` | 예 | 검색 끝 |
321
- | `--page <n>` | 아니오 | pageNumber (기본 0) |
322
- | `--size <n>` | 아니오 | pageSize (기본 10, 최대 100) |
323
- | `--profile <name>` | 아니오 | 사용할 profile |
324
-
325
- 전역 옵션: `--json` / `--quiet` / `--no-color`.
326
-
327
- ## 종료 코드
142
+ ### 종료 코드
328
143
 
329
144
  | 코드 | 의미 |
330
- |:---:|------|
145
+ | :---: | --- |
331
146
  | 0 | 성공 |
332
147
  | 1 | API 오류 |
333
148
  | 2 | 인증 실패 (401/403) |
334
149
  | 3 | 입력 오류 (파라미터·시간 범위) |
335
150
  | 4 | 설정 오류 (자격증명 누락) |
336
151
 
337
- ### 인스턴스 (Instance)
338
-
339
- `~/.nhncloud/credentials.json` 에 `iaas` 블록을 추가하거나 `nhncloud configure` 로 설정한다.
340
-
341
- ```json
342
- {
343
- "version": 1,
344
- "profiles": {
345
- "default": {
346
- "iaas": {
347
- "tenantId": "<tenant-id>",
348
- "username": "<iam-username>",
349
- "password": "<api-password>",
350
- "region": "kr1"
351
- }
352
- }
353
- }
354
- }
355
- ```
356
-
357
- ```bash
358
- # 인스턴스 목록 조회
359
- nhncloud instance list
360
-
361
- # 이미지 목록 (create --image <id> 에 넣을 image id 확인)
362
- nhncloud instance images
363
-
364
- # public 이미지만, 전체 필드 JSON
365
- nhncloud instance images --visibility public --json
366
-
367
- # 페이지네이션 — 다음 페이지
368
- nhncloud instance images --limit 20 --marker <last-image-id>
369
-
370
- # 인스턴스 타입(flavor) 목록 — id·name 만
371
- nhncloud instance flavors
372
-
373
- # 타입 상세 — vcpus·ram·disk 포함 (테이블은 핵심 5컬럼)
374
- nhncloud instance flavors --detail
375
-
376
- # 전체 필드(is_public·extra_specs 등)는 --json 으로
377
- nhncloud instance flavors --detail --json
378
-
379
- # RAM 8GB 이상 타입만 필터
380
- nhncloud instance flavors --detail --min-ram 8192
381
-
382
- # 가용성 영역(availability zone) 목록 (영역명·가용 여부)
383
- nhncloud instance availability-zones
384
-
385
- # 전체 응답(zoneState 등)은 --json 으로
386
- nhncloud instance availability-zones --json
387
-
388
- # 단일 인스턴스 상태 조회
389
- nhncloud instance get <instance-id>
390
-
391
- # 인스턴스 생성 (즉시 반환, BUILD 상태)
392
- nhncloud instance create \
393
- --name my-server \
394
- --flavor <flavor-id> \
395
- --image <image-id> \
396
- --network <network-uuid>
397
-
398
- # 인스턴스 생성 + ACTIVE 대기 (IP 할당까지 폴링)
399
- nhncloud instance create \
400
- --name my-server \
401
- --flavor <flavor-id> \
402
- --image <image-id> \
403
- --network <network-uuid> \
404
- --wait
405
-
406
- # GPU(g2) 등 boot-from-volume 필수 flavor — --boot-volume-size 지정
407
- nhncloud instance create \
408
- --name gpu-server \
409
- --flavor <gpu-flavor-id> \
410
- --image <image-id> \
411
- --network <network-uuid> \
412
- --boot-volume-size 30 \
413
- --wait
414
-
415
- # cloud-init user-data 주입 (부팅 시 자동 셋업 — NVIDIA 드라이버·docker 등)
416
- nhncloud instance create \
417
- --name gpu-runner \
418
- --flavor <gpu-flavor-id> \
419
- --image <image-id> \
420
- --network <network-uuid> \
421
- --boot-volume-size 30 \
422
- --user-data ./cloud-init.yaml \
423
- --wait
424
-
425
- # --quiet --wait: 첫 IP 한 줄만 stdout (CI 파이프용)
426
- IP=$(nhncloud instance create --name ci-runner \
427
- --flavor <flavor-id> --image <image-id> --network <network-uuid> \
428
- --wait --quiet)
429
-
430
- # 인스턴스 삭제 (confirm 생략)
431
- nhncloud instance delete <instance-id> --yes
432
-
433
- # 인스턴스 타입(flavor) 변경 — 후보 id 는 instance flavors 로 조회
434
- nhncloud instance flavors --detail
435
- nhncloud instance resize <instance-id> --flavor <flavor-id>
436
-
437
- # resize 후 VERIFY_RESIZE 상태 — 확정 또는 롤백
438
- nhncloud instance resize-confirm <instance-id>
439
- nhncloud instance resize-revert <instance-id>
440
-
441
- # 인스턴스 정지 / 시작
442
- nhncloud instance stop <instance-id>
443
- nhncloud instance start <instance-id>
444
-
445
- # 재부팅 (기본 SOFT)
446
- nhncloud instance reboot <instance-id>
447
-
448
- # HARD 재부팅 (강제 전원 cycle)
449
- nhncloud instance reboot <instance-id> --hard
450
-
451
- # 키페어 목록 (name·fingerprint)
452
- nhncloud instance keypairs
453
-
454
- # 단일 키페어 조회
455
- nhncloud instance keypair get <keypair-name>
456
-
457
- # 키페어 생성 — NHN 이 키쌍 생성, private_key 를 0600 파일로 저장 (한 번만 받을 수 있음)
458
- nhncloud instance keypair create <keypair-name> -o ./my-key.pem
459
-
460
- # 기존 공개키 등록 (private_key 미반환)
461
- nhncloud instance keypair create <keypair-name> --public-key ~/.ssh/id_rsa.pub
462
-
463
- # 키페어 삭제
464
- nhncloud instance keypair delete <keypair-name>
465
- ```
466
-
467
- > **private_key 안내**: 키페어 생성 시 NHN 이 만든 private_key 는 생성 응답 **한 번만** 반환됩니다.
468
- > `-o <keyfile>` 로 저장하거나 stdout 을 안전한 곳에 보관하세요. 분실 시 복구할 수 없습니다.
152
+ ### 되돌리기 어려운 명령의 확인
469
153
 
470
- 지원 region: `kr1` / `kr2` / `kr3` / `jp1` (`--region` 으로 override 가능).
154
+ 삭제·전체 교체처럼 되돌리기 어려운 명령은 실행 전 확인을 요구한다.
155
+ 자동화·파이프 등 비대화형 실행에서는 `--yes` 를 명시해야 한다.
156
+ 플래그가 없으면 API 를 호출하기 전에 종료 코드 3 으로 끝난다.
471
157
 
472
- ### 네트워크 (Network)
158
+ `--region` 은 IaaS 와 NKS 계열에서 결과를 가르므로, 기본값에 기대지 말고 명시하는 편이 안전하다.
473
159
 
474
- `instance create --network <uuid>` 에 넣을 VPC id 를 확인하거나 서브넷 구성을 조회한다.
475
- `network` 명령군은 `instance` 와 같은 `iaas` 자격증명·Keystone 토큰을 공유한다 — 별도 설정이 필요 없다.
160
+ ## 프로젝트 구조
476
161
 
477
- ```bash
478
- # VPC 목록 (instance create --network <uuid> 에 넣을 VPC id 확인)
479
- nhncloud network list
480
-
481
- # 전체 필드 JSON
482
- nhncloud network list --json
483
-
484
- # 서브넷 목록 (소속 VPC·CIDR·가용 IP 확인)
485
- nhncloud network subnet list
486
-
487
- # 다른 region
488
- nhncloud network list --region kr2
489
-
490
- # create 흐름 — 확인한 VPC id 를 --network 에 사용 (--network 가 받는 uuid = VPC id, 실측 확정)
491
- nhncloud instance create \
492
- --name web \
493
- --flavor <flavor-id> \
494
- --image <image-id> \
495
- --network <network-uuid>
496
- ```
497
-
498
- > **`--network` 가 받는 id**: `network list` 의 VPC id 를 그대로 `--network` 에 사용한다.
499
- > subnet id 가 아니다 — `instance list --json` 의 addresses 키와 VPC name 이 1:1 대응함을 실측으로 확인.
500
-
501
- ### Block Storage (Volume)
502
-
503
- 독립 블록 스토리지 볼륨을 관리한다.
504
- `volume` 명령군은 `instance`·`network` 와 같은 `iaas` 자격증명·Keystone 토큰을 공유한다 — 별도 설정이 필요 없다.
505
-
506
- **볼륨 생성(`volume create`)·인스턴스 연결(`instance volume attach`)·연결 해제(`instance volume detach`)는 쓰기 작업이므로 실행 전 환경을 확인한다(수동 QA 필수).**
507
-
508
- ```bash
509
- # 볼륨 목록 조회
510
- nhncloud volume list
511
-
512
- # 정렬·페이지네이션
513
- nhncloud volume list --sort created_at:desc --limit 20
514
-
515
- # 단일 볼륨 조회
516
- nhncloud volume get <volume-id>
517
-
518
- # 전체 필드 JSON
519
- nhncloud volume get <volume-id> --json
520
-
521
- # 볼륨 생성 — ⚠️ 쓰기 작업, 실행 전 환경 확인 필수
522
- nhncloud volume create --size 10
523
-
524
- # 이름·타입 지정
525
- nhncloud volume create --size 50 --name my-volume --volume-type "General SSD"
526
-
527
- # 인스턴스와 같은 가용성 영역에 생성
528
- nhncloud volume create --size 50 --volume-type "General SSD" --availability-zone kr-pub-a
529
-
530
- # 인스턴스에 연결된 볼륨 목록 조회
531
- nhncloud instance volumes <instance-id>
532
-
533
- # 볼륨 연결 — ⚠️ 쓰기 작업 (--volume 플래그로 볼륨 ID 지정)
534
- nhncloud instance volume attach <instance-id> --volume <volume-id>
535
-
536
- # 볼륨 연결 해제 — ⚠️ 쓰기 작업 (인스턴스 ID + 볼륨 ID 위치 인수)
537
- nhncloud instance volume detach <instance-id> <volume-id>
538
- ```
539
-
540
- > **UX 비대칭**: `attach` 는 `--volume <id>` 플래그로 볼륨을 지정하고,
541
- > `detach` 는 `<instanceId> <volumeId>` 위치 인수 두 개로 지정한다.
542
-
543
- 지원 region: `kr1` / `kr2` / `kr3` / `jp1` (`--region` 으로 override 가능).
544
-
545
- ### 공인 IP (Floating IP)
546
-
547
- Floating IP 를 발급해 인스턴스에 부여하는 공인 IP 를 관리한다.
548
- `floatingip` 명령군은 `network` 와 같은 `iaas` 자격증명·Keystone 토큰을 공유한다.
549
-
550
- ```bash
551
- # Floating IP 목록
552
- nhncloud floatingip list
553
-
554
- # Floating IP 발급 (--network 미지정 시 외부 VPC 자동 조회)
555
- nhncloud floatingip create
556
- nhncloud floatingip create --network <network-uuid>
557
-
558
- # 삭제
559
- nhncloud floatingip delete <floatingip-id> --yes
560
- ```
561
-
562
- > **associate**: `floatingip associate <floatingip-id> <instance-id>` 는 instance→port_id 매핑 경로 미확정으로 보류 중.
563
- > 실측으로 경로가 확정되면 후속 task 에서 추가한다.
564
-
565
- ### Load Balancer와 IP ACL
566
-
567
- Load Balancer와 IP ACL 그룹·대상을 조회하고 관리한다.
568
- `loadbalancer` 명령군은 `network`와 같은 `iaas` 자격증명·Keystone 토큰·network endpoint를 공유한다.
569
-
570
- 자동화에서는 profile과 region을 명시하고 `--json`으로 조회한다.
571
-
572
- ```bash
573
- # Load Balancer 목록과 단건 조회
574
- nhncloud loadbalancer list --profile <profile> --region <region> --json
575
- nhncloud loadbalancer get <loadbalancer> --profile <profile> --region <region> --json
576
-
577
- # IP ACL 그룹 목록과 단건 조회
578
- nhncloud loadbalancer ipacl list --profile <profile> --region <region> --json
579
- nhncloud loadbalancer ipacl get <group> --profile <profile> --region <region> --json
580
-
581
- # 그룹에 속한 IP ACL 대상 조회
582
- nhncloud loadbalancer ipacl target list <group> \
583
- --profile <profile> \
584
- --region <region> \
585
- --json
586
-
587
- # IP ACL 그룹 생성과 삭제
588
- nhncloud loadbalancer ipacl create \
589
- --name <group-name> \
590
- --action ALLOW \
591
- --description <description> \
592
- --profile <profile> \
593
- --region <region> \
594
- --json
595
- nhncloud loadbalancer ipacl delete <group> \
596
- --profile <profile> \
597
- --region <region> \
598
- --yes \
599
- --json
600
-
601
- # Load Balancer의 IP ACL 그룹 전체 교체와 전체 해제
602
- nhncloud loadbalancer set-ipacl <loadbalancer> \
603
- --group <group> \
604
- --group <other-group> \
605
- --profile <profile> \
606
- --region <region> \
607
- --yes \
608
- --json
609
- nhncloud loadbalancer clear-ipacl <loadbalancer> \
610
- --profile <profile> \
611
- --region <region> \
612
- --yes \
613
- --json
614
-
615
- # IP ACL 대상 추가와 삭제
616
- nhncloud loadbalancer ipacl target add <group> \
617
- --cidr <ip-or-cidr> \
618
- --profile <profile> \
619
- --region <region> \
620
- --yes \
621
- --json
622
- nhncloud loadbalancer ipacl target remove <target-id> \
623
- --profile <profile> \
624
- --region <region> \
625
- --yes \
626
- --json
627
- ```
628
-
629
- `<loadbalancer>`와 `<group>`에는 이름 또는 UUID를 넣는다.
630
- UUID가 정확히 일치하면 바로 선택하고, 이름은 정확히 하나만 일치해야 한다.
631
- 같은 이름이 여러 개면 오류에 표시되는 후보 UUID를 사용한다.
632
-
633
- 기본 테이블의 Load Balancer 목록 컬럼은 `id`, `name`, `vip_address`, `provisioning_status`, `operating_status`, `ipacl_group_action`이다.
634
- IP ACL 그룹 목록 컬럼은 `id`, `name`, `action`, `ipacl_target_count`, `loadbalancer_count`다.
635
- IP ACL 대상 목록 컬럼은 `id`, `cidr_address`, `description`, `ipacl_group_id`다.
636
- `--json`은 응답 래퍼를 제거한 객체 또는 배열을 stdout에 출력하고, `--quiet`는 리소스 UUID만 한 줄에 하나씩 stdout에 출력한다.
637
- 진행 상황, 운영 경고, 오류는 stderr로 분리된다.
638
-
639
- 쓰기 명령은 대화형 확인을 열지 않는다.
640
- 삭제, 연결 교체, 대상 변경에는 `--yes`가 필수다.
641
- `set-ipacl`은 지정한 그룹 목록으로 기존 연결을 전체 교체하고, `clear-ipacl`은 모든 연결을 해제한다.
642
-
643
- 대상 추가·삭제는 변경 전에 연결 상태를 수집한 뒤 관련 Load Balancer를 순차 재바인딩한다.
644
- `--no-rebind`를 쓰면 재바인딩을 생략하지만 데이터 영역에 규칙이 즉시 반영되지 않을 수 있다.
645
- 대상 변경은 반영까지 약 10–20초가 걸릴 수 있다.
646
- `ALLOW` 그룹에는 Load Balancer가 속한 VPC의 private CIDR을 사용한다.
647
-
648
- 재바인딩이 일부 실패하면 대상 변경은 되돌리지 않는다.
649
- 명령은 `status: "partial"`과 `rebind.failed[].retry_argv`를 stdout JSON에 먼저 출력한 뒤 종료 코드 1을 반환한다.
650
- AI 에이전트는 문자열인 `retry_command`보다 배열인 `retry_argv`를 우선 사용한다.
651
- 사용자가 명시한 `--profile`과 `--region`도 복구 배열에 보존된다.
652
-
653
- ```bash
654
- result_file="$(mktemp)"
655
- if ! nhncloud loadbalancer ipacl target add <group> \
656
- --cidr <ip-or-cidr> \
657
- --profile <profile> \
658
- --region <region> \
659
- --yes \
660
- --json >"$result_file"; then
661
- jq '.rebind.failed[] | {error, retry_argv}' "$result_file"
662
- fi
663
162
  ```
664
-
665
- ### NHN Container Registry (NCR)
666
-
667
- NCR Management API 로 레지스트리를 조회한다.
668
- 인증은 공통 UAK(`X-TC-AUTHENTICATION-ID/SECRET` 정적 헤더)를 재사용하며 OAuth 토큰 교환이 없다.
669
- appKey 는 NHN Cloud 콘솔 → Container Registry 서비스에서 확인한다.
670
-
671
- ```bash
672
- # ncr appkey 설정 (비대화형)
673
- nhncloud configure --ncr-appkey <appkey>
674
-
675
- # 레지스트리 목록 조회
676
- nhncloud ncr list --app-key <appkey>
677
-
678
- # region 지정 (기본: kr1)
679
- nhncloud ncr list --region kr2 --app-key <appkey>
680
-
681
- # JSON 출력
682
- nhncloud ncr list --app-key <appkey> --json
683
-
684
- # 단일 레지스트리 조회 (이름 또는 ID)
685
- nhncloud ncr get <registry-name> --app-key <appkey>
686
- ```
687
-
688
- appKey 를 `nhncloud configure --ncr-appkey <appkey>` 로 저장해 두면 `--app-key` 없이도 호출할 수 있다.
689
-
690
- ```bash
691
- # configure 로 저장 후 --app-key 생략
692
- nhncloud configure --ncr-appkey <appkey>
693
- nhncloud ncr list
694
- nhncloud ncr get <registry-name>
163
+ src/
164
+ index.ts CLI 진입점
165
+ api/ 공통 endpoint, 응답 봉투, HTTP 오류 처리 (ky)
166
+ services/ 서비스별 API 클라이언트와 타입 가드
167
+ commands/ Commander.js 명령 정의
168
+ config/ ~/.nhncloud/ 자격증명·설정 스키마와 profile 해석
169
+ cache/ ~/.nhncloud/cache/ 토큰 캐시
170
+ formatters/ 표·JSON·quiet 출력
171
+ skill/ Claude Code 스킬 설치·갱신
172
+ utils/ 에러, 스피너, 종료 코드
695
173
  ```
696
174
 
697
- 이미지(repository)·태그는 레지스트리 데이터플레인 Harbor REST API 를 직접 호출한다.
698
- UAK 를 Basic Auth 로 사용하며 추가 설정은 없다.
175
+ 의존 방향은 `commands/` → `services/` → `api/` 이고, `utils/` 와 `formatters/` 는 그 아래에서 공유한다.
176
+ `services/` 가 `commands/` 를 import 하지 않는다 — 역류는 금지다.
699
177
 
700
- ```bash
701
- # 이미지(repository) 목록 조회
702
- nhncloud ncr images <registry>
703
-
704
- # region 지정
705
- nhncloud ncr images <registry> --region kr2
706
-
707
- # JSON 출력
708
- nhncloud ncr images <registry> --json
178
+ | 문서 | 담는 것 |
179
+ | --- | --- |
180
+ | [docs/prd.md](docs/prd.md) | 제품 목적과 범위 |
181
+ | [docs/flow.md](docs/flow.md) | 사용자 흐름 |
182
+ | [docs/code-architecture.md](docs/code-architecture.md) | 디렉터리 트리, 레이어, 경계 |
183
+ | [docs/data-schema.md](docs/data-schema.md) | 자격증명과 캐시 스키마 |
184
+ | [docs/adr/INDEX.md](docs/adr/INDEX.md) | 기술 의사결정 기록 (27건) |
185
+ | [docs/pitfalls/INDEX.md](docs/pitfalls/INDEX.md) | 반복해서 발견된 회피 패턴 (104건) |
709
186
 
710
- # 특정 이미지의 태그 목록 조회
711
- nhncloud ncr tags <registry> <repository>
712
-
713
- # JSON 출력 (태그·push_time·size)
714
- nhncloud ncr tags <registry> <repository> --json
715
- ```
187
+ ## 기여하기
716
188
 
717
- ### NHN Kubernetes Service (NKS)
189
+ 이슈와 PR 모두 환영한다.
718
190
 
719
- NKS는 `iaas` 자격증명으로 Keystone 토큰을 발급하고 `container-infra` API를 호출한다.
720
- 지원 region은 `kr1`, `kr2`, `kr3` 이다.
191
+ ### 개발 환경
721
192
 
722
193
  ```bash
723
- # 지원 Kubernetes version / event type 조회
724
- nhncloud nks supports
725
-
726
- # 클러스터와 노드 그룹 조회
727
- nhncloud nks cluster list
728
- nhncloud nks cluster get <cluster>
729
- nhncloud nks cluster events <cluster>
730
- nhncloud nks cluster event <cluster> <event>
731
- nhncloud nks cluster ipacl <cluster>
732
- nhncloud nks nodegroup list <cluster>
733
- nhncloud nks nodegroup get <cluster> <nodegroup>
734
- nhncloud nks nodegroup autoscale <cluster> <nodegroup>
735
-
736
- # kubeconfig stdout 출력 또는 mode 0600 파일 저장
737
- nhncloud nks cluster kubeconfig <cluster>
738
- nhncloud nks cluster kubeconfig <cluster> --output ./kubeconfig
739
- nhncloud nks cluster kubeconfig <cluster> --output ./kubeconfig --force
740
-
741
- # 애드온 조회
742
- nhncloud nks addon-type list
743
- nhncloud nks addon-type get <addon-type>
744
- nhncloud nks addon list --k8s-version v1.30.1
745
- nhncloud nks addon get <addon>
746
- nhncloud nks cluster addon list <cluster>
747
- nhncloud nks cluster addon get <cluster> <addon>
748
- ```
749
-
750
- 복잡한 쓰기 작업은 공식 API payload를 JSON 파일로 전달한다.
751
- 삭제·제거 명령은 비대화형 환경에서 `--yes` 가 필요하다.
752
-
753
- ```bash
754
- # 클러스터 / 노드 그룹 생성
755
- nhncloud nks cluster create --file ./cluster-create.json
756
- nhncloud nks nodegroup create <cluster> --file ./nodegroup-create.json
757
-
758
- # resize / upgrade
759
- nhncloud nks cluster resize <cluster> --nodegroup worker --node-count 3
760
- nhncloud nks nodegroup upgrade <cluster> worker --version v1.30.1
761
-
762
- # 삭제 / 노드 action
763
- nhncloud nks cluster delete <cluster> --yes
764
- nhncloud nks nodegroup delete <cluster> worker --yes
765
- nhncloud nks nodegroup stop-node <cluster> worker --nodes node-1,node-2
766
- nhncloud nks nodegroup start-node <cluster> worker --nodes node-1,node-2
767
-
768
- # 애드온 설치 / 업데이트 / 제거
769
- nhncloud nks cluster addon install <cluster> \
770
- --name coredns \
771
- --version 1.0.0 \
772
- --resolve-conflicts overwrite
773
-
774
- nhncloud nks cluster addon update <cluster> coredns \
775
- --version 1.0.1 \
776
- --resolve-conflicts preserve
777
-
778
- nhncloud nks cluster addon remove <cluster> coredns --yes
779
-
780
- # payload 파일 기반 변경
781
- nhncloud nks cluster set-ipacl <cluster> --file ./ipacl.json
782
- nhncloud nks cluster renew-certificate <cluster> --term-of-validity 3
783
- nhncloud nks cluster update-sgw <cluster> --ncr-sgw <uuid> --obs-sgw <uuid>
784
- nhncloud nks cluster set-control-plane-log <cluster> --file ./control-plane-log.json
785
- nhncloud nks nodegroup set-autoscale <cluster> worker --file ./autoscale.json
786
- nhncloud nks nodegroup set-metric-autoscale <cluster> worker --file ./metric-autoscale.json
787
- nhncloud nks nodegroup set-userscript <cluster> worker --file ./userscript.sh
788
- nhncloud nks nodegroup update-flavor <cluster> worker --flavor <flavor-uuid>
789
- nhncloud nks nodegroup set-fip-auto-bind <cluster> worker --file ./fip-auto-bind.json
790
- nhncloud nks nodegroup set-labels <cluster> worker --file ./labels.json
791
- ```
792
-
793
- ### NHN Container Service (NCS)
794
-
795
- NCS는 template(설계도)과 workload(런타임 실행)를 조회한다.
796
- 인증은 Deploy와 같은 UAK OAuth Bearer 토큰을 재사용하며(profile 토큰 캐시 공유), appkey는 경로에 포함한다.
797
- 지원 region은 `kr1`(판교), `kr3`(광주)만이다.
798
- appkey는 `nhncloud configure` (대화형 또는 `--ncs-appkey`) 로 설정하거나 `--app-key` 옵션으로 직접 넘긴다.
194
+ git clone https://github.com/jon890/nhncloud-cli.git
195
+ cd nhncloud-cli
196
+ pnpm install
799
197
 
800
- template(설계도)의 생성·삭제, workload(런타임 실행)의 생성·변경·실행제어(일시정지/재개/재시작/삭제), 악성코드 검사(malware) 설정·결과 조회를 지원한다.
198
+ pnpm run build # tsup 으로 dist/index.js 단일 번들 생성
199
+ pnpm test # vitest
200
+ pnpm tsc --noEmit # 타입 검사 (빌드는 타입을 검사하지 않는다)
801
201
 
802
- ```bash
803
- # template(설계도) 목록/단건/버전 조회
804
- nhncloud ncs template list --app-key <appkey>
805
- nhncloud ncs template get <template-id> --app-key <appkey>
806
- nhncloud ncs template version list <template-id> --app-key <appkey>
807
- nhncloud ncs template version get <template-id> <version> --app-key <appkey>
808
-
809
- # workload(런타임 실행) 목록/단건 조회
810
- nhncloud ncs workload list --app-key <appkey>
811
- nhncloud ncs workload get <workload-id> --app-key <appkey>
812
-
813
- # task 컨테이너 로그/이벤트 조회 (--task는 workload get 응답의 tasks[].id)
814
- nhncloud ncs workload logs <workload-id> \
815
- --task <task-id> \
816
- --container <name> \
817
- --from 1h \
818
- --to now \
819
- --profile <profile> \
820
- --json
821
- nhncloud ncs workload events <workload-id> \
822
- --task <task-id> \
823
- --from 1h \
824
- --to now \
825
- --profile <profile> \
826
- --json
827
-
828
- # 실행 히스토리 / 예약 실행 히스토리 조회
829
- nhncloud ncs workload history <workload-id> --app-key <appkey>
830
- nhncloud ncs workload history get <workload-id> <history-id> --app-key <appkey>
831
- nhncloud ncs workload schedule-history <workload-id> --app-key <appkey>
202
+ node dist/index.js --help # 빌드 결과 직접 실행
203
+ node dist/index.js commands --json
832
204
  ```
833
205
 
834
- `workload logs`와 `workload events`의 `--from`·`--to`는 다음 입력을 받는다.
206
+ `pnpm` 을 쓴다. 빌드는 `tsup`(esbuild) 이 담당하고 `tsc` 는 타입 검사 전용이므로,
207
+ 타입 오류를 잡으려면 `pnpm tsc --noEmit` 를 따로 돌려야 한다.
835
208
 
836
- - 시간대와 초를 포함한 RFC3339 절대시간
837
- - `now`
838
- - 0 이상의 정수 뒤에 `m`, `h`, `d` 중 하나를 붙인 상대시간
209
+ ### 새 명령을 추가할 때
839
210
 
840
- 상대시간 예시는 `30m`, `1h`, `2d`다.
211
+ 1. [공식 API 문서](https://docs.nhncloud.com)로 엔드포인트와 요청·응답 구조를 먼저 확인한다. 확정할 수 없으면 추측해 구현하지 않는다
212
+ 2. `src/services/<service>/` 에 API 클라이언트와 타입 가드를 둔다. 공식 예제 JSON 과 필드 타입을 맞춘다
213
+ 3. `src/commands/<service>/` 에 명령을 정의한다. 인접한 명령의 구조를 따르는 것이 가장 빠르다
214
+ 4. 출력은 `src/formatters/` 에서 표·JSON·quiet 세 모드를 모두 지원한다
215
+ 5. `src/**/*.test.ts` 에 테스트를 추가한다
216
+ 6. 명령이나 옵션이 바뀌면 이 README 와 `skills/nhncloud-cli/references/` 를 함께 갱신한다
841
217
 
842
- 입력은 API 호출 전에 UTC 초 단위 `Z` 문자열로 정규화된다.
843
- 두 옵션을 모두 생략하면 API 기본 범위를 사용하고, 한쪽만 지정할 수도 있다.
844
- 잘못된 날짜, 시간대 없는 절대시간, 역전된 범위는 자격증명과 API에 접근하기 전에 종료 코드 3으로 거부한다.
845
- 조회 데이터는 stdout, 진행 상황과 오류는 stderr에 출력한다.
218
+ HTTP 호출은 `ky` 만 쓰고, 사용자 오류는 `NhnCloudCliError` 와 `src/utils/exit-codes.ts` 의 종료 코드를 쓴다.
219
+ 데이터는 stdout, 진행 상황·경고·오류는 stderr 로 분리한다.
846
220
 
847
- template 생성·버전 생성처럼 복잡한 입력은 공식 API payload를 JSON 파일로 전달한다.
848
- 삭제 명령은 비대화형 환경에서 `--yes`가 필요하다.
221
+ NHN Cloud API 가 문서와 다르거나 직관에 반하면 [docs/adr/](docs/adr/) 에 기록한다.
222
+ 엔드포인트 버전 이중 prefix 나 200 응답 속 `isSuccessful: false` 처럼, 모르고 접근하면 다시 막히는 것들이 이미 27건 쌓여 있다.
849
223
 
850
- ```bash
851
- # template(설계도) 생성 / 삭제
852
- nhncloud ncs template create --file ./template-create.json --app-key <appkey>
853
- nhncloud ncs template delete <template-id> --yes --app-key <appkey>
854
-
855
- # template 버전 생성 / 삭제 (--file 의 sourceVersion 필드가 필수)
856
- nhncloud ncs template version create <template-id> --file ./version-create.json --app-key <appkey>
857
- nhncloud ncs template version delete <template-id> <version> --yes --app-key <appkey>
858
-
859
- # workload 실행제어 — 일시정지 / 재개 / task 재시작 / 삭제
860
- nhncloud ncs workload pause <workload-id> --app-key <appkey>
861
- nhncloud ncs workload resume <workload-id> --app-key <appkey>
862
- nhncloud ncs workload restart <workload-id> --task <task-id> --app-key <appkey>
863
- nhncloud ncs workload delete <workload-id> --yes --app-key <appkey>
864
- ```
224
+ ### PR 을 낼 때
865
225
 
866
- workload 생성은 비동기다.
867
- `--wait`를 주면 `Running` 상태가 될 때까지 폴링하고, `--timeout`(초, 기본 300)으로 대기 시간을 조절한다.
868
- 변경은 `update`(PUT, 전체 교체)와 `patch`(PATCH, JSON Patch 배열로 부분 변경) 두 가지다.
226
+ - 커밋과 PR 제목은 `type(scope): 설명` 형식을 쓴다
227
+ - 커밋 메시지와 PR 본문은 한국어로 쓴다
228
+ - PR 을 열면 CI 가 타입 검사·테스트·빌드를 돌리고, Claude 가 코드 리뷰를 남긴다
229
+ - 리뷰의 🔴 항목은 머지 전에 반영한다
869
230
 
870
- ```bash
871
- # workload 생성 (--wait로 Running 대기)
872
- nhncloud ncs workload create --file ./workload-create.json --wait --app-key <appkey>
231
+ 이 저장소와 npm 패키지는 공개된다.
232
+ 문서·코드·테스트 fixture·이슈 본문에 실제 자격증명이나 사용자 리소스 ID 를 남기지 않고 `<instance-id>` 같은 placeholder 로 바꾼다.
873
233
 
874
- # workload 전체 교체 / 부분 변경(JSON Patch 배열)
875
- nhncloud ncs workload update <workload-id> --file ./workload-update.json --app-key <appkey>
876
- nhncloud ncs workload patch <workload-id> --file ./workload-patch.json --app-key <appkey>
877
- ```
234
+ ### 버그와 제안
878
235
 
879
- 악성코드 검사(malware) 설정은 appkey 단위이고, 검사 결과는 workload 실행 히스토리 단위로 조회한다.
236
+ [GitHub Issues](https://github.com/jon890/nhncloud-cli/issues) 에 올린다.
237
+ 설정 문제라면 `nhncloud doctor` 출력을 함께 붙이면 진단이 빠르다 (비밀값은 가려서 붙인다).
880
238
 
881
- ```bash
882
- # 악성코드 검사 설정 조회 / 변경
883
- nhncloud ncs malware config get --app-key <appkey>
884
- nhncloud ncs malware config set --enabled true --app-key <appkey>
239
+ ## 기술 스택
885
240
 
886
- # 악성코드 검사 결과 조회 (workload history get 응답의 id를 historyId로 사용)
887
- nhncloud ncs malware result <workload-id> <history-id> --app-key <appkey>
888
- ```
241
+ | 분류 | 사용 |
242
+ | --- | --- |
243
+ | 언어·런타임 | TypeScript, Node.js 20+ |
244
+ | CLI 프레임워크 | Commander.js |
245
+ | HTTP | ky |
246
+ | 출력 | chalk, cli-table3, ora |
247
+ | 대화형 입력 | @inquirer/prompts |
248
+ | 빌드 | tsup (CJS 단일 번들) |
249
+ | 테스트 | vitest |
889
250
 
890
- ## 개발
251
+ ## 라이선스
891
252
 
892
- ```bash
893
- pnpm install
894
- pnpm run build # tsup 단일 번들 (dist/index.js)
895
- pnpm tsc --noEmit # 타입 체크
896
- node dist/index.js instance --help
897
- node dist/index.js logncrash search --help
898
- node dist/index.js ncr --help
899
- node dist/index.js nks --help
900
- node dist/index.js commands --json
901
- ```
253
+ MIT