Первый шаг был простой: локальная модель, шлюз перед ней, веб-интерфейс сверху. Заработало за вечер.
Потом я посмотрел на это трезво и нашёл четыре вещи, каждая из которых делала «работает» неправдой:
— шлюз отвечал 200 на запрос вообще без ключа;
— рантайм я запускал руками, и после перезагрузки он не поднимался;
— образы стояли на плавающих тегах, то есть следующий pull мог сломать всё молча;
— ничего из этого не лежало в Git.
Вывод, который стал у меня правилом: то, что запущено руками и не записано скриптом или конфигом, считается несуществующим. Не «надо бы оформить», а именно несуществующим — иначе перенос на другую машину превращается в археологию по памяти.
Починил: автозапуск через launchd, ключи на всех входах, версии образов прибиты, всё под Git.