diff --git a/Dockerfile b/Dockerfile index 4fe4bf4..5da011e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,96 +1,109 @@ -# ============================================================================ -# FlyGuard: Bionic Obstacle Detection Core (LCT-2026, Case 05) -# Hesai Pandar128 LiDAR (128 beams, 10 Hz / 100ms) -# Universal Production Image: NVIDIA CUDA 12.x / Ada Lovelace / Graceful CPU Fallback -# ============================================================================ +# FlyGuard — обнаружение посторонних объектов в тоннеле метро по данным 3D-лидара. +# +# Образ самодостаточен: во время работы сеть не нужна, все зависимости ставятся +# на этапе сборки. Базовый образ — официальный ROS 2 Humble на Ubuntu 22.04, +# ровно та среда, что указана в ТЗ. +# +# docker build -t flyguard . +# docker run --rm -it --gpus all --network host --ipc host -v /path/to/bags:/data flyguard +# +# Без --gpus all (или на машине без видеокарты NVIDIA) тот же образ считает на +# процессоре — с тем же результатом. +FROM ros:humble-ros-base-jammy -# ---------------------------------------------------------------------------- -# Stage 1: Optional lightweight CPU-only image (build with: --target cpu) -# ---------------------------------------------------------------------------- -FROM python:3.11-slim-bookworm AS cpu - -ENV DEBIAN_FRONTEND=noninteractive \ - PYTHONUNBUFFERED=1 \ - PYTHONDONTWRITEBYTECODE=1 \ - PYTHONPATH="/app:/app/tools" \ - FLYGUARD_DATA="/data" \ - FLYGUARD_DEVICE="cpu" +ARG DEBIAN_FRONTEND=noninteractive +# Численное ядро берётся из репозиториев Ubuntu, а не из pip: так образ собирается +# без выхода в PyPI и получает numpy/scipy, слинкованные с системным BLAS. RUN apt-get update && apt-get install -y --no-install-recommends \ - libgomp1 \ - ca-certificates \ + python3-numpy \ + python3-scipy \ + python3-opencv \ + python3-pil \ + fonts-dejavu-core \ + python3-colcon-common-extensions \ + ros-humble-rviz2 \ + ros-humble-rosbag2-storage-mcap \ + ros-humble-diagnostic-msgs \ && rm -rf /var/lib/apt/lists/* -RUN useradd -m -u 1000 -s /bin/bash flyguard && \ - mkdir -p /app /data /app/artifacts && \ - chown -R flyguard:flyguard /app /data +# PyTorch с CUDA 12.8 — плотные стадии конвейера на видеокарте (сетчатка, +# ламина, кластеризация; flyguard/gpu.py). Колёса несут свою среду CUDA, от +# машины нужен только драйвер NVIDIA (у стенда 580 — это до CUDA 13.0). +# 2.9.1 — последняя сборка под Python 3.10 из Ubuntu 22.04; CUDA 12.8 нужна +# для Blackwell (RTX 50xx) и годится для Ada (RTX 40xx). Весит PyTorch с +# библиотеками CUDA 6.5 ГБ, поэтому ставится одним слоем и без кэша pip. +# +# Колёса — из индекса PyTorch, а если задан TORCH_WHEELS — с этого адреса +# (сборка там, где сети нет: колёса скачиваются на соседней машине и отдаются +# любым HTTP-сервером, docker/wheels/README.md). В контекст сборки колёса не +# кладутся: это ещё 4 ГБ копий на диске. +ARG TORCH_WHEELS= +RUN set -e; \ + if [ -n "$TORCH_WHEELS" ]; then \ + python3 -c "import re, urllib.request as u; b = '$TORCH_WHEELS'.rstrip('/'); \ +f = re.findall(r'href=\"(pip-[^\"]+\.whl)\"', u.urlopen(b + '/').read().decode())[0]; \ +u.urlretrieve(b + '/' + f, '/tmp/pip.whl')"; \ + python3 /tmp/pip.whl/pip install --no-cache-dir --no-index \ + --find-links "$TORCH_WHEELS" torch==2.9.1; \ + rm -f /tmp/pip.whl; \ + else \ + apt-get update && apt-get install -y --no-install-recommends python3-pip; \ + pip3 install --no-cache-dir --index-url https://download.pytorch.org/whl/cu128 \ + torch==2.9.1; \ + rm -rf /var/lib/apt/lists/*; \ + fi; \ + python3 -c "import torch; print('torch', torch.__version__, 'CUDA', torch.version.cuda)" -WORKDIR /app -COPY --chown=flyguard:flyguard requirements.txt /app/ -RUN pip install --no-cache-dir --upgrade pip && \ - pip install --no-cache-dir -r requirements.txt +# Видеокарта для CUDA и для RViz (OpenGL через драйвер NVIDIA при --gpus all) +ENV NVIDIA_VISIBLE_DEVICES=all \ + NVIDIA_DRIVER_CAPABILITIES=all -COPY --chown=flyguard:flyguard . /app/ -RUN chmod +x /app/docker-entrypoint.sh +WORKDIR /opt/flyguard -USER flyguard -VOLUME ["/data", "/app/artifacts"] -ENTRYPOINT ["/app/docker-entrypoint.sh"] -CMD ["default"] +# Сначала манифесты — слой с зависимостями переживает правки кода +COPY ros2_ws/src/flyguard/package.xml ros2_ws/src/flyguard/package.xml +COPY ros2_ws/src/flyguard_msgs/package.xml ros2_ws/src/flyguard_msgs/package.xml +COPY ros2_ws/src/flyguard_msgs/CMakeLists.txt ros2_ws/src/flyguard_msgs/CMakeLists.txt +COPY ros2_ws/src ros2_ws/src +# Память тоннеля и обученное считывание MBON. Без считывания узел работает +# на ручной формуле веса улики, а у неё ложных тревог в полтора раза больше +# (13.6 против 8.0 на км, README) — замеренная конфигурация и образ должны совпадать. +COPY artifacts/mushroom_body.npz ros2_ws/src/flyguard/artifacts/mushroom_body.npz +COPY artifacts/mbon_readout.npz ros2_ws/src/flyguard/artifacts/mbon_readout.npz -# ---------------------------------------------------------------------------- -# Stage 2: Universal Production Image with NVIDIA GPU acceleration & CPU fallback -# (Default target when building with: docker build -t flyguard:latest .) -# ---------------------------------------------------------------------------- -FROM nvidia/cuda:12.4.1-runtime-ubuntu22.04 AS production +# Обычная установка, без --symlink-install: тот режим оставляет в install/ +# ссылки внутрь build/ и src/, и последующее удаление build/ ломает пакет. +RUN . /opt/ros/humble/setup.sh \ + && cd ros2_ws \ + && colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release \ + && rm -rf build log -ENV DEBIAN_FRONTEND=noninteractive \ +COPY docker/entrypoint.sh /entrypoint.sh +COPY docker/fastdds_large.xml /opt/flyguard/fastdds_large.xml +COPY docker/fastdds_udp.xml /opt/flyguard/fastdds_udp.xml +# Пульт проигрывания для `docker exec` (пауза, перемотка, скорость) +COPY docker/flyguard-keys.sh /usr/local/bin/flyguard-keys +# Снятие CR: при клонировании на Windows git может подставить CRLF, и тогда +# ядро ищет интерпретатор «bash\r». Ошибка неочевидная, а стоит одной строки. +RUN sed -i 's/\r$//' /entrypoint.sh /usr/local/bin/flyguard-keys \ + && chmod +x /entrypoint.sh /usr/local/bin/flyguard-keys + +# BLAS в один поток. Матрицы конвейера мелкие, и потоки OpenBLAS не ускоряют +# кадр, а крутятся вхолостую в ожидании работы: при 4 потоках узел занимал +# 3 ядра, при одном — 0.4 ядра, а кадр даже чуть быстрее (33.9 / 39.3 мс против +# 33.2 / 40.5, медиана / p95; синтетика 43.7 / 50.2 против 45.9 / 54.7). +ENV OMP_NUM_THREADS=1 \ + OPENBLAS_NUM_THREADS=1 \ + MKL_NUM_THREADS=1 \ PYTHONUNBUFFERED=1 \ - PYTHONDONTWRITEBYTECODE=1 \ - PYTHONPATH="/app:/app/tools" \ - FLYGUARD_DATA="/data" \ - FLYGUARD_DEVICE="auto" \ - NVIDIA_VISIBLE_DEVICES=all \ - NVIDIA_DRIVER_CAPABILITIES=compute,utility + RCUTILS_COLORIZED_OUTPUT=1 -# Install Python 3.11, pip, and system runtime libraries (OpenMP for LightGBM/Torch) -RUN apt-get update && apt-get install -y --no-install-recommends \ - software-properties-common \ - ca-certificates \ - libgomp1 \ - curl \ - && add-apt-repository -y ppa:deadsnakes/ppa \ - && apt-get update && apt-get install -y --no-install-recommends \ - python3.11 \ - python3.11-distutils \ - && curl -sS https://bootstrap.pypa.io/get-pip.py | python3.11 \ - && ln -sf /usr/bin/python3.11 /usr/bin/python3 \ - && ln -sf /usr/bin/python3.11 /usr/bin/python \ - && apt-get clean && rm -rf /var/lib/apt/lists/* +# Транспорт под кадр в 24 МБ: умолчания Fast DDS рассчитаны на сотни килобайт +# и теряли половину кадров ещё до подписчика. Профиль поднимает сегмент +# разделяемой памяти и буферы сокетов; снимается через FLYGUARD_DDS_PROFILE=0. +ENV FASTRTPS_DEFAULT_PROFILES_FILE=/opt/flyguard/fastdds_large.xml -# Create non-root user for container security compliance -RUN useradd -m -u 1000 -s /bin/bash flyguard && \ - mkdir -p /app /data /app/artifacts && \ - chown -R flyguard:flyguard /app /data - -WORKDIR /app - -# Cache layer: install Python dependencies with PyTorch CUDA 12.1+ wheels -COPY --chown=flyguard:flyguard requirements-gpu.txt /app/ -RUN pip install --no-cache-dir --upgrade pip setuptools wheel && \ - pip install --no-cache-dir -r requirements-gpu.txt - -# Copy source code and artifacts -COPY --chown=flyguard:flyguard . /app/ -RUN chmod +x /app/docker-entrypoint.sh - -USER flyguard -VOLUME ["/data", "/app/artifacts"] - -# Container healthcheck: verifies Python runtime and graceful device detection -HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ - CMD python3 -c "import flyguard; from flyguard.device import get_device_info; print('healthy', get_device_info())" || exit 1 - -ENTRYPOINT ["/app/docker-entrypoint.sh"] -CMD ["default"] +ENTRYPOINT ["/entrypoint.sh"] +CMD ["ros2", "launch", "flyguard", "detect.launch.py"] diff --git a/Dockerfile.gpu b/Dockerfile.gpu index 2fcd26e..89623f5 100644 --- a/Dockerfile.gpu +++ b/Dockerfile.gpu @@ -1,7 +1,7 @@ # ============================================================================ # FlyGuard GPU: NVIDIA RTX / CUDA 12 Production Image (Кейс 05, ЛЦТ-2026) # Архитектура: Ada Lovelace (RTX 4070 Ti Super 16GB) / Ampere / Turing -# Полная совместимость с Dockerfile (Stage: production) +# Полная совместимость с Dockerfile.offline (Stage: production) # ============================================================================ FROM nvidia/cuda:12.4.1-runtime-ubuntu22.04 AS production diff --git a/Dockerfile.offline b/Dockerfile.offline new file mode 100644 index 0000000..4fe4bf4 --- /dev/null +++ b/Dockerfile.offline @@ -0,0 +1,96 @@ +# ============================================================================ +# FlyGuard: Bionic Obstacle Detection Core (LCT-2026, Case 05) +# Hesai Pandar128 LiDAR (128 beams, 10 Hz / 100ms) +# Universal Production Image: NVIDIA CUDA 12.x / Ada Lovelace / Graceful CPU Fallback +# ============================================================================ + +# ---------------------------------------------------------------------------- +# Stage 1: Optional lightweight CPU-only image (build with: --target cpu) +# ---------------------------------------------------------------------------- +FROM python:3.11-slim-bookworm AS cpu + +ENV DEBIAN_FRONTEND=noninteractive \ + PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + PYTHONPATH="/app:/app/tools" \ + FLYGUARD_DATA="/data" \ + FLYGUARD_DEVICE="cpu" + +RUN apt-get update && apt-get install -y --no-install-recommends \ + libgomp1 \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +RUN useradd -m -u 1000 -s /bin/bash flyguard && \ + mkdir -p /app /data /app/artifacts && \ + chown -R flyguard:flyguard /app /data + +WORKDIR /app +COPY --chown=flyguard:flyguard requirements.txt /app/ +RUN pip install --no-cache-dir --upgrade pip && \ + pip install --no-cache-dir -r requirements.txt + +COPY --chown=flyguard:flyguard . /app/ +RUN chmod +x /app/docker-entrypoint.sh + +USER flyguard +VOLUME ["/data", "/app/artifacts"] +ENTRYPOINT ["/app/docker-entrypoint.sh"] +CMD ["default"] + + +# ---------------------------------------------------------------------------- +# Stage 2: Universal Production Image with NVIDIA GPU acceleration & CPU fallback +# (Default target when building with: docker build -t flyguard:latest .) +# ---------------------------------------------------------------------------- +FROM nvidia/cuda:12.4.1-runtime-ubuntu22.04 AS production + +ENV DEBIAN_FRONTEND=noninteractive \ + PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + PYTHONPATH="/app:/app/tools" \ + FLYGUARD_DATA="/data" \ + FLYGUARD_DEVICE="auto" \ + NVIDIA_VISIBLE_DEVICES=all \ + NVIDIA_DRIVER_CAPABILITIES=compute,utility + +# Install Python 3.11, pip, and system runtime libraries (OpenMP for LightGBM/Torch) +RUN apt-get update && apt-get install -y --no-install-recommends \ + software-properties-common \ + ca-certificates \ + libgomp1 \ + curl \ + && add-apt-repository -y ppa:deadsnakes/ppa \ + && apt-get update && apt-get install -y --no-install-recommends \ + python3.11 \ + python3.11-distutils \ + && curl -sS https://bootstrap.pypa.io/get-pip.py | python3.11 \ + && ln -sf /usr/bin/python3.11 /usr/bin/python3 \ + && ln -sf /usr/bin/python3.11 /usr/bin/python \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +# Create non-root user for container security compliance +RUN useradd -m -u 1000 -s /bin/bash flyguard && \ + mkdir -p /app /data /app/artifacts && \ + chown -R flyguard:flyguard /app /data + +WORKDIR /app + +# Cache layer: install Python dependencies with PyTorch CUDA 12.1+ wheels +COPY --chown=flyguard:flyguard requirements-gpu.txt /app/ +RUN pip install --no-cache-dir --upgrade pip setuptools wheel && \ + pip install --no-cache-dir -r requirements-gpu.txt + +# Copy source code and artifacts +COPY --chown=flyguard:flyguard . /app/ +RUN chmod +x /app/docker-entrypoint.sh + +USER flyguard +VOLUME ["/data", "/app/artifacts"] + +# Container healthcheck: verifies Python runtime and graceful device detection +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ + CMD python3 -c "import flyguard; from flyguard.device import get_device_info; print('healthy', get_device_info())" || exit 1 + +ENTRYPOINT ["/app/docker-entrypoint.sh"] +CMD ["default"] diff --git a/README.md b/README.md index 04445d8..c3c38c8 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ ROS 2 bag → /lidar_points (PointCloud2, 0.3–0.9 млн точек, 10 Гц ## Сборка ```bash -docker build -t flyguard -f docker/Dockerfile . +docker build -t flyguard . ``` Образ основан на `ros:humble-ros-base-jammy` (Ubuntu 22.04 + ROS 2 Humble). Все зависимости @@ -647,9 +647,9 @@ artifacts/ обученная память тоннеля и ``` Ядро в `flyguard/` и в `ros2_ws/src/flyguard/flyguard/` — один и тот же код из одного -источника. Сборка и запуск по этому README — через `docker/Dockerfile`. В корне лежат ещё -`Dockerfile`, `Dockerfile.gpu` и `docker-compose.yml` для прогона ядра по записям без ROS -и `Dockerfile.ros2` с узлом `flyguard/flyguard_ros2_node.py`. +источника. Корневой `Dockerfile` и `docker/Dockerfile` собирают один и тот же образ. В корне +лежат ещё `Dockerfile.offline`, `Dockerfile.gpu` и `docker-compose.yml` для прогона ядра по +записям без ROS и `Dockerfile.ros2` с узлом `flyguard/flyguard_ros2_node.py`. ## Лицензия diff --git a/docker-compose.yml b/docker-compose.yml index 816b6fe..7f69898 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: pipeline: build: context: . - dockerfile: Dockerfile + dockerfile: Dockerfile.offline image: flyguard:latest container_name: flyguard-pipeline command: ["pipeline", "--all", "--verbose"] @@ -209,7 +209,7 @@ services: cpu-test: build: context: . - dockerfile: Dockerfile + dockerfile: Dockerfile.offline target: cpu image: flyguard:cpu container_name: flyguard-cpu-test diff --git a/docker-run.sh b/docker-run.sh index 4fc8b38..e1dc69b 100755 --- a/docker-run.sh +++ b/docker-run.sh @@ -46,11 +46,11 @@ CMD="${1:-run}" case "$CMD" in build) echo "==> Сборка универсального образа FlyGuard ($IMAGE_NAME)..." - docker build -t "$IMAGE_NAME" -f "$DIR/Dockerfile" "$DIR" + docker build -t "$IMAGE_NAME" -f "$DIR/Dockerfile.offline" "$DIR" ;; build-cpu) echo "==> Сборка облегченного CPU-образа FlyGuard (flyguard:cpu)..." - docker build --target cpu -t flyguard:cpu -f "$DIR/Dockerfile" "$DIR" + docker build --target cpu -t flyguard:cpu -f "$DIR/Dockerfile.offline" "$DIR" ;; run|default) shift 2>/dev/null || true diff --git a/docs/DOCKER.md b/docs/DOCKER.md index ba2d481..87e7759 100644 --- a/docs/DOCKER.md +++ b/docs/DOCKER.md @@ -34,7 +34,7 @@ FlyGuard поставляется в виде универсального пр ### Универсальный образ с GPU-ускорением (по умолчанию) ```bash -docker build -t flyguard:latest . +docker build -t flyguard:latest -f Dockerfile.offline . ``` * **База**: `nvidia/cuda:12.4.1-runtime-ubuntu22.04` * **Python**: 3.11, PyTorch CUDA 12.1+, cuDNN, OpenMP `libgomp1` @@ -43,7 +43,7 @@ docker build -t flyguard:latest . ### Облегченный CPU-образ (опционально, ~200 МБ) ```bash -docker build --target cpu -t flyguard:cpu . +docker build --target cpu -t flyguard:cpu -f Dockerfile.offline . ``` ---