268 lines
17 KiB
Markdown
268 lines
17 KiB
Markdown
|
---
|
|||
|
marp: true
|
|||
|
theme: uncover
|
|||
|
paginate: true
|
|||
|
|
|||
|
---
|
|||
|
<!--
|
|||
|
Чтобы сгенерировать из этого файла презентацию в pdf, html или pptx, нужно воспользоваться утилитой Marp https://marp.app/ или одноимённым расширением VSCode https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode.
|
|||
|
-->
|
|||
|
# Nix/Nixos
|
|||
|
ОС-независимая сборка пакетов ROS
|
|||
|
|
|||
|
|
|
|||
|
|
|||
|
Брылёв Игорь
|
|||
|
robossembler.org
|
|||
|
|
|||
|
---
|
|||
|
|
|||
|
# Что же такое ROS?
|
|||
|
|
|||
|
<!--
|
|||
|
В сообществе часто спорят по поводу того чем является или не является ROS. ROS звучит буквально как операционная система для роботов, однако де-факто операционной системой не является. Как правило, все сходятся на том, что ROS включает в себя много разных сущностей - это и стандарт, и фреймворк, и формат взаимодействия приложений, и непосредственно программное обеспечение - стандартная библиотека, если хотите. Но конкретно в этом докладе я бы хотел поговорить о ROS в немного другом свете - как о системе сборки и дистрибьюции программного обеспечения, что тоже имеет место быть. Причём этот аспект я считаю весьма важным, потому что почти любое ROS-приложение в среднем на 95% состоит из подгруженного из пакетных репозиториев кода, из которых на долю ROS-экосистемы приходится меньшая часть.
|
|||
|
-->
|
|||
|
|
|||
|
* Стандарт
|
|||
|
* Фреймворк
|
|||
|
* Набор форматов
|
|||
|
* ...
|
|||
|
* Система сборки и дистрибьюции ПО
|
|||
|
---
|
|||
|
|
|||
|
<!--
|
|||
|
Итак метод сборки и дострибьюции пакетов в ROS в значительной опирается на пакетных менеджер apt и пакетные базы debian/ubuntu (по статистике ros index 2100 пакетов представляют собой системные зависимости, предоставляемые операционной системой), а следовательно зависит от них. Многие пакеты ROS-экосистемы представляют в качестве рекомендуемого способа установки именно установку из своих репозиториев собранных заранее бинарных пакетов. Компиляция проектов их исходников редко практикуется и достаточно сложна. В целом, apt свойственны следующие проблемы.
|
|||
|
-->
|
|||
|
|
|||
|
### Проблемы пакетных менеджеров
|
|||
|
|
|||
|
* Апгрейд конфигурации безвозвратно изменяет состояние системы
|
|||
|
* Сборки не детерминированы
|
|||
|
* Не поддерживаются разные версии бинарников и библиотек
|
|||
|
* Конфликты пакетов
|
|||
|
|
|||
|
---
|
|||
|
|
|||
|
#### Проблемы управления зависимостями в ROS
|
|||
|
|
|||
|
* Зависимость от Ubuntu и её системных зависимостей (apt-пакеты)
|
|||
|
* Сложность интеграции с ПО вне ROS-экосистемы
|
|||
|
* Подготовить для удобного запуска сложный ROS-проект - трудоёмкая задача
|
|||
|
|
|||
|
---
|
|||
|
|
|||
|
# Тренды
|
|||
|
|
|||
|
* Из набора библиотек для одного робота ROS становится стандартом для роботизированных кибер-физических систем
|
|||
|
* В робототехнику проникают инструменты из других ниш: web, машинное обучение, DevOps
|
|||
|
|
|||
|
---
|
|||
|
<!--
|
|||
|
Когда рассказываешь про nix часто у инженеров возникает прочная ассциация с Docker. А не решает ли Docker ту же самую проблему? Да, действительно, эти инструменты решают одну и ту же проблему, которую можно было бы кратко сформулировать так
|
|||
|
-->
|
|||
|
# А как же Docker?
|
|||
|
---
|
|||
|
<!--
|
|||
|
С проблемой сталкиваются нууууу почти все - от первой линии службы технической поддержки до программистов. Это проблема состояния окружения - если ваша программа или приложение в какой-то степени опирается на него, то неизбежно будут возникать проблемы с его корректной работы на компьютерах с другим окружением.
|
|||
|
-->
|
|||
|

|
|||
|
|
|||
|
---
|
|||
|
<!-- Как добиться того, чтобы программа запущенная успешно на одном компьютере, была также успешно запущена на другом? Современные проекты представляют собой зачастую сложную комбинацию инструментов, библиотек и обеспечить воспроизводимость в этих условиях непросто. Классическое управление зависимостями в Linux-системах не позволяло добиться хорошей воспроизводимости. Docker появился во многом в ответ на эту проблему плохого управления зависимостями в операционной системе. Как это решил Docker? -->
|
|||
|
|
|||
|
# "В"
|
|||
|
воспроизводимость
|
|||
|
|
|||
|
---
|
|||
|
<!-- Как мы знаем, Docker создаёт своеобразную песочницу вокруг вашего приложения и вы передаёте его вместе с ней, чтобы состояние машины пользователя не влияло на работоспособность. Идеальная картика выглядит так: на входе Dockerfile, на выходе Образ. Вроде всё круто -->
|
|||
|
|
|||
|
# Теория
|
|||
|
Dockerfile -> Image
|
|||
|
|
|||
|
---
|
|||
|
<!-- Но де-факто с одним и тем же докерфайлом вы можете получить кучу разных образов. Почему так происходит? -->
|
|||
|
|
|||
|
# Реальность
|
|||
|
Dockerfile -> Image1 || Image2 ... ImageN
|
|||
|
|
|||
|
---
|
|||
|
<!--
|
|||
|
Если посмотреть вглубь, то можно обнаружить, что в типичном Docker-файле для ROS есть сразу несколько мест, которые сделают вашу сборку невоспроизводимой на другом компьютере:
|
|||
|
1. hub.docker.com
|
|||
|
2. apt-репозиторий
|
|||
|
3. rosdep-репозиторий
|
|||
|
3. файл, взятый по имени
|
|||
|
|
|||
|
Но есть другие недостатки:
|
|||
|
1. Возможность комбинировать зависимости (docker позволяет создавать контейнеры только наследуя от одного базового - нельзя добавить несколько базовых контейнеров)
|
|||
|
2. Необходимость тянуть с собой все зависимости, даже если они представлены в системе
|
|||
|
-->
|
|||
|
|
|||
|
# Типичный Dockerfile для ROS
|
|||
|
FROM ros:foxy-ros-base-focal
|
|||
|
...
|
|||
|
RUN rosdep update && apt-get update
|
|||
|
...
|
|||
|
RUN apk add --no-cache python g++ make
|
|||
|
...
|
|||
|
RUN curl -sSL http://get.gazebosim.org | sh
|
|||
|
...
|
|||
|
CMD [ "ros2", "launch", "app", "app_bringup.launch.py" ]
|
|||
|
---
|
|||
|
<!-- # Что предлагает Nix? -->
|
|||
|
# Ключевая идея nix
|
|||
|
Описывать сборку в виде _чистой функции_ или уравнения(derivation), результат исполнения строго детерминирован входными параметрами.
|
|||
|
|
|||
|
---
|
|||
|
<!-- Именно эта идея и легла в основу диссертации автора nix под названием ___, где как раз и описывались недостатки классической системы использования динамических библиотек в unix-подобных системах. Данный подход получил название декларативным в противовес императивного. -->
|
|||
|

|
|||
|
Eelco Dolstra
|
|||
|
## The Purely Functional Software Deployment Model
|
|||
|
PhD Thesis'2006
|
|||
|
https://edolstra.github.io/pubs/phd-thesis.pdf
|
|||
|
|
|||
|
---
|
|||
|
# Парадигмы программирования
|
|||
|
* Императивная (как?) - C, C++, Java
|
|||
|
* Декларативная (что?) - Lisp, Prolog, Nix
|
|||
|
|
|||
|
---
|
|||
|
<!--
|
|||
|
nix использует функциональный язык программирования для описания процесса сборки. Тут можно сделать некоторое отступление о том, что ROS создан робототехниками для робототехников, а у них по прежнему был и остаётся доминирующим императивный подход к программированию, что обусловлено высокими требованиями к производительности и реальному времени исполнения. Собственно, императивная парадигма распространилась не только на сферу низкоуровневых программ, но и на управление операционной системой. Однако, сфера сборки ПО не требует гарантий реального времени или высокой производительности, в ней куда важнее как раз воспроизводимость, отсутствие неявных обращений к состоянию системы.
|
|||
|
-->
|
|||
|
|
|||
|
# Парадигмы конфигурации
|
|||
|
|
|||
|
* Императивная конфигурация (apt)
|
|||
|
- Изменение состояния (dependency hell, неконсистентные состояния)
|
|||
|
* Декларативная конфигурация (nix)
|
|||
|
- Пакеты = иммутабельные переменные (нельзя изменить напрямую, только через функцию)
|
|||
|
- Одно и то же nix-выражение даёт всегда один и тот же результат
|
|||
|
|
|||
|
---
|
|||
|
<!-- как выглядит типичное Nix-выражение. Это уравнение превращается в такой json-образный файл, где и прописаны все версии с хэшами конкретных зависимостей. Этот файл и является по сути инструкцией или чистой функцией, на выходе которой мы получаем конкретные артефакты в виде пакетов, бинарников, динамических библиотек и т.п. -->
|
|||
|
{
|
|||
|
pname = "hello";
|
|||
|
version = "2.12.1";
|
|||
|
src = fetchurl {
|
|||
|
url = "http://github.com/hello-${version}.tar.bz2";
|
|||
|
sha256 = "0x2g1jqy...";
|
|||
|
};
|
|||
|
buildInputs = [ libbar perl ncurses ];
|
|||
|
buildPhase = ''gcc hello.c -o hello'';
|
|||
|
installPhase = ''mkdir -p $out/bin && cp hello $out/bin'';
|
|||
|
}
|
|||
|
---
|
|||
|
{
|
|||
|
"builder": "/nix/store/561wgc73s0x1250hrgp7jm22hhv7yfln-bash-5.2-p15/bin/bash",
|
|||
|
"env": {
|
|||
|
"builder": "/nix/store/561wgc73s0x1250hrgp7jm22hhv7yfln-bash-5.2-p15/bin/bash",
|
|||
|
"out": "/nix/store/260q5867crm1xjs4khgqpl6vr9kywql1-hello-2.12.1",
|
|||
|
"src": "/nix/store/pa10z4ngm0g83kx9mssrqzz30s84vq7k-hello-2.12.1.tar.gz",
|
|||
|
"stdenv": "/nix/store/b09v23lirgvci3wzszh22mbkdfj0h0yq-stdenv-linux",
|
|||
|
"version": "2.12.1"
|
|||
|
},
|
|||
|
"inputDrvs": {
|
|||
|
"/nix/store/0hnjp6s8k71xm62157v37zg3qzwvl8lx-bash-5.2-p15.drv": [ "out" ],
|
|||
|
"/nix/store/8n3ib41pb90nkq3vv49z520qinf4q9c0-hello-2.12.1.tar.gz.drv": [ "out" ],
|
|||
|
"/nix/store/r2h029bx2fbyxxj84s5hf1abp2vfkah2-stdenv-linux.drv": [ "out" ]
|
|||
|
},
|
|||
|
"inputSrcs": [ "/nix/store/6xg259477c90a229xwmb53pdfkn6ig3g-default-builder.sh" ],
|
|||
|
"outputs": {
|
|||
|
"out": { "path": "/nix/store/260q5867crm1xjs4khgqpl6vr9kywql1-hello-2.12.1" }
|
|||
|
},
|
|||
|
"system": "x86_64-linux"
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
---
|
|||
|
<!-- А вот как это выглядит на диске. Заметьте, имя каждого пакета снабжается хэшом, который позволяет избежать коллизий при совпадении имён и даже совпадении имён и версий, а ещё даёт использовать несколько версий библиотеки одновременно. Откуда берётся этот хэш? -->
|
|||
|
|
|||
|
$ ls /nix/store/ | grep humble
|
|||
|
00z4hg8q0cxhsl5jq4s7iq81zz54j8vy-ros-humble-ament-lint-common-0.12.5-r1
|
|||
|
01nvrmwbf0zbchb3d25kb49rl8jzspv6-ros-humble-ament-cmake-cppcheck-0.12.5-r1
|
|||
|
02gdrzn2yrngmqih4hq0j17vj2hgiiz3-ros-humble-unique-identifier-msgs-2.2.1-r3
|
|||
|
08s5gvg7gaypllyxvzd17w21ijqx3hgd-ros-humble-tf2-msgs-0.25.2-r1
|
|||
|
0hwva9zk3250hd6spwq11ayk0aq4flnm-ros-humble-control-msgs-4.1.0-r1
|
|||
|
|
|||
|
---
|
|||
|
<!-- Собственно этот хэш и получается с помощью криптографической хэш-функции применённой ко всем входным зависимостям -->
|
|||
|

|
|||
|
|
|||
|
---
|
|||
|
<!-- Вы не полагаетесь на apt, можете при желании собрать систему полностью из исходников. -->
|
|||
|
|
|||
|
# Что это даёт для ROS?
|
|||
|
|
|||
|
* Возможность запустить проект ROS на любой ОС, даже без apt
|
|||
|
* Контролируемое управление зависимостями
|
|||
|
* Возможность использования разных версий одних и тех же пакетов и библиотек
|
|||
|
* Детерминированные сборки одной командой
|
|||
|
* CACHE!!!
|
|||
|
|
|||
|
---
|
|||
|
<!--
|
|||
|
|
|||
|
-->
|
|||
|
|
|||
|
# Основные компоненты nix
|
|||
|
|
|||
|
* Nix (менеджер пакетов и язык программирования)
|
|||
|
* Nixpkgs (репозиторий пакетов и стандартная библиотека)
|
|||
|
* NixOS (операционная система)
|
|||
|
* NixOps (DevOps инструмент)
|
|||
|
|
|||
|
---
|
|||
|
<!--
|
|||
|
# Текущее состояние nixpkgs -->
|
|||
|
|
|||
|

|
|||
|
|
|||
|
---
|
|||
|
|
|||
|
## Nix ROS Overlay
|
|||
|
https://github.com/lopsided98/nix-ros-overlay
|
|||
|
|
|||
|
Автоматическая генерация nix-выражений для сборки пакетов ROS из официальных репозиториев (github:ros/rosdistro).
|
|||
|
|
|||
|
---
|
|||
|
{ lib, buildRosPackage, fetchurl, ament-cmake ... }:
|
|||
|
buildRosPackage {
|
|||
|
pname = "ros-rolling-std-msgs";
|
|||
|
version = "4.6.1-r1";
|
|||
|
src = fetchurl {
|
|||
|
url = "https://github.com/ros2-gbp/common_interfaces/std_msgs/4.6.1-1.tar.gz";
|
|||
|
name = "4.6.1-1.tar.gz";
|
|||
|
sha256 = "87eee895c2c60a8335ae2a63b05f99773f0897e451e5bf7f45a14a6c36295640";
|
|||
|
};
|
|||
|
|
|||
|
buildType = "ament_cmake";
|
|||
|
buildInputs = [ ament-cmake rosidl-default-generators ];
|
|||
|
checkInputs = [ ament-lint-common ];
|
|||
|
propagatedBuildInputs = [ builtin-interfaces rosidl-default-runtime ];
|
|||
|
nativeBuildInputs = [ ament-cmake rosidl-default-generators ];
|
|||
|
|
|||
|
meta = {
|
|||
|
description = ''A package containing some standard message definitions.'';
|
|||
|
license = with lib.licenses; [ asl20 ];
|
|||
|
};
|
|||
|
}
|
|||
|
---
|
|||
|
|
|||
|
# Недостатки
|
|||
|
|
|||
|
* Пологая кривая обучения
|
|||
|
* Некоторая разрозненность документации
|
|||
|
* Не все пакеты ROS адаптированы в nix
|
|||
|
* Необходимость сборки мусора
|
|||
|
|
|||
|
|
|||
|
---
|
|||
|
# Полезные ресурсы
|
|||
|
|
|||
|

|
|||
|
Русскоязычное сообщество Telegram
|
|||
|
@ru_nixos
|
|||
|
|
|||
|
Туториал для новичков
|
|||
|
zero-to-nix.com
|