@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.
- package/README.md +300 -0
- package/dist/index.js +959 -0
- 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.
|