Привет Хабр! Если вам тоже доводилось разбирать незнакомый проект, сопровождать прод или помогать QA, вы знаете, как быстро начинаешь ненавидеть однообразные команды etcdctl: копировать ключ, вбивать get, ловить в терминале многострочные значения, скроллить историю… Особенно если ключей сотни, а половина из них — конфиги или JSON’ы на несколько экранов.

Мне хотелось чего-то попроще: запустил один бинарь в терминале и спокойно ходишь по дереву ключей etcd, как по файловой системе, подобно mc.

Без браузера, без копипаста, с нормальным просмотром и редактированием многострочных значений. Так появился etcd-walker.

Под катом расскажу, как он устроен, почему в etcd v2 внезапно пропадают ключи, которые начинаются с подчеркивания, как их всё-таки увидеть, зачем понадобилась “инъекция” узлов, и как решить боль с большими многострочными ключами, например JSON или yaml. А также покажу, как этот инструмент помогает разбираться с локами, которые создает python библиотека для работы c etcd.

Если вы хоть раз пробовали разгрести чужое хранилище в etcd, то поймёте, почему без подобного инструмента жить уже не хочется.

Что такое etcd-walker

etcd-walker — это консольное TUI-приложение (на базе tview/tcell), которое:

  • работает прямо в терминале, без web UI;

  • подключается к etcd v2 и v3 (можно явно выбрать протокол или работать в режиме auto);

  • показывает дерево ключей как каталоги/файлы:

    • слева — список ключей/“папок”;

    • справа — панель с деталями (полное имя, Cluster ID, значение);

  • позволяет:

    • создавать ключи и “каталоги”;

    • удалять (в том числе рекурсивно);

    • редактировать значения, в том числе в полноэкранном многстрочном редакторе;

    • быстро искать и прыгать к нужному ключу.

И самое важное — утилиту можно просто запустить в терминале и забыть про etcdctl для ежедневной рутины. А заодно, если вы так же любите TUI, как автор — это просто приятно эстетически :)

Архитектура вкратце

Утилита разбита на три слоя:

  • model — работа с etcd (v2 и v3), минимальный API: (Ls, Get,  Set,  MkDir, Del, DelDir, RenameDir)

  • view — TUI на базе tview:

    • список ключей, 

    • панель деталей,

    • модальные окна,

    • полноэкранный редактор;

  • controller — склеивает всё вышеперечисленное :)

    • хранит текущее “каталогоподобное” состояние currentDir;

    • управляет навигацией, поиском, Jump, выделением;

    • решает “магические” кейсы - например, с ключами, начинающимися с “_”

При запуске в хедере показывается, к какому хосту и порту утилита подключилась и какой протокол реально используется — v2 или v3.

Основная боль: многострочные значения

Одна из причин написать отдельный инструмент — многострочные ключи. В реальных проектах в etcd живут:

  • большие JSON-конфиги;

  • шаблоны;

  • текстовые настройки;

  • логи/дампы для отладки.

Через etcdctl это читать и править — мучение: терминал ломает форматирование, не видно границы строк, любой промах — снова вбивать команду.

В etcd-walker это решено так:

  • при выборе “файла” (ключа без IsDir) в правой панели сразу видно полное значение целиком;

  • есть два режима редактирования:

           - обычный (однострочное поле);

            - многострочный полноэкранный редактор (горячая клавиша Ctrl+E, если это файл): открывается TextArea и можно спокойно править большие тексты.

После сохранения значение отправляется через model.Set, TUI обновляется, курсор остается на нужном ключе, а детальная панель тут же показывает новое значение. Всё это работает и для обычных ключей, и для “особенных” вроде тех, что начинаются с _.

Проблема ключей, начинающихся с _ в etcd v2

В etcd v2 есть неприятный кейс: ключи, которые находятся на “корне” и начинаются с подчеркивания, не всегда попадают в привычный обзор дерева.

Посмотрим на пример:

curl -s 'http://127.0.0.1:2379/v2/keys/_test' | jq .

Ответ:

{
  "action": "get",
  "node": {
    "key": "/_test",
    "value": "test",
    "modifiedIndex": 4,
    "createdIndex": 4
  }
}

То есть ключ / _test существует, значение "test", всё ок.

А теперь попробуем посмотреть весь “корень”:

curl -s 'http://127.0.0.1:2379/v2/keys/?recursive=true' | jq .

Ответ:

{
  "action": "get",
  "node": {
    "dir": true
  }
}

То есть etcd сообщает, что это каталог ("dir": true), но детей не показывает — ни /foo, ни /_test, ничего. В итоге TUI, который просто обходит дерево через ls("/"), вообще не видит / _test и подобных ключей.

Как etcd-walker решает проблему ключей с _ через Jump

В контроллере есть механизм “инъекции” узлов — injectNode. И есть отдельная команда Jump (Ctrl+J), которая:

  1. Берет введенный путь (абсолютный или относительный).

  2. Через model.Get делает прямой запрос к etcd:

    - для v2 — это прямой вызов KeysAPI.Get по ключу;

    - для v3 — запрос через clientv3.Get.

  3. Если ключ найден:

    - утилита определяет это “директория” (набор ключей с общим префиксом) или файл;

    - создаёт Node и подкладывает его в кеш injected для родительской “папки”, то есть / _test после Jump реально “вклеивается” в список корня /;

    - если это директория — переключает текущий “каталог” на неё;

    - если это файл — переходит в родительский каталог и ставит курсор на этот ключ.

  4. При последующих обновлениях списка (updateList) контроллер:

    - сначала берёт real-список от модели (Ls);

    - затем поверх него сливает “инъектированные” узлы;

    - если ключ уже есть в ответе сервера, отдается приоритет “реальному” варианту.

Таким образом:

  • даже если etcd v2 не показывает / _test в дереве,
    один раз прыгнув к нему через Jump — вы “подсветите” его для TUI;

  • в списке такой ключ будет отображаться как обычный файл, который дополнительно подсвечивается жёлтым, т.к. colorize специально крастит всё, что начинается с _.

Практически это выглядит так:

  1. Вы находитесь в корне /.

  2. Нажимаете Ctrl+J.

  3. Вводите:

    /_test — абсолютный путь, или _test — относительный от текущего каталога.

  4. Если ключ существует, etcd-walker:

    - открывает каталог /;

    - отображает / _test среди других ключей (если они есть);

    - ставит курсор на нём;

    - показывает в правой панели полное значение и метаданные.

Дальше можно:

  • открывать полноэкранный редактор;

  • удалять ключ;

  • смотреть значение, не мучаясь с curl/etcdctl.

Работа с локами на базе EtcdLock

Многие библиотеки поверх etcd используют “скрытые” ключи (часто с _ в имени) для реализации распределённых локов. Типичный пример — Python-клиент:

from etcd import Lock as EtcdLock

Внутри EtcdLock создаёт служебный ключ в etcd (часто с префиксом , типа /locks/...), который:

  • может жить недолго (TTL);

  • не предназначен напрямую для человека;

  • но при отладке или расследовании проблем очень хочется видеть:

    • какие именно ключи создаются;

    • где они висят;

    • не “завис” ли где-то лок.

С обычным обходом /v2/keys/?recursive=true такие ключи легко “потерять” — как мы видели на примере /_test.

С etcd-walker подход другой:

  • вы просто знаете (или подозреваете), где живёт лок,
    например /_locks/user-123 или /_test_lock;

  • жмёте Ctrl+J, вписываете путь и попадаете именно туда;

  • ключ инъектируется в дерево и становится видимым в TUI;

  • дальше можно смотреть значение, при необходимости удалять зависшие локи и наблюдать, как они появляются и исчезают в реальном времени.

Это сильно упрощает анализ и отладку распределённых локов, особенно в QA/стейджинг окружениях, где руками приходится разбирать странные состояния.

Навигация и поиск, когда ключей очень много

На реальных кластерах etcd в одном “уровне” (в одном префиксе) легко может быть сотни ключей. Листать их стрелками — такое себе. В etcd-walker для этого есть несколько фич:

Поиск по имени (/ или Ctrl+S)

  • Нажимаете / илиCtrl+S — открывается строка поиска.

  • Вводите префикс имени (поиск регистронезависимый).

  • Работает автодополнение то есть, показываются только те имена, которые начинаются с введённой строкой.

  • По Enter курсор прыгает на найденный ключ в текущем каталоге.

Это удобно, когда, например, на уровне /services/ куча разных сервисов, и нужно быстро найти /services/payment или /services/auth.

Jump по пути (Ctrl+J)

  • Если вы знаете путь целиком или частично — используете Jump:

    • абсолютный путь /foo/bar/baz;

    • относительный от текущего каталога bar/baz;

    • для “директории” удобно добавить / на конец, чтобы утилита требовала именно папку.

  • Jump работает поверх Get, а не Ls, поэтому может найти ключи, которых нет в обычном дереве (тот самый кейс с _).

Запоминание позиции

Контроллер хранит position для каждого каталога:

  • при переходе “вниз” - запоминает позицию в текущем каталоге;

  • при возвращении “вверх” [..] или Backspace восстанавливает её.

Это даёт эффект “как в нормальном файловом менеджере”: вернувшись на уровень выше, вы попадаете ровно туда же, а не в начало списка.

Ключи, начинающиеся с _, в списке подсвечиваются жёлтым, чтобы их легко было визуально отделить от остальных — это удобно для тех самых “скрытых” служебных сущностей (локи, системные ключи и т.п.).

Поскольку автор любит TUI, интерфейс сделан максимально “клавиатурным”.

Итог

etcd-walker появился из очень практичной мотивации:

  • лень и скука постоянно писать команды etcdctl ради банального просмотра и правки значений;

  • боль с многострочными ключами, где обычный терминал не даёт нормального UX;

  • неудобство работы со скрытыми ключами (особенно теми, что начинаются с _), которых не видно в стандартном дереве etcd v2, но которые критичны для локов и служебной логики.

Теперь всё это закрывается одним TUI-инструментом, который:

  • запускается как обычная консольная утилита;

  • даёт привычную “каталожную” навигацию по ключам;

  • умеет полноэкранный многстрочный редактор;

  • адекватно работает с etcd v2 и v3;

  • позволяет видеть и трогать “невидимые” _-ключи через Jump и механизм инъекции.

Если вы много ковыряетесь в конфигурации через etcd, копаетесь в чужих проектах или помогаете QA — такой TUI-проводник очень быстро становится чем-то, что просто всегда хочется иметь под рукой. Ну и это opensource и PR приветствуется ?

Комментарии (3)


  1. DmitriyEssensci
    05.12.2025 12:16

    Приятная статейка


  1. baldr
    05.12.2025 12:16

    Любопытно. А для Redis что-нибудь похожее есть? Ну, то есть, существует RedisInsight, но хотелось бы в консоли.


    1. RustDaemon Автор
      05.12.2025 12:16

      Готового TUI не видел, к сожалению.