mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-07 11:22:31 +00:00
feat(web-svc-cdn): serve the npm mirror from a compose one-shot build service
Replace the ansible container-run plus copy publish with a proper compose build service deployed via the role's own stack. The one-shot writes the npm mirror straight into the node-local served CDN root that openresty reads, so there is no DiND bind-layer mismatch and no separate publish step. - meta/volumes.yml: build mounts (served root rw, staged manifests ro, build script as a docker config) - templates/compose.yml.j2 + env.j2: one-shot build service (restart no, swarm condition none), CDN_WEB_ROOT and ROLES_DIR from the mount targets - meta/services.yml: placement manager, replicas 1, resources, deploy modes - meta/networks.yml: local subnet (the role now ships a stack) - meta/variants.yml: internal and external flavor variants - meta/tests.yml + test.env.j2 + files/test/test.sh: flavor-branching e2e - tasks: internal flavor deploys the stack via sys-stk-full; drop the container-run and ansible-copy publish; remove the unused dev-git include - vars: pin CDN_FLAVOR to the role id (scope-safe) and compute host paths directly (avoid the volume-lookup double-template) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
e79183f96a
commit
466f04503b
14 files changed
+152
-57
No files matched your search
+18
-17
@@ -20,9 +20,10 @@ flowchart LR
|
||||
dep_web_app_matomo["web-app-matomo 🐳🐝"]
|
||||
dep_web_app_prometheus["web-app-prometheus 🐳🐝"]
|
||||
end
|
||||
subgraph role [web-svc-cdn 💻]
|
||||
subgraph role [web-svc-cdn 🐳🐝]
|
||||
svc_dashboard["dashboard"]
|
||||
svc_cdn["cdn"]
|
||||
svc_build["build"]
|
||||
svc_matomo["matomo"]
|
||||
svc_javascript["javascript"]
|
||||
svc_prometheus["prometheus"]
|
||||
@@ -56,27 +57,27 @@ make compose-deploy mode=reinstall apps=web-svc-cdn full_cycle=false
|
||||
|
||||
### Production
|
||||
|
||||
Install Content Delivery Network directly onto the target machine — clone the repository, install the OS prerequisites and the repository toolchain, then deploy against localhost over a local connection (no SSH, no container):
|
||||
Run the published image to provision the inventory and deploy Content Delivery Network to a managed server (the mounted volume persists the inventory):
|
||||
|
||||
```bash
|
||||
git clone https://github.com/infinito-nexus/core.git
|
||||
cd core
|
||||
bash scripts/install/package.sh
|
||||
make install
|
||||
source scripts/meta/env/load.sh
|
||||
|
||||
APP=web-svc-cdn
|
||||
HOST=<your-server>
|
||||
TLS_MODE=self_signed
|
||||
SSH_PUBLIC_KEY="<your-ssh-public-key>"
|
||||
INVENTORY=inventories/production
|
||||
infinito administration inventory provision "$INVENTORY" \
|
||||
--inventory-file "$INVENTORY/devices.yml" \
|
||||
--host localhost \
|
||||
--include "$APP" \
|
||||
--vars "{\"TLS_MODE\": \"$TLS_MODE\", \"users\": {\"administrator\": {\"authorized_keys\": [\"$SSH_PUBLIC_KEY\"]}}}"
|
||||
infinito administration deploy dedicated "$INVENTORY/devices.yml" \
|
||||
--password-file "$INVENTORY/.password" \
|
||||
--diff -vv
|
||||
|
||||
docker run --rm -it \
|
||||
-v "$PWD/inventories:/etc/infinito.nexus/inventories" \
|
||||
-e APP="$APP" -e HOST="$HOST" -e TLS_MODE="$TLS_MODE" -e SSH_PUBLIC_KEY="$SSH_PUBLIC_KEY" \
|
||||
ghcr.io/infinito-nexus/core/debian bash -c '
|
||||
INVENTORY=/etc/infinito.nexus/inventories/production
|
||||
infinito administration inventory provision "$INVENTORY" \
|
||||
--inventory-file "$INVENTORY/devices.yml" \
|
||||
--host "$HOST" \
|
||||
--include "$APP" \
|
||||
--vars "{\"TLS_MODE\": \"$TLS_MODE\", \"users\": {\"administrator\": {\"authorized_keys\": [\"$SSH_PUBLIC_KEY\"]}}}" &&
|
||||
infinito administration deploy dedicated "$INVENTORY/devices.yml" \
|
||||
--password-file "$INVENTORY/.password" \
|
||||
--diff -vv'
|
||||
```
|
||||
|
||||
## Further Resources
|
||||
|
||||
@@ -11,6 +11,8 @@ set -eu
|
||||
: "${CDN_WEB_ROOT:?}"
|
||||
: "${ROLES_DIR:?}"
|
||||
|
||||
mkdir -p "${CDN_WEB_ROOT}/npm"
|
||||
|
||||
work="$(mktemp -d)"
|
||||
trap 'rm -rf "$work"' EXIT
|
||||
|
||||
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
# E2E orchestrator for web-svc-cdn. Branches on the deployed CDN flavor:
|
||||
# internal - the one-shot npm-mirror build ran, so the served CDN root holds
|
||||
# the npm/ mirror tree (empty when no frontend-dep role is co-deployed).
|
||||
# external - front-proxy only, no build stack, so the served root has no npm/.
|
||||
# Variables sourced from test.env.j2 by test-e2e-cli.
|
||||
set -euo pipefail
|
||||
|
||||
: "${CDN_TEST_FLAVOR:?}"
|
||||
: "${CDN_TEST_IS_STACK_HOST:?}"
|
||||
: "${CDN_TEST_WEB_ROOT:?}"
|
||||
|
||||
if [[ "${CDN_TEST_IS_STACK_HOST}" != "true" ]]; then
|
||||
echo "SKIP: not the stack host; web-svc-cdn only builds there"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
npm_dir="${CDN_TEST_WEB_ROOT%/}/npm"
|
||||
|
||||
case "${CDN_TEST_FLAVOR}" in
|
||||
internal)
|
||||
if [[ ! -d "${npm_dir}" ]]; then
|
||||
echo "FAIL: internal flavor but the one-shot build left no npm mirror at ${npm_dir}"
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: internal flavor built the npm mirror tree at ${npm_dir}"
|
||||
;;
|
||||
*)
|
||||
if [[ -d "${npm_dir}" ]]; then
|
||||
echo "FAIL: external flavor but an npm mirror exists at ${npm_dir}; the build stack must not deploy"
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: external flavor served without a build (no npm mirror at ${npm_dir})"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "ALL CHECKS PASSED"
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
local:
|
||||
subnet: 192.168.220.0/24
|
||||
@@ -5,9 +5,15 @@ dashboard:
|
||||
enabled: false
|
||||
# nocheck: playwright-service-flag — self-provider
|
||||
cdn:
|
||||
# nocheck: default-placement-manager the one-shot npm-mirror build must write the served CDN root, a node-local host bind openresty (manager-pinned) reads
|
||||
placement: manager
|
||||
modes:
|
||||
host:
|
||||
enabled: true
|
||||
compose:
|
||||
enabled: true
|
||||
swarm:
|
||||
enabled: true
|
||||
bond: 1
|
||||
enabled: true
|
||||
shared: true
|
||||
@@ -18,6 +24,16 @@ cdn:
|
||||
pids_limit: 128
|
||||
min_storage: "1GB"
|
||||
lifecycle: beta
|
||||
# nocheck: playwright-service-flag — transient node image used only to build the npm asset mirror, never served
|
||||
build:
|
||||
# nocheck: single-replica one-shot npm-mirror build writing the shared served root; parallel replicas would race and duplicate work
|
||||
replicas: 1
|
||||
image: node
|
||||
version: "26-bookworm"
|
||||
cpus: "1.0"
|
||||
mem_reservation: 128m
|
||||
mem_limit: 256m
|
||||
pids_limit: 256
|
||||
# nocheck: playwright-service-flag — CDN serves static assets, no HTML pages with tracking snippet
|
||||
matomo:
|
||||
bond: 1
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
cli:
|
||||
timeout: 1800
|
||||
@@ -2,10 +2,12 @@
|
||||
# Matrix-deploy variant overrides for web-svc-cdn.
|
||||
# See docs/contributing/artefact/files/role/variants.md for the file format.
|
||||
|
||||
# variant pinning every dynamic services.yml flag to true so the
|
||||
# matrix exercises the in-group_names branch of web-svc-cdn.
|
||||
|
||||
# variant 0 exercises the internal build-mirror flavor with every dynamic
|
||||
# services.yml flag on; variant 1 the external front-proxy-only flavor with
|
||||
# them off.
|
||||
- services:
|
||||
cdn:
|
||||
flavor: internal
|
||||
matomo:
|
||||
enabled: true
|
||||
shared: true
|
||||
@@ -13,6 +15,8 @@
|
||||
enabled: true
|
||||
shared: true
|
||||
- services:
|
||||
cdn:
|
||||
flavor: external
|
||||
matomo:
|
||||
enabled: false
|
||||
shared: false
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
cdn_out:
|
||||
type: bind
|
||||
source: "{{ lookup('nginx', 'directories.data.cdn') }}"
|
||||
mounts:
|
||||
- service: build
|
||||
target: /out
|
||||
|
||||
cdn_pkgsrc:
|
||||
type: bind
|
||||
source: "{{ [ lookup('container', 'web-svc-cdn', 'directories.volumes'), 'pkgsrc' ] | path_join }}"
|
||||
read_only: true
|
||||
mounts:
|
||||
- service: build
|
||||
target: /pkgsrc
|
||||
|
||||
cdn_build_script:
|
||||
type: config
|
||||
source: "{{ [ lookup('container', 'web-svc-cdn', 'directories.volumes'), 'build_assets.sh' ] | path_join }}"
|
||||
mode: "0555"
|
||||
mounts:
|
||||
- service: build
|
||||
target: /build_assets.sh
|
||||
@@ -1,15 +1,18 @@
|
||||
---
|
||||
- include_tasks: utils/once/flag.yml
|
||||
|
||||
- name: 📂 Include dependencies
|
||||
include_role:
|
||||
name: "{{ item }}"
|
||||
loop:
|
||||
- sys-stk-front-proxy
|
||||
- dev-git
|
||||
- name: "🧩 Internal CDN flavor: stage frontend deps + deploy the build stack"
|
||||
when: CDN_FLAVOR == 'internal'
|
||||
block:
|
||||
- name: "📦 Stage every deployed role's frontend dependencies for the CDN"
|
||||
include_tasks: 01_assets.yml
|
||||
when: IS_STACK_HOST | bool
|
||||
|
||||
- name: "📦 Mirror every deployed role's frontend dependencies into the CDN"
|
||||
include_tasks: 01_assets.yml
|
||||
when:
|
||||
- IS_STACK_HOST | bool
|
||||
- CDN_FLAVOR == 'internal'
|
||||
- name: "🧩 Deploy the CDN stack (one-shot npm-mirror build) + front proxy"
|
||||
include_role:
|
||||
name: sys-stk-full
|
||||
|
||||
- name: "🧩 Front proxy only (external CDN flavor)"
|
||||
include_role:
|
||||
name: sys-stk-front-proxy
|
||||
when: CDN_FLAVOR != 'internal'
|
||||
@@ -19,25 +19,8 @@
|
||||
manifest_role: "{{ manifest.path | dirname | dirname | basename }}"
|
||||
when: manifest_role in groups
|
||||
|
||||
- name: "🛠️ npm ci each manifest and mirror it under {{ CDN_WEB_ROOT }}/npm"
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- container
|
||||
- run
|
||||
- --rm
|
||||
- --network=host
|
||||
- -e
|
||||
- "CDN_WEB_ROOT=/cdn"
|
||||
- -e
|
||||
- "ROLES_DIR=/pkgsrc"
|
||||
- -v
|
||||
- "{{ CDN_WEB_ROOT }}:/cdn"
|
||||
- -v
|
||||
- "{{ CDN_ASSET_STAGE }}:/pkgsrc:ro"
|
||||
- -v
|
||||
- "{{ [ role_path, 'files', 'build_assets.sh' ] | path_join }}:/build_assets.sh:ro"
|
||||
- "{{ CDN_ASSET_BUILD_IMAGE }}"
|
||||
- sh
|
||||
- /build_assets.sh
|
||||
changed_when: true
|
||||
timeout: "{{ lookup('timeout', 600) | int }}"
|
||||
- name: "📁 Stage the mirror build script on the CDN host"
|
||||
ansible.builtin.copy:
|
||||
src: build_assets.sh
|
||||
dest: "{{ CDN_BUILD_SCRIPT_HOST }}"
|
||||
mode: "0755"
|
||||
@@ -0,0 +1,13 @@
|
||||
{% include 'roles/sys-svc-compose/templates/base.yml.j2' %}
|
||||
|
||||
{% set service_name = 'build' %}
|
||||
{% set docker_restart_policy = 'no' %}
|
||||
{{ service_name }}:
|
||||
{{ lookup('container_image', application_id, 'build') }}
|
||||
{% include 'roles/sys-svc-container/templates/base.yml.j2' %}
|
||||
command: ["sh", "{{ lookup('volume', application_id, 'cdn_build_script').mounts[0].target }}"]
|
||||
{{ lookup('container_networks') | indent(4) }}
|
||||
{{ lookup('container_volumes', application_id, 'build') | indent(4) }}
|
||||
|
||||
{{ lookup('compose_volumes', application_id) }}
|
||||
{{ lookup('compose_networks') }}
|
||||
@@ -0,0 +1,4 @@
|
||||
{% include 'roles/sys-svc-container/templates/env.j2' %}
|
||||
|
||||
CDN_WEB_ROOT={{ lookup('volume', application_id, 'cdn_out').mounts[0].target }}
|
||||
ROLES_DIR={{ lookup('volume', application_id, 'cdn_pkgsrc').mounts[0].target }}
|
||||
@@ -0,0 +1,4 @@
|
||||
CDN_TEST_DOMAIN={{ domain }}
|
||||
CDN_TEST_FLAVOR={{ CDN_FLAVOR }}
|
||||
CDN_TEST_IS_STACK_HOST={{ IS_STACK_HOST | bool | lower }}
|
||||
CDN_TEST_WEB_ROOT={{ lookup('nginx', 'directories.data.cdn') }}
|
||||
@@ -3,7 +3,6 @@
|
||||
application_id: "web-svc-cdn"
|
||||
domain: "{{ lookup('domain',application_id) }}"
|
||||
|
||||
CDN_FLAVOR: "{{ lookup('config', application_id, 'services.cdn.flavor') }}"
|
||||
CDN_WEB_ROOT: "{{ lookup('nginx', 'directories.data.cdn') }}"
|
||||
CDN_ASSET_STAGE: "{{ [ lookup('container', application_id, 'directories.volumes'), 'pkgsrc' ] | path_join }}"
|
||||
CDN_ASSET_BUILD_IMAGE: "node:26-bookworm"
|
||||
CDN_FLAVOR: "{{ lookup('config', 'web-svc-cdn', 'services.cdn.flavor') }}"
|
||||
CDN_ASSET_STAGE: "{{ [ lookup('container', 'web-svc-cdn', 'directories.volumes'), 'pkgsrc' ] | path_join }}"
|
||||
CDN_BUILD_SCRIPT_HOST: "{{ [ lookup('container', 'web-svc-cdn', 'directories.volumes'), 'build_assets.sh' ] | path_join }}"
|
||||
Reference in new issue
Block a user