Моделирование сети потоков с использованием OpenThread в Docker

1. Введение

26b7f4f6b3ea0700.png

OpenThread , выпущенный Google, представляет собой реализацию сетевого протокола Thread с открытым исходным кодом. Google Nest выпустила OpenThread, чтобы сделать технологию, используемую в продуктах Nest, широко доступной для разработчиков и ускорить разработку продуктов для подключенного дома.

Спецификация Thread определяет надежный, безопасный и маломощный протокол беспроводной связи между устройствами на основе IPv6 для домашних приложений. OpenThread реализует все сетевые уровни Thread, включая IPv6, 6LoWPAN, IEEE 802.15.4 с безопасностью MAC, созданием Mesh Link и Mesh Routing.

В этой лаборатории кода вы узнаете, как моделировать сеть Thread на эмулируемых устройствах с помощью Docker.

Что вы узнаете

  • Как настроить набор инструментов сборки OpenThread
  • Как смоделировать сеть потоков
  • Как аутентифицировать узлы потоков
  • Как управлять сетью потоков с помощью OpenThread Daemon

Что вам понадобится

  • Докер
  • Базовые знания Linux, сетевая маршрутизация.

2. Настройте Докер

Эта Codelab предназначена для использования Docker на компьютере с Linux, Mac OS X или Windows. Linux является рекомендуемой средой.

Установить Докер

Установите Docker на выбранную вами ОС.

Извлеките образ Docker

После установки Docker откройте окно терминала и извлеките образ Docker openthread/environment . В этом образе представлены предварительно созданные и готовые к использованию OpenThread и OpenThread Daemon для этой лаборатории кода.

$ docker pull openthread/environment:latest

Обратите внимание, что полная загрузка может занять несколько минут.

В окне терминала запустите Docker-контейнер из образа и подключитесь к его оболочке bash :

$ docker run --name codelab_otsim_ctnr -it --rm \
   --sysctl net.ipv6.conf.all.disable_ipv6=0 \
   --cap-add=net_admin openthread/environment bash

Опция --rm удаляет контейнер при выходе из контейнера. Не используйте эту опцию, если вы не хотите, чтобы контейнер был удален.

Обратите внимание на флаги, которые необходимы для этой Codelab:

  • --sysctl net.ipv6.conf.all.disable_ipv6=0 — включает IPv6 внутри контейнера.
  • --cap-add=net_admin — включает возможность NET_ADMIN, которая позволяет выполнять сетевые операции, такие как добавление IP-маршрутов.

Оказавшись в контейнере, вы должны увидеть приглашение, подобное этому:

root@c0f3912a74ff:/#

В приведенном выше примере c0f3912a74ff — это идентификатор контейнера. Идентификатор контейнера для вашего экземпляра контейнера Docker будет отличаться от идентификатора, показанного в подсказках для этой лаборатории кода.

Использование Докера

В этом Codelab предполагается, что вы знаете основы использования Docker. Вы должны оставаться в контейнере Docker на протяжении всей работы Codelab.

3. Имитация сети потоков

Пример приложения, которое вы будете использовать для этого Codelab, демонстрирует минимальное приложение OpenThread, которое предоставляет интерфейсы настройки и управления OpenThread через базовый интерфейс командной строки (CLI).

В этом упражнении вы выполните минимальные шаги, необходимые для проверки связи одного эмулируемого устройства Thread с другим эмулируемым устройством Thread.

На рисунке ниже описана базовая топология сети потоков. В этом упражнении мы эмулируем два узла внутри зеленого круга: лидера потока и маршрутизатора потока с одним соединением между ними.

6e3aa07675f902dc.png

Создать сеть

1. Запустите узел 1.

Если вы еще этого не сделали, в окне терминала запустите контейнер Docker и подключитесь к его оболочке bash :

$ docker run --name codelab_otsim_ctnr -it --rm \
   --sysctl net.ipv6.conf.all.disable_ipv6=0 \
   --cap-add=net_admin openthread/environment bash

В контейнере Docker создайте процесс CLI для эмулируемого устройства Thread, используя двоичный файл ot-cli-ftd .

root@c0f3912a74ff:/# /openthread/build/examples/apps/cli/ot-cli-ftd 1

Примечание. Если после выполнения этой команды вы не видите приглашение > , нажмите enter .

Этот двоичный файл реализует устройство OpenThread. Радиодрайвер IEEE 802.15.4 реализован поверх UDP (кадры IEEE 802.15.4 передаются внутри полезных данных UDP).

Аргумент 1 — это файловый дескриптор, который представляет младшие биты «назначенного на заводе» IEEE EUI-64 для эмулируемого устройства. Это значение также используется при привязке к порту UDP для радиоэмуляции IEEE 802.15.4 (порт = 9000 + файловый дескриптор). Каждый экземпляр эмулируемого устройства Thread в этой Codelab будет использовать другой файловый дескриптор.

Примечание. При запуске процесса для эмулируемого устройства используйте только файловые дескрипторы 1 или выше, как указано в этой Codelab. Дескриптор файла 0 зарезервирован для другого использования.

Создайте новый набор операционных данных и зафиксируйте его как активный. Операционный набор данных — это конфигурация создаваемой вами сети потоков.

> dataset init new
Done
> dataset
Active Timestamp: 1
Channel: 20
Channel Mask: 07fff800
Ext PAN ID: d6263b6d857647da
Mesh Local Prefix: fd61:2344:9a52:ede0/64
Network Key: e4344ca17d1dca2a33f064992f31f786
Network Name: OpenThread-c169
PAN ID: 0xc169
PSKc: ebb4f2f8a68026fc55bcf3d7be3e6fe4
Security Policy: 0, onrcb
Done

Зафиксируйте этот набор данных как активный:

> dataset commit active
Done

Поднимите интерфейс IPv6:

> ifconfig up
Done

Запускаем работу протокола потока:

> thread start
Done

Подождите несколько секунд и убедитесь, что устройство стало лидером темы. Лидер — это устройство, отвечающее за управление назначением идентификатора маршрутизатора.

> state
leader
Done

Просмотрите адреса IPv6, назначенные интерфейсу потока узла 1 (ваш вывод будет другим):

> ipaddr
fd61:2344:9a52:ede0:0:ff:fe00:fc00
fd61:2344:9a52:ede0:0:ff:fe00:5000
fd61:2344:9a52:ede0:d041:c5ba:a7bc:5ce6
fe80:0:0:0:94da:92ea:1353:4f3b
Done

Обратите внимание на конкретные типы адресов IPv6:

  • Начинается с fd = mesh-local
  • Начинается с fe80 = link-local

Типы Mesh-локальных адресов классифицируются дополнительно:

  • Содержит ff:fe00 = локатор маршрутизатора (RLOC).
  • Не содержит ff:fe00 = идентификатор конечной точки (EID)

Определите EID в выводе консоли и запишите его для дальнейшего использования. В приведенном выше примере выходных данных EID имеет следующий вид:

fd61:2344:9a52:ede0:d041:c5ba:a7bc:5ce6

2. Запустить узел 2.

Откройте новый терминал и запустите оболочку bash в работающем в данный момент контейнере Docker, чтобы использовать его для узла 2.

$ docker exec -it codelab_otsim_ctnr bash

В этом новом приглашении bash запустите процесс CLI с аргументом 2 . Это ваше второе эмулируемое устройство Thread:

root@c0f3912a74ff:/# /openthread/build/examples/apps/cli/ot-cli-ftd 2

Примечание. Если после выполнения этой команды вы не видите приглашение > , нажмите enter .

Настройте ключ сети потока и идентификатор PAN, используя те же значения, что и в наборе рабочих данных узла 1:

> dataset networkkey e4344ca17d1dca2a33f064992f31f786
Done
> dataset panid 0xc169
Done

Зафиксируйте этот набор данных как активный:

> dataset commit active
Done

Поднимите интерфейс IPv6:

> ifconfig up
Done

Запускаем работу протокола потока:

> thread start
Done

Устройство инициализируется как дочернее. Дочерний поток эквивалентен конечному устройству, которое представляет собой устройство потока, которое передает и получает одноадресный трафик только с родительским устройством.

> state
child
Done

В течение 2 минут вы должны увидеть переключение состояния с child на router . Маршрутизатор потоков способен маршрутизировать трафик между устройствами потоков. Его еще называют Родителем.

> state
router
Done

Проверьте сеть

Простой способ проверить ячеистую сеть — посмотреть таблицу маршрутизатора.

1. Проверьте подключение

На узле 2 получите RLOC16. RLOC16 — это последние 16 бит IPv6-адреса RLOC устройства.

> rloc16
5800
Done

На узле 1 проверьте таблицу маршрутизации на наличие RLOC16 узла 2. Убедитесь, что узел 2 сначала перешел в состояние маршрутизатора.

> router table
| ID | RLOC16 | Next Hop | Path Cost | LQ In  | LQ Out  | Age | Extended MAC   |
+----+--------+----------+-----------+--------+-------+---+--------------------+
| 20 | 0x5000 |       63 |         0 |      0 |     0 |   0 | 96da92ea13534f3b |
| 22 | 0x5800 |       63 |         0 |      3 |     3 |  23 | 5a4eb647eb6bc66c |

В таблице указан RLOC узла 2, равный 0x5800 , что подтверждает его подключение к сети.

2. Пинг узла 1 с узла 2.

Проверьте соединение между двумя эмулируемыми устройствами Thread. На узле 2 ping EID, назначенный узлу 1:

> ping fd61:2344:9a52:ede0:d041:c5ba:a7bc:5ce6
> 16 bytes from fd61:2344:9a52:ede0:d041:c5ba:a7bc:5ce6: icmp_seq=1 hlim=64 time=12ms

Нажмите enter , чтобы вернуться к приглашению > CLI.

Проверьте сеть

Теперь, когда вы можете успешно выполнить проверку связи между двумя эмулируемыми устройствами Thread, протестируйте ячеистую сеть, отключив один узел.

Вернитесь к узлу 1 и остановите поток:

> thread stop
Done

Переключитесь на узел 2 и проверьте состояние. В течение двух минут Узел 2 обнаруживает, что лидер (Узел 1) находится в автономном режиме, и вы должны увидеть, как Узел 2 становится leader сети:

> state
router
Done
...
> state
leader
Done

После подтверждения остановите поток и выполните сброс настроек узла 2, прежде чем вернуться к командной строке Docker bash . Сброс к заводским настройкам выполняется для того, чтобы гарантировать, что учетные данные сети Thread, которые мы использовали в этом упражнении, не будут перенесены в следующее упражнение.

> thread stop
Done
> factoryreset
>
> exit
root@c0f3912a74ff:/#

Возможно, вам придется нажать enter несколько раз, чтобы вернуть приглашение > после команды factoryreset . Не выходите из Docker-контейнера.

Также сброс настроек к заводским настройкам и выход из узла 1:

> factoryreset
>
> exit
root@c0f3912a74ff:/#

См. Справочник по OpenThread CLI , чтобы изучить все доступные команды CLI.

4. Аутентификация узлов при вводе в эксплуатацию

В предыдущем упражнении вы настроили сеть Thread с двумя смоделированными устройствами и проверенным подключением. Однако это позволяет передавать между устройствами только неаутентифицированный локальный трафик IPv6. Чтобы маршрутизировать глобальный трафик IPv6 между ними (и Интернетом через пограничный маршрутизатор Thread), узлы должны пройти аутентификацию.

Для аутентификации одно устройство должно выступать в роли комиссара. Комиссар является избранным в настоящее время сервером аутентификации для новых устройств Thread и авторизатором предоставления сетевых учетных данных, необходимых для подключения устройств к сети.

В этом упражнении мы будем использовать ту же топологию с двумя узлами, что и раньше. Для аутентификации лидер потока будет выступать в роли комиссара, а маршрутизатор потока — в качестве участника.

d6a67e8a0d0b5dcb.png

Докер

Для каждого узла (окна терминала) в оставшихся упражнениях убедитесь, что вы запускаете контейнер Docker со сборкой OpenThread. Если продолжить предыдущее упражнение, у вас по-прежнему должно быть открыто два приглашения bash в одном контейнере Docker. Если нет, см. шаг «Устранение неполадок Docker» или просто повторите упражнение «Моделирование сети потока» .

1. Создайте сеть

В узле 1 создайте процесс CLI:

root@c0f3912a74ff:/# /openthread/build/examples/apps/cli/ot-cli-ftd 1

Примечание. Если после выполнения этой команды вы не видите приглашение > , нажмите enter .

Создайте новый набор операционных данных, зафиксируйте его как активный и запустите поток:

> dataset init new
Done
> dataset
Active Timestamp: 1
Channel: 12
Channel Mask: 07fff800
Ext PAN ID: e68d05794bf13052
Mesh Local Prefix: fd7d:ddf7:877b:8756/64
Network Key: a77fe1d03b0e8028a4e13213de38080e
Network Name: OpenThread-8f37
PAN ID: 0x8f37
PSKc: f9debbc1532487984b17f92cd55b21fc
Security Policy: 0, onrcb
Done

Зафиксируйте этот набор данных как активный:

> dataset commit active
Done

Поднимите интерфейс IPv6:

> ifconfig up
Done

Запускаем работу протокола потока:

> thread start
Done

Подождите несколько секунд и убедитесь, что устройство стало лидером темы:

> state
leader
Done

2. Начните работу в роли комиссара

Еще находясь на узле 1, начните роль комиссара:

> commissioner start
Done

Разрешите любому участнику (с помощью подстановочного знака * ) с учетными данными участника J01NME присоединиться к сети. Столяр — это устройство, которое добавляется администратором в введенную в эксплуатацию сеть потоков.

> commissioner joiner add * J01NME
Done

3. Запустите роль Столяра

Во втором окне терминала в контейнере Docker создайте новый процесс CLI. Это узел 2.

root@c0f3912a74ff:/# /openthread/build/examples/apps/cli/ot-cli-ftd 2

На узле 2 включите роль присоединения, используя учетные данные присоединения J01NME .

> ifconfig up
Done
> joiner start J01NME
Done

...подождите несколько секунд для подтверждения...

Join success

В качестве участника устройство (узел 2) успешно прошло аутентификацию у комиссара (узел 1) и получило учетные данные сети потоков.

Теперь, когда узел 2 аутентифицирован, запустите поток:

> thread start
Done

4. Проверка сетевой аутентификации.

Проверьте state узла 2, чтобы убедиться, что он теперь подключен к сети. В течение двух минут Узел 2 переходит из child в router :

> state
child
Done
...
> state
router
Done

5. Сброс конфигурации

Чтобы подготовиться к следующему упражнению, сбросьте конфигурацию. На каждом узле остановите Thread, выполните сброс настроек к заводским и выйдите из эмулируемого устройства Thread:

> thread stop
Done
> factoryreset
>
> exit
root@c0f3912a74ff:/#

Возможно, вам придется нажать enter несколько раз, чтобы вернуть приглашение > после команды factoryreset .

5. Управляйте сетью с помощью OpenThread Daemon.

В этом упражнении мы собираемся смоделировать один экземпляр CLI (одно встроенное устройство SoC Thread) и один экземпляр радиосопроцессора (RCP).

ot-daemon — это режим приложения OpenThread Posix, который использует сокет UNIX в качестве ввода и вывода, поэтому ядро ​​OpenThread может работать как служба. Клиент может взаимодействовать с этой службой, подключаясь к сокету, используя OpenThread CLI в качестве протокола.

ot-ctl — это интерфейс командной строки, предоставляемый ot-daemon для управления и настройки RCP. Используя это, мы подключим RCP к сети, созданной устройством Thread.

Докер

Для каждого узла (окна терминала) в этом упражнении убедитесь, что вы запускаете контейнер Docker со сборкой OpenThread. Если продолжить предыдущее упражнение, у вас уже должно быть открыто два приглашения bash в одном контейнере Docker. Если нет, см. шаг «Устранение неполадок Docker» .

Используйте ot-daemon

В этом упражнении будут использоваться три окна терминала, соответствующие следующему:

  1. Экземпляр CLI моделируемого устройства Thread (узел 1)
  2. процесс ot-daemon
  3. экземпляр CLI ot-ctl

1. Запустите узел 1.

В первом окне терминала запустите процесс CLI для эмулируемого устройства Thread:

root@c0f3912a74ff:/# /openthread/build/examples/apps/cli/ot-cli-ftd 1

Примечание. Если после выполнения этой команды вы не видите приглашение > , нажмите enter .

Создайте новый набор операционных данных, зафиксируйте его как активный и запустите поток:

> dataset init new
Done
> dataset
Active Timestamp: 1
Channel: 13
Channel Mask: 07fff800
Ext PAN ID: 97d584bcd493b824
Mesh Local Prefix: fd55:cf34:dea5:7994/64
Network Key: ba6e886c7af50598df1115fa07658a83
Network Name: OpenThread-34e4
PAN ID: 0x34e4
PSKc: 38d6fd32c866927a4dfcc06d79ae1192
Security Policy: 0, onrcb
Done

Зафиксируйте этот набор данных как активный:

> dataset commit active
Done

Поднимите интерфейс IPv6:

> ifconfig up
Done

Запускаем работу протокола потока:

> thread start
Done

Просмотрите адреса IPv6, назначенные интерфейсу потока узла 1:

> ipaddr
fd55:cf34:dea5:7994:0:ff:fe00:fc00
fd55:cf34:dea5:7994:0:ff:fe00:d000
fd55:cf34:dea5:7994:460:872c:e807:c4ab
fe80:0:0:0:9cd8:aab6:482f:4cdc
Done
>

Как объяснялось в шаге «Моделирование сети потока» , один адрес является локальным для канала ( fe80 ), а три — локальными для сети ( fd ). EID — это локальный адрес сети, который не содержит ff:fe00 в адресе. В этом примере выходных данных EID — fd55:cf34:dea5:7994:460:872c:e807:c4ab .

Определите конкретный EID из выходных данных ipaddr , который будет использоваться для связи с узлом.

2. Запустите ot-daemon

Во втором окне терминала создайте узел устройства tun и установите разрешения на чтение/запись:

root@c0f3912a74ff:/# mkdir -p /dev/net && mknod /dev/net/tun c 10 200
root@c0f3912a74ff:/# chmod 600 /dev/net/tun

Это устройство используется для передачи и приема пакетов в виртуальных устройствах. Вы можете получить сообщение об ошибке, если устройство уже создано — это нормально и его можно игнорировать.

Запустите ot-daemon для узла RCP, который мы назовем узлом 2. Используйте подробный флаг -v , чтобы увидеть вывод журнала и убедиться, что он работает:

root@c0f3912a74ff:/# /openthread/build/posix/src/posix/ot-daemon -v \
'spinel+hdlc+forkpty:///openthread/build/examples/apps/ncp/ot-rcp?forkpty-arg=2'

В случае успеха ot-daemon в подробном режиме генерирует выходные данные, подобные следующему:

ot-daemon[31]: Running OPENTHREAD/297a880; POSIX; Feb  1 2022 04:43:39
ot-daemon[31]: Thread version: 3
ot-daemon[31]: Thread interface: wpan0
ot-daemon[31]: RCP version: OPENTHREAD/297a880; SIMULATION; Feb  1 2022 04:42:50

Оставьте этот терминал открытым и работающим в фоновом режиме. Никаких дальнейших команд вы вводить в него не будете.

3. Используйте ot-ctl для подключения к сети.

Мы еще не подключили узел 2 (RCP ot-daemon ) к какой-либо сети Thread. Именно здесь на помощь приходит ot-ctl . ot-ctl использует тот же интерфейс командной строки, что и приложение OpenThread CLI. Таким образом, вы можете управлять узлами ot-daemon так же, как и другими симулируемыми устройствами Thread.

Откройте третье окно терминала и запустите существующий контейнер:

$ docker exec -it codelab_otsim_ctnr bash

Оказавшись в контейнере, запустите ot-ctl :

root@c0f3912a74ff:/# /openthread/build/posix/src/posix/ot-ctl
>

Вы будете использовать ot-ctl в этом третьем окне терминала для управления узлом 2 (узлом RCP), который вы запустили во втором окне терминала с помощью ot-daemon . Проверьте state узла 2:

> state
disabled
Done

Получите eui64 узла 2, чтобы ограничить присоединение к конкретному Joiner:

> eui64
18b4300000000001
Done

На узле 1 (первое окно терминала) запустите Commissioner и ограничьте присоединение только этим eui64:

> commissioner start
Done
> commissioner joiner add 18b4300000000001 J01NME
Done

В третьем окне терминала откройте сетевой интерфейс для узла 2 и подключитесь к сети:

> ifconfig up
Done
> joiner start J01NME
Done

...подождите несколько секунд для подтверждения...

Join success

В качестве участника RCP (узел 2) успешно прошел аутентификацию у комиссара (узел 1) и получил учетные данные сети потоков.

Теперь присоедините Node 2 к сети Thread (опять же в третьем окне терминала):

> thread start
Done

4. Проверка сетевой аутентификации.

В третьем терминале проверьте state узла 2, чтобы убедиться, что он теперь подключен к сети. В течение двух минут Узел 2 переходит из child в router :

> state
child
Done
...
> state
router
Done

5. Проверка подключения

В третьем окне терминала закройте ot-ctl , используя Ctrl+D или команду exit , и вернитесь в консоль bash контейнера. С этой консоли пропингуйте узел 1, используя его EID, с помощью команды ping6 . Если экземпляр RCP ot-daemon успешно присоединен к сети Thread и взаимодействует с ней, пинг будет успешным:

root@c0f3912a74ff:/# ping6 -c 4 fd55:cf34:dea5:7994:460:872c:e807:c4ab
PING fd55:cf34:dea5:7994:460:872c:e807:c4ab (fd55:cf34:dea5:7994:460:872c:e807:c4ab): 56 data bytes
64 bytes from fd55:cf34:dea5:7994:460:872c:e807:c4ab: icmp_seq=0 ttl=64 time=4.568 ms
64 bytes from fd55:cf34:dea5:7994:460:872c:e807:c4ab: icmp_seq=1 ttl=64 time=6.396 ms
64 bytes from fd55:cf34:dea5:7994:460:872c:e807:c4ab: icmp_seq=2 ttl=64 time=7.594 ms
64 bytes from fd55:cf34:dea5:7994:460:872c:e807:c4ab: icmp_seq=3 ttl=64 time=5.461 ms
--- fd55:cf34:dea5:7994:460:872c:e807:c4ab ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max/stddev = 4.568/6.005/7.594/1.122 ms

6. Устранение неполадок Docker

Если вы вышли из Docker-контейнера

bash , вам может потребоваться проверить , работает ли он, и перезапустить/повторить вход при необходимости. Любые контейнеры Docker, созданные вами без использования параметра --rm должны по-прежнему существовать.

Чтобы показать, какие контейнеры Docker запущены:

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
505fc57ffc72        environment       "bash"              10 minutes ago      Up 10 minutes                           codelab_otsim_ctnr

Чтобы отобразить все контейнеры Docker (как запущенные, так и остановленные):

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
505fc57ffc72        environment       "bash"              10 minutes ago      Up 10 minutes                           codelab_otsim_ctnr

Если вы не видите контейнер codelab_otsim_ctnr в выходных данных команды docker ps , запустите ее еще раз:

$ docker run --name codelab_otsim_ctnr -it --rm \
   --sysctl net.ipv6.conf.all.disable_ipv6=0 \
   --cap-add=net_admin openthread/environment bash

Используйте опцию --rm только в том случае, если вы хотите, чтобы контейнер удалялся при выходе из контейнера.

Если контейнер остановлен (указан в docker ps -a но не docker ps ), перезапустите его:

$ docker start -i codelab_otsim_ctnr

Если контейнер Docker уже запущен (указан в docker ps ), повторно подключитесь к контейнеру в каждом терминале:

$ docker exec -it codelab_otsim_ctnr bash

Ошибки «Операция не разрешена»

Если вы столкнулись с ошибками Operation not permitted при создании новых узлов OpenThread (с помощью команды mknod ), убедитесь, что вы запускаете Docker от имени пользователя root в соответствии с командами, представленными в этой лаборатории кода. Эта Codelab не поддерживает запуск Docker в режиме без root-прав .

7. Поздравляем!

Вы успешно смоделировали свою первую сеть Thread с помощью OpenThread. Потрясающий!

В этой Codelab вы узнали, как:

  • Запуск контейнера Docker OpenThread Simulation и управление им.
  • Имитировать сеть потоков
  • Аутентификация узлов потока
  • Управление сетью потоков с помощью OpenThread Daemon

Чтобы узнать больше о Thread и OpenThread, изучите эти ссылки:

Или попробуйте использовать OpenThread Border Router в контейнере Docker !