한 줄 치면 올라간다
빌드 폴더를 훑고, 해시를 비교하고, 바뀐 파일만 엣지로 밀어 넣습니다. 설정 파일 하나에 12줄, 그게 전부입니다.
진짜로 칩니다. help deploy ls whoami version clear — 나머지는 정직하게 못 찾았다고 답합니다.
§ 01 설치
패키지 매니저 없이 단일 실행 파일 하나를 내려받습니다. 용량은 약 9 MB, 런타임 의존성은 없습니다.
$ curl -fsSL https://get.nudl.dev | sh
- macOS
- arm64 / x86_64 · 12 Monterey 이상
- Linux
- glibc 2.31 이상, musl 정적 빌드 별도 제공
- Windows
- x86_64 · PowerShell 스크립트는 get.nudl.dev/ps1
- CI
- 공식 컨테이너 이미지 대신 같은 스크립트를 쓰세요. 캐시가 더 잘 붙습니다
설치를 못 하겠다면
파이프에 셸을 물리는 게 꺼림칙한 건 당연합니다. get.nudl.dev는 그냥 텍스트라서 브라우저로 먼저 읽어 보고 저장한 뒤 실행해도 결과가 같습니다. 릴리스 페이지에는 SHA-256도 같이 올려 둡니다.
§ 02 배포가 지나가는 길
명령 한 줄 뒤에서 벌어지는 일은 네 단계뿐입니다. 숨겨진 서버 사이드 빌드는 없습니다 — 빌드는 당신 기계에서 이미 끝나 있어야 합니다.
┌───────────────┐ ┌──────────────────────┐ ┌──────────────────┐
│ build output │ │ nudl client │ │ edge nodes │
│ ./dist │──>│ scan + hash diff │──>│ 12 regions │
└───────────────┘ └──────────┬───────────┘ └──────────────────┘
│
└──> manifest log ──> nudl back
왜 굳이 해시를 다시 세나
타임스탬프를 믿으면 CI에서 매번 전부 새 파일이 됩니다. 체크아웃이 mtime을 갱신하니까요. 내용으로 비교하면 브랜치를 옮겨 다녀도 실제로 달라진 것만 남습니다. 480개 파일 기준으로 해시를 다시 세는 데 0.3초쯤 듭니다.
§ 03 명령 레퍼런스
전체 명령은 아홉 개입니다. 외울 것은 앞의 세 개고, 나머지는 필요할 때 nudl help로 찾으면 됩니다.
| 명령 | 하는 일 | 옵션 |
|---|---|---|
| deploy | 바뀐 파일만 올리고 새 버전을 활성화합니다 | --dry 올리지 않고 목록만 |
| back | 직전 배포로 되돌립니다. 평균 0.8초 | --to 7 일곱 번째 이전으로 |
| ls | 올라간 파일과 크기를 봅니다 | --diff 로컬과 다른 것만 |
| log | 배포 기록을 최근순으로 훑습니다 | -n 5 다섯 줄만 |
| env | 빌드에 넘길 값을 넣고 뺍니다 | --file .env 통째로 |
| domain | 도메인을 붙이고 인증서를 발급합니다 | --verify DNS 상태만 확인 |
| purge | 엣지 캐시를 비웁니다. 경로 패턴을 받습니다 | '/assets/*' |
| whoami | 지금 어느 계정, 어느 프로젝트인지 확인합니다 | — |
| doctor | 설정과 네트워크를 점검하고 막힌 곳을 짚습니다 | --json CI 용 출력 |
$ nudl help --exit-codes 0 ok 1 deploy failed, nothing activated 2 config error (nudl.toml) 3 auth error 4 network error, safe to retry # 실패했는데 0을 뱉는 일은 없습니다. set -e를 믿어도 됩니다.
§ 04 얼마나 걸리나
아래 수치는 이 샘플 페이지를 위해 지어낸 가상의 측정값입니다. 비교 대상인 harbor-cli와 shipwright도 실존하지 않는 이름입니다.
┌─────────────────────────────────────────────────────────┐ │ cold deploy · 480 files · 12 MB │ ├───────────────┬────────┬────────────────────────────────┤ │ tool │ time │ 1 col = 0.5s │ ├───────────────┼────────┼────────────────────────────────┤ │ nudl 2.4.1 │ 6.2s │ ############ │ │ harbor-cli │ 9.8s │ #################### │ │ shipwright │ 14.9s │ ############################## │ ├───────────────┴────────┴────────────────────────────────┤ │ incremental · 6 files changed · same scale │ ├───────────────┬────────┬────────────────────────────────┤ │ nudl 2.4.1 │ 1.1s │ ## │ │ harbor-cli │ 4.4s │ ######### │ │ shipwright │ 5.8s │ ############ │ └───────────────┴────────┴────────────────────────────────┘
- NOTES
- 파일 수가 3만 개를 넘어가면 해시 스캔이 병목이 되어 이점이 거의 사라집니다.
- 업링크가 20 Mbps 아래면 어느 도구를 쓰든 전송 시간이 지배하므로 차이는 오차 범위입니다.
- 이런 경우까지 빠르다고 말하지는 않겠습니다.
§ 05 설정 파일
저장소 루트에 파일 두 개를 둡니다. 하나는 무엇을 어떻게 올릴지, 하나는 무엇을 빼놓을지 정합니다. 둘 다 없어도 ./dist를 기본으로 잡고 동작합니다.
# 저장소 루트. 이게 전부입니다. name = "onlynudles-portal" out = "./dist" [build] command = "npm run build" node = "22" [deploy] regions = ["icn", "nrt", "sfo"] prune = true # 원본에 없는 파일은 엣지에서도 지웁니다 retain = 10 # 되돌릴 수 있는 배포 개수 [headers."/assets/*"] cache-control = "public, max-age=31536000, immutable"
# .gitignore 문법을 그대로 씁니다. 위에서 아래로 읽고, # 나중 줄이 앞 줄을 덮어씁니다. node_modules/ *.map .env* **/__snapshots__/ coverage/ # 소스맵을 굳이 올리고 싶다면 이렇게 되살립니다 !dist/vendor/*.map
설정이 의심스러우면 nudl deploy --dry로 올라갈 목록만 먼저 뽑아 보세요. 실제 전송은 일어나지 않습니다.
§ 06 안 되는 것
먼저 못 하는 일을 적어 두는 편이 서로 시간을 아낍니다.
- 미지원: 서버 사이드 렌더링을 대신 돌려주지 않습니다. 정적 산출물만 다룹니다. 요청마다 코드가 돌아야 한다면 다른 도구를 보세요.
- 미지원: 데이터베이스도, 백엔드 함수도 없습니다. 엣지에서 실행되는 것은 리다이렉트와 헤더 규칙까지입니다.
- 미지원: 빌드를 대신 해 주지 않습니다. [build] 항목은 로컬에서 명령을 부를 뿐, 클라우드 빌더를 부르지 않습니다.
- 미지원: 웹 대시보드가 얇습니다. 로그와 배포 기록은 볼 수 있지만 설정은 대부분 파일과 CLI로만 바꿉니다.
- 지원: 되돌리기는 확실합니다. 매니페스트가 통째로 남아 있어 열 번 전 상태로도 1초 안에 돌아갑니다.
- 지원: 종료 코드와 --json 출력이 안정적입니다. 스크립트에 물려 쓰라고 만든 도구입니다.