Tatarnetes: как мы научили Kubernetes говорить по-татарски, цитировать Габдуллу Тукая и останавливаться на чай с молоком

от автора

И туган тел, и матур тел, әткәм-әнкәмнең теле! («О родной язык, о прекрасный язык, язык моих отца и матери!» — Габдулла Тукай, «Туган тел», 1909)

TL;DR. Мы выкатили Татарнетес — национальную обёртку над Kubernetes, где команды, сообщения, ошибки и даже перерывы на чай с чак-чаком и т.п. на татарском. Рядом — TatarOS Linux (обёртка над Talos, которая поднимает кластер с Татарнетесом) и Татарнетес UI (панель на фоне татарского келәма). Всё под собственной лицензией Tatarch 2.0.

Под капотом i18n на чистом bash 3.2 без единой зависимости, три системы письма (кириллица, яңалиф, гарәп язуы), детерминированный чайный график (кластер рандомно останавливается на попить чай с молоком и бабушкиными кыстыбыями) и первый черновик татарской IT-терминологии Kubernetes. А ещё мы прогнали всё на реальном кластере CozyStack — с живыми kubectl/talosctl, RBAC, метриками и одним пойманным багом.

Репозитории tatar-ncf: tatarnetes · tataros · tatarnetes-ui. Лицензия — Tatarch 2.0.

Проект посвящается Саше, Роме, Максу и Рамилю из одного замечательного кубер-чатика.

Тур по консоли на живом кластере

Тур по консоли на живом кластере

1. Зачем нам это вообще

Помимо того, что это просто троллинг, у нас была вполне и серьёзная задумка: туган тел (родной язык) заслуживает того, чтобы жить не только в стихах, но и в терминале! Татарской IT-терминологии для cloud-native почти нет: как по-татарски «reconciliation», «ingress», «replica»? Мы решили не ждать, а предложить — пусть спорный, но живой черновик, который можно дополнять через pull request.

Поэтому Татарнетес — это три вещи одновременно: (1) весёлый инструмент, который поднимает настроение; (2) настоящая инженерная песочница по i18n в bash; (3) вклад в цифровизацию языка — глоссарий и локализация, которые может править любой носитель.

2. Почему запуск 20 сентября

Дату выбирали не «для галочки». Конец сентября у татар — муллык чоры, пора изобилия, когда с полей и садов собирают җимеш (плоды). А в нашей лицензии Tatarch 2.0 любое произведение — код, программа, книга — так и называется: «Җимеш», плод труда. Рәхим итегез — угощайтесь.

И приятное совпадение: 20 сентября 1970 года родился татарский писатель и поэт Марат Кәбиров — один из тех, кто первым затащил татарскую литературу в цифру. Литература, ушедшая в код; код, заговоривший на языке литературы — это по-нашему. Так что Татарнетес — это подарок всей татарской земле и международному татарскому сообществу, от Казани до Стамбула, от Хельсинки до Сан-Франциско. Милләтем данлыклы, халкым юмарт, коды ирекле.

3. Демо за 30 секунд

kubectl get pods знает каждый. А теперь:

ayda күрсәт кузаклар

ayda (әйдә — «давай, пошли!») переводит татарскую команду в kubectl и выполняет её.

Как ayda переводит команду в kubectl

Как ayda переводит команду в kubectl

Ресурсы получили осмысленные татарские имена: под — кузак (стручок, ведь и англ. pod — стручок), node — төен (узел), service — хезмәт, namespace — мәйдан, ingress — капка (ворота), secret — сер, volume — күләм.

Татарские имена ресурсов

Татарские имена ресурсов

При успехе тебя встречает добрая рожица в түбәтәе и хвалит Татарстан; при ошибке — она же, но сердитая, и лёгкое татарское ворчание. Между делом — строка Тукая или горячий эчпочмак.

Успешный вызов: рожа в тюбетейке, мактау и гарнир

Успешный вызов: рожа в тюбетейке, мактау и гарнир

И — да — обычный kubectl тоже работает: ayda get pods пройдёт насквозь. Есть и krew-плагин: kubectl ayda ....

get nodes: узлы кластера по-татарски

get nodes: узлы кластера по-татарски

4. Архитектура: тонкая обёртка

Татарнетес не форкает Kubernetes построчно. Это тонкая, безопасная для пайпов обёртка над kubectl: разобрать татарский, перевести в kubectl, выполнить, обернуть ответ в национальные декорации. Схематично поток такой:

пользователь → ayda (bash) ───────────────→ kubectl → Kubernetes API                 1. resolve_verb (глагол, латин-фолбэк)                 2. resolve_noun (первый позиционный токен = ресурс)                 3. чайный шлюз (tea_now?)                 4. запуск + захват stderr                 5. рожа/мактау/шелтә + гарнир (всё в stderr)

Строк bash — 1936 (ayda + tos + lib/), и это включает шесть систем письма-логики, i18n-движок, корпус и тесты. Ни одной внешней зависимости, только bash, sed, awk, grep — и целевой bash3.2 (тот самый, что стоит на macOS по умолчанию: без ассоциативных массивов, с граблями мультибайта). Это осознанное ограничение: инструмент должен запускаться везде.

5. i18n на чистом bash 3.2

Самое интересное — как локализация живёт без gettext-рантайма.

Источник правды — .po. Строки интерфейса лежат в locale/tt.po (39 msgid) и en.po в обычном gettext-формате, где татарский — канонический:

msgid "err.unknown_verb"msgstr "Мондый әмер юк: «%s»"

Сборка каталога. scripts/build-catalog.sh (awk) генерит из .po чистый bash — case-функцию lib/catalog.sh, чтобы в рантайме не было ни парсинга, ни зависимостей:

catalog_lookup() { # $1=lang $2=key  case "$1:$2" in    tt:err.unknown_verb) printf '%s' 'Мондый әмер юк: «%s»' ;;    en:err.unknown_verb) printf '%s' 'No such command: "%s"' ;;    ...    *) printf '%s' "$2" ;;  esac}

Функция t() достаёт строку, подставляет аргументы и, если язык татарский, прогоняет через транслитерацию:

t() {  local key="$1"; shift  local fmt; fmt="$(catalog_lookup "$AYDA_LANG" "$key")"  local out; out="$(printf "$fmt" "$@")"  if [ "$AYDA_LANG" = "tt" ]; then printf '%s' "$out" | alif_render; else printf '%s' "$out"; fi}

Синхронность каталога сторожит CI: отдельный job пересобирает catalog.sh из .po и падает, если появился diff. Так перевод и рантайм не разъезжаются.

Сингармонизм. Множественное число мы не хардкодим, а порождаем по гармонии гласных: суффикс -лар/-ләр (задний/передний ряд), а после носовых м/н/ң-нар/-нәр:

tn() {  # кузак→кузаклар, төен→төеннәр, хезмәт→хезмәтләр, мәйдан→мәйданнар, сер→серләр  local w="$1" lastvow lastch front=0 nas=0  lastvow="$(printf '%s' "$w" | grep -oE '[аәоөуүыиеэюёяАӘОӨУҮЫИЕЭ]' | tail -1)"  lastch="$(printf '%s' "$w" | grep -oE '.$')"  case "$lastvow" in ә|ө|ү|е|и|э|ю|ё|Ә|Ө|Ү|Е|И|Э) front=1 ;; esac  case "$lastch"  in м|н|ң|М|Н|Ң) nas=1 ;; esac  if [ "$front" -eq 1 ]; then [ "$nas" = 1 ] && echo "${w}нәр" || echo "${w}ләр"  else                        [ "$nas" = 1 ] && echo "${w}нар" || echo "${w}лар"; fi}

Всё это покрыто юнит-тестами (28 проверок в tatarnetes, 12 в tataros).

6. Три письменности одного народа

Татарский за век сменил три алфавита — и каждый это культурный пласт. Татарнетес умеет во все три:

AYDA_ALIF=cyrl  ayda ярдәм    # кириллица (по умолчанию)AYDA_ALIF=latin ayda ярдәм    # яңалиф — латиница 1920–30-хAYDA_ALIF=arab  ayda ярдәм    # яңа имля — татарское арабское письмо
Девиз лицензии в трёх письменностях

Девиз лицензии в трёх письменностях

Латиницей можно и вводить команды (для клавиатур без кириллицы). Причём мы не заводили второй словарь: сначала пробуем распознать как есть, а если не вышло — транслитерируем ввод в кириллицу и пробуем снова. Английские kubectl-глаголы при этом не ломаются:

resolve_noun() {  local n="$1" r c  r="$(translate_noun "$n")"; [ "$r" != "$n" ] && { printf '%s' "$r"; return 0; }  # нашли как есть  c="$(printf '%s' "$n" | latin_to_cyrl)"                                          # латин → кирилл  r="$(translate_noun "$c")"  if [ "$r" != "$c" ]; then printf '%s' "$r"; else printf '%s' "$n"; fi            # иначе — как ввели}
Ввод команды латиницей

Ввод команды латиницей

Арабское письмо (яңа имля, реформа 1920-х) — фонематическое: каждый звук отдельной буквой, все гласные записываются, различаются передний/задний ряд (о ۇ / ө ۆ, у و / ү ۈ). В начале слова гласная получает носитель-хамзу ئ. Выводим в логическом порядке — RTL и соединение букв делает сам терминал. Word-initial hamza добавляем через awk (по словам, byte-safe), а буквы меняем отдельными подстановками:

cyrl_to_arab() {  awk '{ n=split($0,a,/ /); o=""    for(i=1;i<=n;i++){ w=a[i]      if (w ~ /^(а|ә|о|ө|у|ү|ы|и|э|е|я|ю|ё|А|Ә|О|Ө|У|Ү|Ы|И|Э|Е)/) w="ئ" w      o=o (i>1?" ":"") w } print o }' \  | sed -e 's/я/یا/g' -e 's/а/ا/g' -e 's/ә/ە/g' -e 's/о/ۇ/g' -e 's/ө/ۆ/g' \        -e 's/у/و/g' -e 's/ү/ۈ/g' -e 's/к/ك/g' -e 's/т/ت/g' ...   # по одной букве}

Проверяли не на глаз, а по кодпоинтам:

Татарнетес → تاتارنېتېسU+062A TEH · U+0627 ALEF · U+062A TEH · U+0627 ALEF · U+0631 REH · U+0646 NOON· U+06D0 E · U+062A TEH · U+06D0 E · U+0633 SEEN   =  т-а-т-а-р-н-е-т-е-с
Версия в арабском письме (яңа имля, RTL)

Версия в арабском письме (яңа имля, RTL)

7. Кластер уходит на чәй

Несколько раз в сутки Татарнетес останавливается на чай с молоком и кыстыбыем. Стучишься в это время — получаешь картинку и вежливое «Кыстырылма, туганкай — безгә дә чәй эчәргә кирәк!».

Перерыв на чай в консоли

Перерыв на чай в консоли

График детерминированный — выводится из календарного дня, три окна по 7 минут:

tea_windows() {  today=$(date +%Y%m%d); seed=$(( 10#$today )); i=1  while [ "$i" -le 3 ]; do    m=$(( (seed * (i * 37 + 13) + i * 101) % 1440 ))   # минута суток 0..1439    echo "$m 7"; i=$(( i + 1 ))  done}

Та же формула зеркалится в ui/app.js (teaWindowsFor), поэтому консоль и браузер видят одинаковые окна до минуты. Пьёт кластер чай по-настоящему везде — в пайпах и в CI тоже: чәй — это чәй, выход 42. Не хочешь ждать — честная кнопка AYDA_NO_TEA=1 (её же используют наши тесты), а форснуть перерыв для демо — AYDA_FORCE_TEA=1. Робот, впрочем, чаю не откажет — просто знает пароль.

8. pipe-safety и перевод ошибок

Весь «арт» (рожа, мактау, гарнир, ковёр) уходит в stderr, а stdout остаётся чистым — поэтому ayda күрсәт кузаклар -o json | jq работает как обычный kubectl. Чтобы при этом перехватить и перевести ошибку, мы жонглируем дескрипторами: stdout ребёнка идёт «насквозь» (fd 3), а stderr ловим в переменную:

{ ERRTEXT="$("$KUBECTL_BIN" "$kverb" ${kargs[@]+"${kargs[@]}"} 2>&1 1>&3 3>&-)"; RC=$?; } 3>&1

Дальше по тексту ошибки подбираем татарскую подсказку, не пряча оригинал: NotFound«Табылмады — исемен яки мәйданны тикшер», Forbidden«Рөхсәт юк — хокукларыңны (RBAC) тикшер», timeout, connection refused и т. д.

Реальная ошибка kubectl с татарской подсказкой

Реальная ошибка kubectl с татарской подсказкой
Неизвестная команда: сердитая рожа и ворчание

Неизвестная команда: сердитая рожа и ворчание

9. Характер как фичи

Мы старались, чтобы «национальный характер» стал не стереотипом, а полезной фичей.

  • Хуҗалыкчыллык (бережливость). Просишь много реплик — система по-татарски напомнит про экономию: «Акчаны әрәм итмә!» Порог настраивается AYDA_FINOPS_MAX.

  • Кунакчыллык (гостеприимство). При первом заходе в новый контекст тебя встретят как гостя: «Рәхим итегез! Яңа төбәк (контекст): …. Кунагыбыз бул!» (запоминаем последний контекст в ~/.cache/ayda/last_ctx).

  • Календарь. По пятницам — «Җомгагыз мөбарәк булсын!», на Нәүрүз/Сабантуй/байрамы — праздничный баннер (даты 2026-го выверены по Указу Раиса Татарстана).

10. Культурный корпус и борьба с галлюцинациями

Стихи и пословицы вынесены в data/*.tt (9 стихотворных фрагментов, 14 пословиц), чтобы носитель мог дополнять их через PR. Здесь у нас железное правило: классику искажать нельзя. Все строки Тукая, Җәлила, Дәрдмәнда, Сибгата Хакима и народные мәкальләр выверены по источникам, а не по памяти нейросети (в data/VERIFICATION.tt.md — таблица источников). Там, где источник не удалось подтвердить, автор в корпус не попал — точность важнее полноты.

Народная мәкаль как гарнир

Народная мәкаль как гарнир

11. Лицензия Tatarch 2.0

Юридически Tatarch 2.0 эквивалентна Apache License 2.0 — те же права и условия (грант авторских прав, патентный грант с ретолиацией, четыре условия распространения, отказ от гарантий, ограничение ответственности). Совместимость мы берегли специально. Отличается форма и дух:

  • Эпическая преамбула вместо канцелярии: лицензия открывается словами о славной истории, щедрости и кунакчыллыке татарского народа — и звучит как дастан.

  • «Җимеш». Произведение называется не «Work», а Җимеш (плод), и распространяется «иркен, татар кунакны каршылагандай» («свободно, как татарин встречает гостя»).

  • Народное достояние. Каждое произведение провозглашается духовно принадлежащим всему великому татарскому народу. Тут же — честная юридическая оговорка: это почётное заявление, оно не создаёт имущественных прав, копирайт остаётся у правообладателя. Красивая метафора не должна мешать реальному использованию.

  • Двуязычие, татарский — первым (и вся документация тоже). Латиница/арабица — авто-транслит.

Если коротко: берите так же свободно, как под Apache 2.0 — просто у этой свободы есть түбәтәй.

12. TatarOS Linux и Татарнетес UI

Три проекта складываются в один национальный стек:

Милли стек: TatarOS → Татарнетес → UI

Милли стек: TatarOS → Татарнетес → UI

TatarOS Linux — обёртка над Talos (иммутабельная ОС для Kubernetes). CLI называется tos и важно отличается идеологически: он поднимает кластер не с Кубернетесом, а с Татарнетесом. tos татарнетес-конфиг выдаёт доступ — и в кластере тебя ждёт саф Татарнетес.

tos сәламәтлек — health вживую

tos сәламәтлек — health вживую

Татарнетес UI — форк официального дашборда: татарская палитра (яшел-ак-кызыл плюс алтын), фон — настоящий татарский келәм (тамга, лаләләр-тюльпаны, ислими-вязь), а идентификаторы нод — это тамга, родовые знаки. В перерыв панель тоже закрывается и показывает шамаиль-баннер.

Дашборд: поды на фоне ковра

Дашборд: поды на фоне ковра
Төеннәр: тамга как идентификаторы нод

Төеннәр: тамга как идентификаторы нод
Чайный перерыв в браузере: шамаиль-баннер

Чайный перерыв в браузере: шамаиль-баннер

13. Как проверяли

Тут начинается самое интересное — мы не поверили себе на слово и прогнали всё на реальном кластере CozyStack: изолированный тенант tncf, тенант-Kubernetes на Talos v1.13.6 / k8s v1.35.6 (2 ноды), отдельный kubeconfig, каждая команда с явным --context.

ayda — вся боевая матрица прошла на живом кластере:

Проверка

Факт (live)

exit

ayda күрсәт кузаклар/төеннәр

реальные поды/ноды + оформление в stderr

0

ayda kürsät kuzaklar (латиница)

идентично кириллице

0

ayda get pods (passthrough)

обычный kubectl

0

ayda сөйлә кузак yuk-pod

Error … NotFound + «Табылмады…»

1

RBAC: SA без прав

Error … Forbidden … cannot list pods + «Рөхсәт юк…»

1

FinOps: --replicas=12

реально масштабирует до 12 + «Акчаны әрәм итмә! 12 реплика…»

0

pipe-safety: … -o json | jq '.items|length'

4 (арт не попал в stdout)

0

AYDA_ALIF=latin/arab

латиница / RTL-арабица

0

ayda абырвалг

64

AYDA_FORCE_TEA=1 ayda …

экран чая

42

Латентность (медиана 5 прогонов): ayda 774 мс vs kubectl 812 мс. Накладные обёртки — в пределах шума (≈0, фактически −5%). То есть «национальный слой» не стоит вам производительности.

tos на настоящем Talos. Против managed-кластера cluster-операции упираются в hosted control-plane (worker-ноды не форвардят tenant-запросы — no request forwarding), поэтому мы подняли отдельную standalone Talos-ноду v1.11.2 и прогнали day-2 глаголы вживую:

  • tos вакыт → реальные NTP-данные; tos дисклар → диски; tos сәламәтлек → health;

  • tos яңадан-кабызреальный ребут ноды (actor ID, sequence START, нода ушла и вернулась);

  • tos татарнетес-конфиг → реальный рабочий kubeconfig 2270 байт (CA-data, server: https://10.244.76.195:6443, cluster tatarnetes). Хедлайн-фича доказана вживую.

А ещё боем поймали баг. tos күрсәт төеннәр мапился в talosctl get nodes — а у talosctl нет COSI-ресурса nodes (resource "nodes" is not registered), команда всегда падала. Починили: төен → members (cluster.Member), обновили словарь, help, доки и тесты. Это ровно то, ради чего гоняют боем — на моках такое не всплывает.

14. Грабли

Тут всё из кода самого проекта и с боевого прогона:

  • sed на macOS режет по байтам, а не по буквам. Кириллица/арабица — по 2 байта, и класс [Хх] в BSD sed матчит отдельные байты, кроша UTF-8. Из-за этого первая версия арабицы была битой; лечится подстановками по целой букве + проверкой по кодпоинтам.

  • Слишком жадный перевод переименовал чужой под. Под, буквально названный эш («работа»), команда превращала в get pods jobs. Починка: переводим только первый позиционный токен (тип ресурса), имена и значения флагов не трогаем.

  • bash 3.2 и кавычка-ёлочка «$verb» — многобайтная » «прилипает» к имени переменной; спасают фигурные скобки ${verb}. И printf "$fmt" с %s без аргумента молча съедает плейсхолдер.

  • [из боя] Talos apid отвергает client-cert без EKU clientAuth (tls: bad certificate). Самодельный O=os:admin cert из Talos-CA заработал только с extendedKeyUsage=clientAuth.

  • [из боя] managed CozyStack = hosted control-plane: worker-Talos не форвардят tenant-запросы; talosctl version идёт, а get/health/kubeconfig требуют standalone control-plane.

  • [из боя] talosctl get nodes не существует — см. выше, төен → members.

15. Итоги и как помочь

Готовность по итогам боевого прогона: ayda и UI — к публичному показу готовы сразу; tos — как обёртка готов, а для «живого» татарнетес-конфиг нужен standalone Talos control-plane (это особенность стенда, не баг).

git clone https://github.com/tatar-ncf/tatarnetes.gitcd tatarnetes && ./install.shayda ярдәм

Помочь просто и приятно:

  • перевести интерфейс — правишь locale/*.po, шлёшь PR (кода касаться не надо);

  • дополнить глоссарийdocs/terminology.tt.md (сейчас 36 терминов);

  • добавить строфу классика — обязательно с указанием источника.

Метрики проекта

Строк bash (ayda+tos+lib)

1936

Ключей локализации (tt.po)

39

Терминов в глоссарии

36

Юнит-проверок (tatarnetes / tataros)

28 / 12

Корпус (стихи / пословицы)

9 / 14

Систем письма

3 (кирилл / яңалиф / яңа имля)

Накладные ayda vs kubectl

≈0 (−5%)

Репозиториев

3

Галерея

Полный словарь команд

Полный словарь команд
Помощь на татарском

Помощь на татарском
Логи пода

Логи пода
Хезмәтләр (services)

Хезмәтләр (services)
Стих Тукая как гарнир

Стих Тукая как гарнир
Сәлам! Приветствие

Сәлам! Приветствие
tos: члены кластера (get members)

tos: члены кластера (get members)
tos help на английском

tos help на английском
UI: хезмәтләр

UI: хезмәтләр
UI: урнаштырулар

UI: урнаштырулар
UI: мәйданнар

UI: мәйданнар

Скринкасты (GIF): тур по консоли (живой прогон) · тур по UI.

Ссылки

Организация: github.com/tatar-ncf — Tatar-Native Computing Foundation

Репозитории:

Полезное:

Йомгак

Мы сделали это, потому что туган тел заслуживает жить и в терминале. Технологии не обязаны быть холодными: пусть кластер носит түбәтәй, угощает чәкчәком и уходит на чай — но при этом честно переводит ошибки, не тормозит и переживает боевой прогон. Всё — под Tatarch 2.0, всё — бөек татар халкына, всему великому татарскому народу и татарам всего мира.

Рәхмәт яугыры! Татарстан алга! Яшә, ирекле код! 🟢⚪🔴

ссылка на оригинал статьи https://habr.com/ru/articles/1084230/