Опубликовать образ в реестр и добавить compose для сервера
Образ собран под linux/amd64 и выложен как notbigghost/kbc2d — теги 1.0.0,
latest и 8d17bc8 указывают на один digest sha256:932d881d. В Dockerfile
добавлены метки OCI: версия, хеш коммита и ссылка на репозиторий, чтобы
образ на сервере однозначно сопоставлялся с состоянием исходников.
docker-compose.server.yml самодостаточен: тянет готовый образ из реестра,
исходников не требует, на сервер переносится одним файлом. Кампания —
единственный сервис, поднимающийся по up -d; проверки (vulkaninfo,
preflight, calibrate, dry-run) вынесены в профиль check и сами не
стартуют. Порядок проверок задан документацией: карта, сценарии,
калибровка, смета — и только потом счёт.
Политика перезапуска on-failure, а не unless-stopped: кампания завершается
штатно с кодом 0, и «перезапускать всегда» крутило бы контейнер вхолостую
по кругу, тогда как падение и перезагрузку хоста on-failure подхватывает,
а --resume продолжает с места. Журнал ограничен по размеру: девяносто
часов вывода иначе съедят диск, полные логи каждого прогона всё равно
лежат в out/<id>/log.txt.
Проверено локально из каталога без исходников: образ тянется из реестра,
смоук проходит, результаты ложатся на хост. Часть с картой проверяема
только на сервере — здесь запрос устройства ожидаемо отвергается
«no adapters were found», что само по себе подтверждает, что резервация
GPU в compose действует.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -28,8 +28,16 @@ RUN touch src/main.rs && cargo build --release --locked
|
|||||||
|
|
||||||
# ── исполнение ───────────────────────────────────────────────────────────────
|
# ── исполнение ───────────────────────────────────────────────────────────────
|
||||||
FROM debian:bookworm-slim
|
FROM debian:bookworm-slim
|
||||||
|
|
||||||
|
# Версия и коммит приходят снаружи (см. bench/publish.sh): образ на сервере должен
|
||||||
|
# однозначно сопоставляться с состоянием репозитория, из которого собран.
|
||||||
|
ARG VERSION=dev
|
||||||
|
ARG REVISION=unknown
|
||||||
LABEL org.opencontainers.image.title="kbc2d"
|
LABEL org.opencontainers.image.title="kbc2d"
|
||||||
LABEL org.opencontainers.image.description="Двумерный решатель LBM D2Q9 с энтропийным столкновением KBC"
|
LABEL org.opencontainers.image.description="Двумерный решатель LBM D2Q9 с энтропийным столкновением KBC"
|
||||||
|
LABEL org.opencontainers.image.version="${VERSION}"
|
||||||
|
LABEL org.opencontainers.image.revision="${REVISION}"
|
||||||
|
LABEL org.opencontainers.image.source="https://gitea.arseniev.info/NotBigGhost/TurbulenceCAD"
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
libvulkan1 vulkan-tools python3 ca-certificates \
|
libvulkan1 vulkan-tools python3 ca-certificates \
|
||||||
|
|||||||
@@ -492,14 +492,38 @@ python preflight.py # каждый сценарий старту
|
|||||||
|
|
||||||
## Развёртывание (Docker)
|
## Развёртывание (Docker)
|
||||||
|
|
||||||
|
Собранный образ опубликован: **`notbigghost/kbc2d:1.0.0`** (он же `latest`, он же по хешу
|
||||||
|
коммита `8d17bc8`; все три тега — один digest `sha256:932d881d…`, платформа `linux/amd64`).
|
||||||
|
Исходники на сервере не нужны — достаточно перенести туда один файл
|
||||||
|
`docker-compose.server.yml`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir -p ~/kbc2d && cd ~/kbc2d # сюда же ляжет ./out с результатами
|
||||||
|
# перенести docker-compose.server.yml
|
||||||
|
|
||||||
|
docker compose -f docker-compose.server.yml --profile check run --rm vulkan # карта видна?
|
||||||
|
docker compose -f docker-compose.server.yml --profile check run --rm preflight # сценарии стартуют?
|
||||||
|
docker compose -f docker-compose.server.yml --profile check run --rm calibrate # сколько MLUPS?
|
||||||
|
docker compose -f docker-compose.server.yml up -d # кампания
|
||||||
|
docker compose -f docker-compose.server.yml logs -f
|
||||||
|
```
|
||||||
|
|
||||||
|
Порядок именно такой: узнать, что карта не видна, лучше через минуту, чем через час. Замеренные
|
||||||
|
`--calibrate` числа подставляются переменными `KBC2D_GPU_MLUPS` / `KBC2D_CPU_MLUPS` — только на
|
||||||
|
оценки в часах, на счёт они не влияют.
|
||||||
|
|
||||||
|
Собрать образ самому (`docker-compose.yml` рядом делает то же самое с `build:`):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
docker build -t kbc2d docs/theory/2d_solver
|
docker build -t kbc2d docs/theory/2d_solver
|
||||||
docker run --rm --gpus all kbc2d --calibrate # проверить, что GPU виден
|
docker run --rm --gpus all kbc2d --calibrate
|
||||||
docker run -d --gpus all -v "$PWD/out:/work/bench/out" kbc2d --resume
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`ENTRYPOINT` — драйвер кампании, `CMD` по умолчанию `--dry-run`: случайный `docker run` покажет
|
`ENTRYPOINT` — драйвер кампании, `CMD` по умолчанию `--dry-run`: случайный `docker run` покажет
|
||||||
смету и выйдет, а не запустит сточасовую задачу.
|
смету и выйдет, а не запустит сточасовую задачу. В серверном compose политика перезапуска —
|
||||||
|
`on-failure`, а не `unless-stopped`: кампания завершается штатно с кодом 0, и «перезапускать
|
||||||
|
всегда» крутило бы контейнер вхолостую по кругу, тогда как падение или перезагрузку хоста
|
||||||
|
`on-failure` подхватывает, а `--resume` продолжает с места.
|
||||||
|
|
||||||
**Главная тонкость — Vulkan внутри контейнера.** NVIDIA Container Toolkit подкладывает
|
**Главная тонкость — Vulkan внутри контейнера.** NVIDIA Container Toolkit подкладывает
|
||||||
Vulkan-ICD (`nvidia_icd.json`) только если в `NVIDIA_DRIVER_CAPABILITIES` есть `graphics`;
|
Vulkan-ICD (`nvidia_icd.json`) только если в `NVIDIA_DRIVER_CAPABILITIES` есть `graphics`;
|
||||||
|
|||||||
@@ -6,23 +6,49 @@
|
|||||||
|
|
||||||
## Быстрый старт на сервере
|
## Быстрый старт на сервере
|
||||||
|
|
||||||
```sh
|
Образ опубликован, собирать ничего не нужно: **`notbigghost/kbc2d:1.0.0`**. Исходники на
|
||||||
docker build -t kbc2d docs/theory/2d_solver
|
сервере тоже не нужны — переносится один файл `docker-compose.server.yml`.
|
||||||
docker run --rm --gpus all --entrypoint python3 kbc2d preflight.py # сценарии стартуют
|
|
||||||
docker run --rm --gpus all kbc2d --calibrate # GPU виден
|
|
||||||
docker run -d --gpus all -v "$PWD/out:/work/bench/out" --name kbc2d kbc2d --resume
|
|
||||||
docker logs -f kbc2d
|
|
||||||
```
|
|
||||||
|
|
||||||
Первым делом стоит убедиться, что Vulkan внутри контейнера действительно видит карту:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
docker run --rm --gpus all --entrypoint vulkaninfo kbc2d --summary | head -20
|
mkdir -p ~/kbc2d && cd ~/kbc2d # сюда же ляжет ./out с результатами
|
||||||
|
# перенести сюда docker-compose.server.yml
|
||||||
|
|
||||||
|
C=docker-compose.server.yml
|
||||||
|
docker compose -f $C --profile check run --rm vulkan # 1. карта видна из контейнера?
|
||||||
|
docker compose -f $C --profile check run --rm preflight # 2. все 115 сценариев стартуют?
|
||||||
|
docker compose -f $C --profile check run --rm calibrate # 3. сколько MLUPS на этой машине?
|
||||||
|
docker compose -f $C --profile check run --rm plan # 4. смета в часах по замеренному
|
||||||
|
docker compose -f $C up -d # 5. кампания
|
||||||
|
docker compose -f $C logs -f
|
||||||
```
|
```
|
||||||
|
|
||||||
Если адаптеров ноль — почти наверняка дело в `NVIDIA_DRIVER_CAPABILITIES`: Container Toolkit
|
Порядок не случайный: узнать, что карта не видна, лучше на первом шаге, чем через час счёта.
|
||||||
подкладывает Vulkan-ICD только при наличии `graphics` в списке. В образе это прописано, но
|
|
||||||
может быть переопределено снаружи.
|
Замеренные калибровкой числа подставляются переменными окружения — они влияют только на
|
||||||
|
оценки в часах, не на счёт:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
KBC2D_GPU_MLUPS=1450 KBC2D_CPU_MLUPS=40 docker compose -f $C --profile check run --rm plan
|
||||||
|
```
|
||||||
|
|
||||||
|
**Если `vulkaninfo` показывает ноль адаптеров** — почти наверняка дело в
|
||||||
|
`NVIDIA_DRIVER_CAPABILITIES`: Container Toolkit подкладывает Vulkan-ICD только при наличии
|
||||||
|
`graphics` в списке. В образе и в compose это прописано, но может быть переопределено снаружи.
|
||||||
|
Проверить, что хост вообще умеет отдавать карту:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi
|
||||||
|
```
|
||||||
|
|
||||||
|
## Своя сборка образа
|
||||||
|
|
||||||
|
Если нужен образ из текущего состояния репозитория, а не опубликованный:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker build -t kbc2d docs/theory/2d_solver --build-arg VERSION=dev --build-arg REVISION=$(git rev-parse --short HEAD)
|
||||||
|
```
|
||||||
|
|
||||||
|
Рядом лежит `docker-compose.yml` — то же самое через `build:`, для локальной отладки.
|
||||||
|
|
||||||
## Без Docker
|
## Без Docker
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
# Развёртывание кампании на сервере с NVIDIA. Этот файл САМОДОСТАТОЧЕН: он тянет готовый образ
|
||||||
|
# из реестра и исходников репозитория не требует. Скопировать на сервер достаточно его одного.
|
||||||
|
#
|
||||||
|
# mkdir -p ~/kbc2d && cd ~/kbc2d
|
||||||
|
# curl -O <ссылка на этот файл> # либо просто перенести файл руками
|
||||||
|
#
|
||||||
|
# docker compose -f docker-compose.server.yml --profile check run --rm vulkan
|
||||||
|
# docker compose -f docker-compose.server.yml --profile check run --rm preflight
|
||||||
|
# docker compose -f docker-compose.server.yml --profile check run --rm calibrate
|
||||||
|
# docker compose -f docker-compose.server.yml --profile check run --rm plan
|
||||||
|
# docker compose -f docker-compose.server.yml up -d
|
||||||
|
# docker compose -f docker-compose.server.yml logs -f
|
||||||
|
#
|
||||||
|
# Порядок именно такой. Сначала vulkan: если карта не видна, кампания молча уйдёт считать
|
||||||
|
# ничего — точнее, откажется стартовать на первом же прогоне, но узнать об этом через час
|
||||||
|
# обиднее, чем через минуту. Потом preflight (каждый сценарий стартует на два шага), потом
|
||||||
|
# calibrate (замер MLUPS этой машины), и только потом сама кампания.
|
||||||
|
#
|
||||||
|
# Результаты складываются в ./out на хосте — около 4.4 ГБ гифок и рядов за полный проход.
|
||||||
|
|
||||||
|
name: kbc2d
|
||||||
|
|
||||||
|
# ── общая часть всех сервисов ────────────────────────────────────────────────
|
||||||
|
x-kbc2d: &kbc2d
|
||||||
|
image: notbigghost/kbc2d:1.0.0
|
||||||
|
pull_policy: missing
|
||||||
|
volumes:
|
||||||
|
- ./out:/work/bench/out
|
||||||
|
environment:
|
||||||
|
# ГЛАВНОЕ МЕСТО ВСЕГО ФАЙЛА. NVIDIA Container Toolkit подкладывает внутрь Vulkan-ICD
|
||||||
|
# (nvidia_icd.json) только если в этом списке есть `graphics`. С одним `compute` wgpu не
|
||||||
|
# увидит НИ ОДНОГО адаптера, и решатель откажется стартовать с --backend gpu. В образе
|
||||||
|
# значение уже прописано, здесь оно продублировано явно — чтобы его было видно тому, кто
|
||||||
|
# читает compose, а не Dockerfile.
|
||||||
|
NVIDIA_DRIVER_CAPABILITIES: compute,utility,graphics
|
||||||
|
NVIDIA_VISIBLE_DEVICES: all
|
||||||
|
# Оценки в часах драйвер считает из этих чисел. Умолчания взяты с другой машины —
|
||||||
|
# подставьте сюда то, что напечатает профиль calibrate.
|
||||||
|
KBC2D_GPU_MLUPS: ${KBC2D_GPU_MLUPS:-1200}
|
||||||
|
KBC2D_CPU_MLUPS: ${KBC2D_CPU_MLUPS:-22}
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
reservations:
|
||||||
|
devices:
|
||||||
|
- driver: nvidia
|
||||||
|
count: all
|
||||||
|
capabilities: [gpu]
|
||||||
|
|
||||||
|
services:
|
||||||
|
# ── сама кампания: единственный сервис, который поднимается по `up -d` ──────
|
||||||
|
campaign:
|
||||||
|
<<: *kbc2d
|
||||||
|
container_name: kbc2d-campaign
|
||||||
|
# --resume пропускает всё, у чего уже есть summary.json: перезапуск продолжает с места,
|
||||||
|
# а не начинает заново. Именно поэтому перезапуск здесь безопасен и дёшев.
|
||||||
|
command: ["--resume"]
|
||||||
|
# on-failure, а НЕ unless-stopped: кампания завершается штатно с кодом 0, и политика
|
||||||
|
# «перезапускать всегда» после её окончания крутила бы контейнер вхолостую по кругу.
|
||||||
|
# Падение (OOM, перезагрузка хоста) даёт ненулевой код и будет подхвачено.
|
||||||
|
restart: on-failure:5
|
||||||
|
stop_grace_period: 30s
|
||||||
|
# Девяносто часов вывода — это сотни мегабайт журнала; без ограничения он съест диск.
|
||||||
|
# Полные логи каждого прогона всё равно лежат в out/<id>/log.txt.
|
||||||
|
logging:
|
||||||
|
driver: json-file
|
||||||
|
options:
|
||||||
|
max-size: "50m"
|
||||||
|
max-file: "5"
|
||||||
|
|
||||||
|
# ── проверки перед запуском (профиль check, сами не поднимаются) ────────────
|
||||||
|
vulkan:
|
||||||
|
<<: *kbc2d
|
||||||
|
profiles: ["check"]
|
||||||
|
entrypoint: ["vulkaninfo"]
|
||||||
|
command: ["--summary"]
|
||||||
|
|
||||||
|
preflight:
|
||||||
|
<<: *kbc2d
|
||||||
|
profiles: ["check"]
|
||||||
|
entrypoint: ["python3"]
|
||||||
|
command: ["preflight.py"]
|
||||||
|
|
||||||
|
calibrate:
|
||||||
|
<<: *kbc2d
|
||||||
|
profiles: ["check"]
|
||||||
|
command: ["--calibrate"]
|
||||||
|
|
||||||
|
plan:
|
||||||
|
<<: *kbc2d
|
||||||
|
profiles: ["check"]
|
||||||
|
command: ["--dry-run"]
|
||||||
|
# ── если результаты нужны не под root ────────────────────────────────────────
|
||||||
|
# Контейнер работает от root, поэтому файлы в ./out окажутся root:root. Чтобы они
|
||||||
|
# принадлежали вам, добавьте в x-kbc2d строку
|
||||||
|
# user: "${UID}:${GID}"
|
||||||
|
# и запускайте как UID=$(id -u) GID=$(id -g) docker compose -f … up -d
|
||||||
|
# (каталог ./out при этом должен быть создан заранее и принадлежать вам).
|
||||||
Reference in New Issue
Block a user