888ba6a714
Host service (runs as llmuser, owns /opt/fluxgym + GPU access) that runs
sd-scripts SDXL LoRA training on demand for arbo — the infra-ops half of the
in-arbo LoRA training Phase 1 ownership split (vh/arbo
docs/contracts/in-arbo-lora-training-phase1.contract.md §4.1/§2).
- Fixed-invocation only (INV-T7): bounded params -> one sd-scripts command
shape; every param range/allowlist/path-containment checked before spawn;
bad request = 422, never a silent downgrade. 14 unit tests green.
- Thin supervisor: never imports torch; subprocesses the fluxgym venv's
accelerate. 1-job-at-a-time (arbo lease is the serializer, 409 is backstop).
Durable job records + boot reconciliation (§4.3).
- API: POST /train, GET /train/{id}[/log], POST /train/{id}/cancel,
GET /gpu-status (per-device VRAM + tts_on_3090 co-OOM signal), GET /healthz.
- Wire-shape (§7 resolved with comfy-dev): shared /worktank/arbo/train handoff
(group arbotrain, setgid 2770); worker binds 0.0.0.0:8203, arbo reaches via
host.docker.internal:host-gateway (reachability proven on 172.20.0.1:8203);
device-aware TTS steering via /gpu-status.
Deployed to irv-ml1 via playbooks/deploy-lora-training-worker.yaml (elway,
idempotent); systemd unit active; /healthz + /gpu-status verified live.
113 lines
4.2 KiB
YAML
113 lines
4.2 KiB
YAML
# Deploy the LoRA training worker to irv-ml1 (arbo in-arbo LoRA training Phase 1, §4.1).
|
|
#
|
|
# Two-part deploy (elway upload is single-file, so code lands via rsync first):
|
|
# 1. Stage the code (run from the eshpfi-management repo root, as infra-ops):
|
|
# rsync -a --delete \
|
|
# --exclude .venv --exclude __pycache__ --exclude state --exclude logs \
|
|
# services/lora-training-worker/ \
|
|
# infra-ops@10.100.79.3:/tmp/lora-training-worker-stage/
|
|
# 2. Run this playbook (privileged on-box install + health-gate):
|
|
# scripts/elway irv-ml1 --playbook playbooks/deploy-lora-training-worker.yaml
|
|
#
|
|
# Idempotent: a second run shows mostly ok/skipped. Runs as infra-ops (NOPASSWD sudo on irv-ml1).
|
|
|
|
vars:
|
|
stage_dir: /tmp/lora-training-worker-stage
|
|
install_dir: /opt/lora-training-worker
|
|
handoff_dir: /worktank/arbo/train
|
|
worker_user: llmuser
|
|
arbo_user: lkraven # arbo container runs as uid 1000 = host lkraven
|
|
group: arbotrain
|
|
port: "8203"
|
|
|
|
steps:
|
|
- name: Create the shared handoff group
|
|
shell: getent group {{ group }} >/dev/null || groupadd {{ group }}
|
|
sudo: true
|
|
changed_when: "false" # groupadd-or-noop; report ok either way
|
|
|
|
- name: Add the worker user (llmuser) to the handoff group
|
|
shell: id -nG {{ worker_user }} | tr ' ' '\n' | grep -qx {{ group }} || usermod -aG {{ group }} {{ worker_user }}
|
|
sudo: true
|
|
when: "! id -nG {{ worker_user }} | tr ' ' '\\n' | grep -qx {{ group }}"
|
|
|
|
- name: Add the arbo-container user (lkraven) to the handoff group
|
|
shell: usermod -aG {{ group }} {{ arbo_user }}
|
|
sudo: true
|
|
when: "! id -nG {{ arbo_user }} | tr ' ' '\\n' | grep -qx {{ group }}"
|
|
|
|
- name: Create the shared handoff dir (group-owned, setgid 2770)
|
|
shell: mkdir -p {{ handoff_dir }}
|
|
sudo: true
|
|
creates: "{{ handoff_dir }}"
|
|
|
|
- name: Set handoff dir group + setgid perms
|
|
shell: chgrp {{ group }} {{ handoff_dir }} && chmod 2770 {{ handoff_dir }}
|
|
sudo: true
|
|
changed_when: "false"
|
|
|
|
- name: Create the install dir owned by the worker user
|
|
shell: mkdir -p {{ install_dir }} && chown {{ worker_user }}:{{ worker_user }} {{ install_dir }}
|
|
sudo: true
|
|
creates: "{{ install_dir }}"
|
|
|
|
- name: Sync staged code into the install dir (worker-owned)
|
|
shell: >
|
|
rsync -a --delete
|
|
--exclude .venv --exclude __pycache__ --exclude state --exclude logs
|
|
{{ stage_dir }}/ {{ install_dir }}/
|
|
&& chown -R {{ worker_user }}:{{ worker_user }} {{ install_dir }}
|
|
sudo: true
|
|
|
|
- name: Ensure state + logs dirs exist (worker-writable)
|
|
shell: mkdir -p {{ install_dir }}/state {{ install_dir }}/logs && chown {{ worker_user }}:{{ worker_user }} {{ install_dir }}/state {{ install_dir }}/logs
|
|
sudo: true
|
|
creates: "{{ install_dir }}/logs"
|
|
|
|
- name: Build the worker venv + install deps (as llmuser; prefer uv, fall back to python3 -m venv)
|
|
shell: >
|
|
sudo -u {{ worker_user }} bash -lc '
|
|
cd {{ install_dir }} &&
|
|
if command -v uv >/dev/null 2>&1; then
|
|
uv venv .venv && uv pip install --python .venv/bin/python . ;
|
|
else
|
|
python3 -m venv .venv && .venv/bin/pip install -q --upgrade pip && .venv/bin/pip install -q . ;
|
|
fi'
|
|
sudo: true
|
|
creates: "{{ install_dir }}/.venv/bin/uvicorn"
|
|
|
|
- name: Install the systemd unit
|
|
upload:
|
|
src: services/lora-training-worker/lora-training-worker.service
|
|
dest: /etc/systemd/system/lora-training-worker.service
|
|
mode: "0644"
|
|
sudo: true
|
|
|
|
- name: Reload systemd + enable the worker
|
|
shell: systemctl daemon-reload && systemctl enable lora-training-worker.service
|
|
sudo: true
|
|
changed_when: "false"
|
|
|
|
- name: Restart the worker to pick up the synced code
|
|
shell: systemctl restart lora-training-worker.service
|
|
sudo: true
|
|
changed_when: "false"
|
|
|
|
- name: Give the service a moment to bind
|
|
shell: sleep 3
|
|
changed_when: "false"
|
|
|
|
verify:
|
|
- name: Worker health endpoint responds ok
|
|
shell: curl -fsS http://127.0.0.1:{{ port }}/healthz
|
|
changed_when: "false"
|
|
|
|
- name: gpu-status reports both devices
|
|
shell: curl -fsS http://127.0.0.1:{{ port }}/gpu-status | grep -q '"index"'
|
|
changed_when: "false"
|
|
|
|
- name: Service is enabled + active
|
|
shell: systemctl is-active lora-training-worker.service
|
|
sudo: true
|
|
changed_when: "false"
|