vibed-infra 0.4.0 → 0.5.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
@@ -71,6 +71,8 @@ wget -qO- .../dist/install-gateway.sh | bash
71
71
  | `INFRA_PROFILE` | `api`, `ui`, `nodes`, or `gateway` |
72
72
  | `INSTALL_DIR` | Target directory (default `.`) |
73
73
 
74
+ Auto-update cron runs profile `update-*.sh`. Each update **prunes dangling Docker images** by default (`DOCKER_AUTO_PRUNE=1`). Set `DOCKER_PRUNE_UNUSED=1` to also drop unused tagged images older than `DOCKER_PRUNE_UNTIL` (default `72h`).
75
+
74
76
  ## Tests
75
77
 
76
78
  ```bash
package/lib/env.sh CHANGED
@@ -222,3 +222,32 @@ chown_data_dir() {
222
222
  fi
223
223
  chmod 755 "$dir" 2>/dev/null || true
224
224
  }
225
+
226
+ # Default on during auto-update. Set DOCKER_AUTO_PRUNE=0 to disable.
227
+ docker_auto_prune_on() {
228
+ if [[ -n "${DOCKER_AUTO_PRUNE+x}" ]]; then
229
+ env_flag_on DOCKER_AUTO_PRUNE
230
+ return
231
+ fi
232
+ return 0
233
+ }
234
+
235
+ # Drop dangling images left after retagged pulls (e.g. :main). Optionally also
236
+ # remove unused tagged images older than DOCKER_PRUNE_UNTIL when DOCKER_PRUNE_UNUSED=1.
237
+ prune_docker_images() {
238
+ local log_dir="${1:-.}"
239
+ local role_label="${2:-infra}"
240
+ docker_auto_prune_on || return 0
241
+ if ! command -v docker >/dev/null 2>&1; then
242
+ return 0
243
+ fi
244
+ local summary
245
+ summary="$(docker image prune -f 2>/dev/null | awk '/Total reclaimed space/{print; found=1} END{if(!found) print "done"}' || echo done)"
246
+ log_update "$log_dir" "${role_label}: prune dangling images — ${summary}"
247
+ if env_flag_on DOCKER_PRUNE_UNUSED; then
248
+ local until="${DOCKER_PRUNE_UNTIL:-72h}"
249
+ summary="$(docker image prune -af --filter "until=${until}" 2>/dev/null \
250
+ | awk '/Total reclaimed space/{print; found=1} END{if(!found) print "done"}' || echo done)"
251
+ log_update "$log_dir" "${role_label}: prune unused images (until=${until}) — ${summary}"
252
+ fi
253
+ }
package/lib/package.py CHANGED
@@ -50,6 +50,9 @@ API_MEMORY_LIMIT=256m
50
50
  {au['flag']}=0
51
51
  {au['intervalEnv']}=30
52
52
  {au['stopTimeoutEnv']}=60
53
+ DOCKER_AUTO_PRUNE=1
54
+ DOCKER_PRUNE_UNUSED=0
55
+ DOCKER_PRUNE_UNTIL=72h
53
56
  """
54
57
 
55
58
 
@@ -63,6 +66,9 @@ UI_MEMORY_LIMIT=32m
63
66
  {au['flag']}=0
64
67
  {au['intervalEnv']}=20
65
68
  {au['stopTimeoutEnv']}=30
69
+ DOCKER_AUTO_PRUNE=1
70
+ DOCKER_PRUNE_UNUSED=0
71
+ DOCKER_PRUNE_UNTIL=72h
66
72
  """
67
73
 
68
74
 
@@ -81,6 +87,9 @@ WORKER_MEMORY_LIMIT=64m
81
87
  {au['flag']}=0
82
88
  {au['intervalEnv']}=30
83
89
  {au['stopTimeoutEnv']}=30
90
+ DOCKER_AUTO_PRUNE=1
91
+ DOCKER_PRUNE_UNUSED=0
92
+ DOCKER_PRUNE_UNTIL=72h
84
93
  """
85
94
 
86
95
 
@@ -103,6 +112,9 @@ GATEWAY_MEMORY_LIMIT=64m
103
112
  {flag_lines}
104
113
  {au.get('intervalEnv', 'GATEWAY_AUTO_UPDATE_INTERVAL_MIN')}=20
105
114
  {au.get('stopTimeoutEnv', 'GATEWAY_STOP_TIMEOUT')}=30
115
+ DOCKER_AUTO_PRUNE=1
116
+ DOCKER_PRUNE_UNUSED=0
117
+ DOCKER_PRUNE_UNTIL=72h
106
118
  """
107
119
 
108
120
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibed-infra",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Product-agnostic VPS packager: wget install, Docker Compose, TLS/nginx, auto-update",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -73,4 +73,14 @@ config: # opaque — written to dist/nodes-workers.yaml
73
73
  | `PACKAGECONFIG_URL` | defaults to `dist/packageconfig.yaml` |
74
74
  | `INFRA_PROFILE` | `api`, `ui`, `nodes`, or `gateway` |
75
75
 
76
+ ### Auto-update + image prune
77
+
78
+ When `*_AUTO_UPDATE=1`, cron runs the profile `update-*.sh`. After each run it **prunes dangling Docker images** (old digests left when `:main` is retagged) so disk does not fill up.
79
+
80
+ | Variable | Default | Meaning |
81
+ |----------|---------|---------|
82
+ | `DOCKER_AUTO_PRUNE` | `1` | Prune dangling images after auto-update |
83
+ | `DOCKER_PRUNE_UNUSED` | `0` | Also prune unused tagged images older than `DOCKER_PRUNE_UNTIL` |
84
+ | `DOCKER_PRUNE_UNTIL` | `72h` | Age filter for unused prune (`docker image prune -af --filter until=…`) |
85
+
76
86
  Legacy `packageconfig.yaml`-only products still work; new products use the four-file layout + `package.sh`.
@@ -35,7 +35,7 @@ sudo certbot certonly --standalone -d app.example.com
35
35
 
36
36
  Set `TLS_FULLCHAIN` / `TLS_PRIVKEY` in gateway `.env`, then `./start-gateway.sh` (reloads certs into the gateway volume).
37
37
 
38
- 6. **Auto-update** — stagger cron: API :00, UI :15, workers :10, gateway :20 (infra defaults).
38
+ 6. **Auto-update** — stagger cron: API :00, UI :15, workers :10, gateway :20 (infra defaults). Update scripts prune dangling images afterward (`DOCKER_AUTO_PRUNE=1`).
39
39
 
40
40
  ## Dual-domain on one host
41
41
 
@@ -28,12 +28,13 @@ run_api_update() {
28
28
  fi
29
29
  if ! container_needs_image "$name" "$image"; then
30
30
  log_update "$SCRIPT_DIR" "api: $name already on latest $image"
31
- return 0
31
+ else
32
+ log_update "$SCRIPT_DIR" "api: updating $name"
33
+ graceful_stop "$name" "$stop_timeout"
34
+ PULL=0 "$SCRIPT_DIR/start-api.sh"
35
+ log_update "$SCRIPT_DIR" "api: $name updated"
32
36
  fi
33
- log_update "$SCRIPT_DIR" "api: updating $name"
34
- graceful_stop "$name" "$stop_timeout"
35
- PULL=0 "$SCRIPT_DIR/start-api.sh"
36
- log_update "$SCRIPT_DIR" "api: $name updated"
37
+ prune_docker_images "$SCRIPT_DIR" "api"
37
38
  }
38
39
 
39
40
  with_update_lock "$SCRIPT_DIR" "api" run_api_update
@@ -30,12 +30,13 @@ run_gateway_update() {
30
30
  fi
31
31
  if ! container_needs_image "$name" "$image"; then
32
32
  log_update "$SCRIPT_DIR" "gateway: $name already on latest $image"
33
- return 0
33
+ else
34
+ log_update "$SCRIPT_DIR" "gateway: updating $name"
35
+ graceful_stop "$name" "$stop_timeout"
36
+ PULL=0 "$SCRIPT_DIR/start-gateway.sh"
37
+ log_update "$SCRIPT_DIR" "gateway: $name updated"
34
38
  fi
35
- log_update "$SCRIPT_DIR" "gateway: updating $name"
36
- graceful_stop "$name" "$stop_timeout"
37
- PULL=0 "$SCRIPT_DIR/start-gateway.sh"
38
- log_update "$SCRIPT_DIR" "gateway: $name updated"
39
+ prune_docker_images "$SCRIPT_DIR" "gateway"
39
40
  }
40
41
 
41
42
  with_update_lock "$SCRIPT_DIR" "gateway" run_gateway_update
@@ -27,11 +27,12 @@ run_nodes_update() {
27
27
  fi
28
28
  if ! container_needs_image "$name" "$image"; then
29
29
  log_update "$SCRIPT_DIR" "nodes: $name already on latest $image"
30
- return 0
30
+ else
31
+ log_update "$SCRIPT_DIR" "nodes: updating via compose"
32
+ PULL=0 "$SCRIPT_DIR/start-nodes.sh"
33
+ log_update "$SCRIPT_DIR" "nodes: updated"
31
34
  fi
32
- log_update "$SCRIPT_DIR" "nodes: updating via compose"
33
- PULL=0 "$SCRIPT_DIR/start-nodes.sh"
34
- log_update "$SCRIPT_DIR" "nodes: updated"
35
+ prune_docker_images "$SCRIPT_DIR" "nodes"
35
36
  }
36
37
 
37
38
  with_update_lock "$SCRIPT_DIR" "nodes" run_nodes_update
@@ -28,12 +28,13 @@ run_ui_update() {
28
28
  fi
29
29
  if ! container_needs_image "$name" "$image"; then
30
30
  log_update "$SCRIPT_DIR" "ui: $name already on latest $image"
31
- return 0
31
+ else
32
+ log_update "$SCRIPT_DIR" "ui: updating $name"
33
+ graceful_stop "$name" "$stop_timeout"
34
+ PULL=0 "$SCRIPT_DIR/start-ui.sh"
35
+ log_update "$SCRIPT_DIR" "ui: $name updated"
32
36
  fi
33
- log_update "$SCRIPT_DIR" "ui: updating $name"
34
- graceful_stop "$name" "$stop_timeout"
35
- PULL=0 "$SCRIPT_DIR/start-ui.sh"
36
- log_update "$SCRIPT_DIR" "ui: $name updated"
37
+ prune_docker_images "$SCRIPT_DIR" "ui"
37
38
  }
38
39
 
39
40
  with_update_lock "$SCRIPT_DIR" "ui" run_ui_update