@dmgnr/kuber 1.0.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.
Files changed (3) hide show
  1. package/README.md +300 -0
  2. package/dist/index.js +959 -0
  3. package/package.json +35 -0
package/README.md ADDED
@@ -0,0 +1,300 @@
1
+ # kuber
2
+
3
+ `kuber` is Astral's internal Docker Compose to Kubernetes translation layer.
4
+
5
+ It reads a local Compose file, renders Kubernetes resources, applies them to the cluster, and can build images remotely from your working tree without requiring Docker on your machine.
6
+
7
+ ## What It Does
8
+
9
+ - Reads `compose.yml` or `docker-compose.yml`
10
+ - Converts supported Compose services into Kubernetes resources
11
+ - Applies those resources into a namespace named after the current directory
12
+ - Turns `env_file` entries into Kubernetes Secrets and mounts them through `envFrom`
13
+ - Translates file mounts into ConfigMaps and directory/volume mounts into PVC-backed volumes
14
+ - Builds images on the remote builder by syncing:
15
+ - committed git state
16
+ - tracked local diffs
17
+ - untracked files
18
+ - ignored `.env*` files
19
+ - Supports host-based `ports` syntax that renders Kubernetes `Ingress` rules
20
+ - Supports managed Postgres claims through special pseudo-volumes such as `postgresql:app`
21
+ - Supports managed S3 buckets and credentials through pseudo-volumes such as `s3:app`
22
+
23
+ ## Environment Assumptions
24
+
25
+ This tool is built for Astral's cluster and workstation setup. It is not intended to work unchanged outside that environment.
26
+
27
+ Expected local setup:
28
+
29
+ - Tailscale access to the remote builder and Kubernetes network
30
+ - a working `~/.kube/config`
31
+ - `ssh` available locally
32
+
33
+ Not required locally:
34
+
35
+ - Docker
36
+ - `kubectl`
37
+
38
+ Docker is not required because builds happen on the remote builder after `kuber` syncs your repo state there. `kubectl` is not required because cluster access is handled through the bundled Kubernetes client.
39
+
40
+ ## Running
41
+
42
+ During development:
43
+
44
+ ```bash
45
+ bun run index.ts up
46
+ ```
47
+
48
+ Run the dedicated unit suite and type checks:
49
+
50
+ ```bash
51
+ bun run test
52
+ bun run typecheck
53
+ ```
54
+
55
+ Other useful commands:
56
+
57
+ ```bash
58
+ bun run index.ts ps
59
+ bun run index.ts logs
60
+ bun run index.ts logs -f
61
+ bun run index.ts exec app sh
62
+ bun run index.ts start
63
+ bun run index.ts stop
64
+ bun run index.ts restart
65
+ bun run index.ts db ls
66
+ ```
67
+
68
+ ### Shell Completion
69
+
70
+ Generate and load completions for your shell:
71
+
72
+ ```bash
73
+ source <(kuber complete zsh)
74
+ source <(kuber complete bash)
75
+ ```
76
+
77
+ For a permanent setup, write the generated script to a file and source it from your shell configuration. Fish and PowerShell are also supported through `kuber complete fish` and `kuber complete powershell`.
78
+
79
+ ## Commands
80
+
81
+ - `up`: build images if needed, render manifests, apply them, restart deployments whose image content changed, and wait for rollout
82
+ - `start`: same as `up` but skips image builds
83
+ - `stop`: scale managed deployments to zero
84
+ - `restart`: roll out a restart across managed deployments
85
+ - `down`: delete managed resources while keeping ingress, PVCs, managed databases, and managed S3 storage
86
+ - `down -f`: also delete ingress, PVCs, managed database and S3 resources, and the namespace
87
+ - `ps`: list deployments in the current project namespace
88
+ - `logs [deployment]`: print logs for one deployment or all managed deployments
89
+ - `logs -f [deployment]`: follow logs continuously
90
+ - `exec <deployment> <command...>`: execute a command inside a running deployment pod
91
+ - `db ls`: list managed Postgres claims declared in the current Compose file
92
+ - `db creds <service>`: print the generated connection details for a managed Postgres claim
93
+
94
+ ## Compose Conventions
95
+
96
+ `kuber` supports a few project-specific Compose conventions on top of normal service translation.
97
+
98
+ ### Host-Based Ports
99
+
100
+ If a `ports` entry uses a hostname instead of a numeric published port, `kuber` treats it as an ingress host and routes traffic to the target container port.
101
+
102
+ Example:
103
+
104
+ ```yml
105
+ services:
106
+ app:
107
+ ports:
108
+ - somedomain.astrxl.dev:3000
109
+ ```
110
+
111
+ That produces a Kubernetes `Ingress` rule for `somedomain.astrxl.dev` pointing at the service port for container port `3000`.
112
+
113
+ Single-level wildcard subdomains are supported. Quote wildcard entries so YAML does not treat the leading `*` as an alias:
114
+
115
+ ```yml
116
+ services:
117
+ app:
118
+ ports:
119
+ - "*.astrxl.dev:3000"
120
+ - "*.secure.astrxl.dev:3001:protected"
121
+ ```
122
+
123
+ Protected routes use the kuber dialect and render Traefik `IngressRoute` resources instead of plain Kubernetes `Ingress`:
124
+
125
+ ```yml
126
+ services:
127
+ app:
128
+ ports:
129
+ - db.astrxl.dev:4984:protected
130
+ - status.astrxl.dev:3001:protected(/dashboard,/socket.io)
131
+ ```
132
+
133
+ Translation rules:
134
+
135
+ - `host:port` -> Kubernetes `Ingress`
136
+ - `host:port:protected` -> Traefik `IngressRoute` with middleware `routing/cf-auth` and host-wide matching
137
+ - `host:port:protected(path1,path2,...)` -> Traefik `IngressRoute` with middleware `routing/cf-auth` and explicit `PathPrefix(...)` matches only
138
+
139
+ ### Managed Postgres
140
+
141
+ You can declare a managed Postgres database with a pseudo-volume:
142
+
143
+ ```yml
144
+ services:
145
+ app:
146
+ volumes:
147
+ - postgresql:app
148
+ ```
149
+
150
+ Or with an explicit username and database name:
151
+
152
+ ```yml
153
+ services:
154
+ app:
155
+ volumes:
156
+ - postgresql:user/database
157
+ ```
158
+
159
+ This creates or reuses the managed CNPG role secret, reconciles the database resource, and injects `DATABASE_URL` into the generated app secret in Kubernetes.
160
+
161
+ ### Managed S3
162
+
163
+ Declare a Garage S3 bucket and access key with a pseudo-volume:
164
+
165
+ ```yml
166
+ services:
167
+ app:
168
+ volumes:
169
+ - s3:app
170
+ ```
171
+
172
+ This creates `GarageBucket/app` and `GarageKey/app` in `garage-system`. To use different key and bucket names:
173
+
174
+ ```yml
175
+ services:
176
+ app:
177
+ volumes:
178
+ - s3:app-key/shared-assets
179
+ ```
180
+
181
+ The Garage operator generates the credentials. `kuber` reads its generated Secret and injects these values into the service's `<service>-env` Secret:
182
+
183
+ - `AWS_ACCESS_KEY_ID`
184
+ - `AWS_SECRET_ACCESS_KEY`
185
+ - `AWS_ENDPOINT_URL_S3`
186
+ - `AWS_REGION`
187
+ - `S3_BUCKET`
188
+
189
+ One service can declare both `postgresql:...` and `s3:...`; all generated values are merged into the same service Secret. Managed Garage buckets and keys are retained by normal `down` and deleted by `down -f`.
190
+
191
+ ### Environment Files
192
+
193
+ `env_file` entries are read locally and turned into a Kubernetes `Secret` named `<service>-env`. Deployments then consume that secret through `envFrom`.
194
+
195
+ This is also where generated values such as `DATABASE_URL` and the managed S3 environment are injected.
196
+
197
+ ### Volumes
198
+
199
+ `kuber` treats different volume shapes differently:
200
+
201
+ - file bind mounts become ConfigMaps
202
+ - directory bind mounts become PVC-backed mounts
203
+ - named volumes become PVC-backed mounts
204
+ - `tmpfs` becomes `emptyDir` with memory backing
205
+ - `postgresql:...` is treated as a managed database claim, not as a filesystem mount
206
+ - `s3:...` is treated as a managed object-storage claim, not as a filesystem mount
207
+
208
+ Named volumes also support kuber-specific storage hints.
209
+
210
+ Default behavior:
211
+
212
+ ```yml
213
+ # compose
214
+ services:
215
+ app:
216
+ volumes:
217
+ - myvolume:/data
218
+
219
+ # effective kuber interpretation
220
+ services:
221
+ app:
222
+ volumes:
223
+ - myvolume(1Gi on 2 fast):/data
224
+ ```
225
+
226
+ Short syntax:
227
+
228
+ ```yml
229
+ services:
230
+ app:
231
+ volumes:
232
+ - data(20Gi):/data
233
+ - archive(200Gi on archive):/archive
234
+ - cache(10Gi on 1 fast):/cache
235
+ ```
236
+
237
+ Meaning:
238
+
239
+ - `name(20Gi):/path` -> PVC size `20Gi`
240
+ - `name(20Gi on archive):/path` -> PVC size `20Gi`, `diskTag: ["archive"]`, `dataLocality: "none"`
241
+ - `name(20Gi on 1 archive):/path` -> PVC size `20Gi`, `replicaCount: 1`, `diskTag: ["archive"]`, `dataLocality: "none"`
242
+
243
+ Explicit extensions are also supported.
244
+
245
+ Top-level named volume:
246
+
247
+ ```yml
248
+ volumes:
249
+ data:
250
+ x-size: 20Gi
251
+ x-diskTag: [archive]
252
+ x-replicaCount: 1
253
+ x-dataLocality: none
254
+ ```
255
+
256
+ Long-form service mount:
257
+
258
+ ```yml
259
+ services:
260
+ app:
261
+ volumes:
262
+ - type: volume
263
+ source: data
264
+ target: /data
265
+ volume:
266
+ x-size: 20Gi
267
+ x-diskTag: [archive]
268
+ x-replicaCount: 1
269
+ x-dataLocality: none
270
+ ```
271
+
272
+ Precedence:
273
+
274
+ - short syntax like `data(20Gi on 1 archive):/data`
275
+ - long-form `volume.x-*`
276
+ - top-level `volumes.<name>.x-*`
277
+ - fallback default `1Gi on 2 fast`
278
+
279
+ ## Building
280
+
281
+ Image builds and image-digest checks run through the selected SSH builder. If a pushed image has the same content fingerprint as the existing registry image, `up` does not restart that deployment.
282
+
283
+ To build distributable binaries:
284
+
285
+ ```bash
286
+ bun run build.ts
287
+ ```
288
+
289
+ If you only want a plain JavaScript bundle for quick local use in another workspace, build `index.ts` directly:
290
+
291
+ ```bash
292
+ bun build index.ts --target bun --minify --sourcemap --outdir dist
293
+ ```
294
+
295
+ ## Notes
296
+
297
+ - Resource names and namespaces are derived from the current working directory.
298
+ - The remote build flow is optimized for local iteration, not for producing a perfectly clean export of the repository.
299
+ - Managed database support is Kubernetes-only. It injects `DATABASE_URL` into the generated app secret and does not rewrite local `.env` files.
300
+ - `kuber` operates on managed resources in the namespace matching the current directory name.