company_banner

shell-operator v1.0.0: долгожданный релиз нашего проекта для Kubernetes-операторов

    Open Source-проект shell-operator был создан с целью упростить создание полноценных Kubernetes-операторов и представлен нами два года назад. За минувшее время он прошёл длинный путь, оброс интересными функциями и, как мы уже недавно писали, созрел для использования в production*.

    Несмотря на это, его версия, долгое время «блуждавшая» в диапазоне бета- и RC-релизов будущей v1.0.0, вносила смуту для сторонних наблюдателей (и пользователей). С этим финальным релизом shell-operator мы ликвидируем это недоразумение, ещё более официально объявляя о зрелости проекта, а заодно — принеся в него новые возможности.

    * И даже более того: он (а точнее — его «старший брат», addon-operator) является одним из кирпичиков для нашей внутренней Kubernetes-платформы Deckhouse, которая станет доступной публично уже в мае.

    Для знакомства с тем, как устроен shell-operator и как с ним работать, рекомендуем доклад на KubeCon EU’2020, а эта статья сфокусирована только на последних новшествах (с момента нашей январской публикации).

    Главные изменения в v1.0.0

    Релиз v1.0.0 не стал формальным событием для проекта shell-operator. Он также принёс весьма значимые обновления, которыми уже сегодня можно воспользоваться.

    Object Patcher Framework

    Мы пишем много хуков для shell-operator (и addon-operator) и давно столкнулись с тем, что побочные эффекты в хуках усложняют тестирование и мешают восприятию логики работы хука.

    Чтобы получить хуки без побочных эффектов — «чистые хуки», которые взаимодействуют только с shell-operator, — мы начали с устранения вызовов kubectl.

    Для замены «читающим» вызовам kubectl в shell-operator появились настройки includeSnapshotsFrom и group, а результат работы выражения jqFilter доступен в объектах в binding context — таким образом можно получать нужные объекты из кластера через файл и использовать их в работе хука. Эти возможности были добавлены в версию beta.6 и уже с тех пор мы пишем хуки без «читающих» вызовов kubectl.

    Вторую часть — замену «пишущим» вызовам kubectl — мы реализовали как внутреннюю библиотеку и пожили с ней какое-то время. И вот в версии v1.0.0 появился так называемый Object Patcher Framework. Он представляет возможность вернуть из хука декларативный набор действий над объектами в кластере.

    Как это работает? Допустим, хук создаёт сертификат и помещает его в секрет. Это можно сделать таким вызовом kubectl:

    cat <<EOF | kubectl -n default apply -f -
    apiVersion: v1
    kind: Secret
    metadata:
      name: certs
    type: kubernetes.io/tls    
    data:
      tls.crt: |
        ${CERT}
      tls.key: |
        ${KEY}
    EOF

    Вроде не сложно, однако:

    • хорошо бы проверить, что такого секрета не существует, а если существует, то обновить его ключи;

    • написать тест для такого хука сложно, т.к. нужен кластер и проверка состояния кластера после работы хука. Либо нужно подменить kubectl на что-то управляемое из тестов.

    Как эти задачи решает Object Patcher Framework? Согласно документации, чтобы заменить такой вызов kubectl, нужно записать в файл $KUBERNETES_PATCH_PATH действие с операцией CreateOrUpdate

    cat <<EOF > $KUBERNETES_PATCH_PATH
    ---
    operation: CreateOrUpdate
    object:
      apiVersion: v1
      kind: Secret
      metadata:
        name: certs
        namespace: default
      type: kubernetes.io/tls    
      data:
        tls.crt: |
          ${CERT}
        tls.key: |
          ${KEY}
    EOF

    Теперь shell-operator попытается создать секрет, а если секрет уже существует, то обновит его. И тестировать хук стало проще: в тесте достаточно проверить содержимое файла $KUBERNETES_PATCH_PATH.

    Подытоживая это краткое описание Object Patcher Framework, можно сказать, что начиная с shell-operator v1.0.0 хуки можно разрабатывать без вызовов kubectl (и даже убрать этот файл из образа!).

    Бонус

    А если вы любите jq так же, как и мы, то вам точно понравится операция JQPatch.

    Замедление запуска хуков

    У хуков появились настройки, позволяющие замедлять их запуск, чтобы «накопить» события в очереди. Это нужно в тех случаях, когда хук умеет обрабатывать актуальное состояние набора объектов за один вызов, а запускать его на каждое изменение накладно. Если изменения приходят слишком часто, то очередь забивается и одно из решений — ограничить частоту запуска такого хука.

    Пример конфигурации:

    cat <<EOF
    configVersion: v1
    settings:
      executionMinInterval: 5s
      executionBurst: 2
    kubernetes:
    - name: pods
      kind: Pod
      group: pods
    EOF

    Такой хук будет запускаться раз в 5 секунд, позволяя хуку выполняться два раза без задержек. Обратите внимание, что в подписке указана group: с этим параметром в хук будет передан один binding context с актуальными объектами. Без group в хук попадёт массив binding context’ов с промежуточными изменениями за 5 секунд и ускорить хук не получится. Подробнее о group можно прочитать в документации.

    Актуальные объекты для Synchronization

    shell-operator при старте начинает следить за изменениями в Kubernetes-объектах и запускает хук, передавая ему список существующих объектов на момент запуска. Мы назвали такой первый запуск Synchronization. Если во время работы хука случается ошибка, то он перезапускается, а в случае Synchronization происходила ошибка: хук на каждый такой перезапуск получал всё тот же набор объектов, что был при первом запуске, несмотря на изменения в кластере.

    Другие изменения

    • для Object Patcher Framework создаётся отдельный Kubernetes client и для него можно настроить таймаут и замедление (--object-patcher-kube-client-timeout, --object-patcher-kube-client-qps, --object-patcher-kube-client-burst);

    • актуализирована документация про group;

    • добавлен флаг для включения отладочной информации от Kubernetes client.

    Что дальше? configVersion: v2

    Мы видим, что конфигурация хуков в shell-operator усложнилась, появилось много дополнительных рычагов и крутилок: executeHookOnEvent и executeHookOnSynchronization, includeSnapshotsFrom и group, keepFullObjectsInMemory, queue (и его отсутствие), а ещё есть waitForSynchronization… И эти настройки не нужны по отдельности, а только определённые наборы их значений, чтобы установить нужный режим подписки.

    Поэтому мы создали milestone v2 в addon-operator и приглашаем вас дать обратную связь о сложностях в работе (и с shell-operator, и с addon-operator) — можно здесь в комментариях, а можно через issue на GitHub или через Telegram-чат.

    P.S.

    Читайте также в нашем блоге:

    Флант
    DevOps-as-a-Service, Kubernetes, обслуживание 24×7

    Комментарии 1

      +1

      Круто! Поздравляю с релизом!


      PS: Если кто-то ищет способы писать операторы именно на Python, то можете также глянуть https://github.com/nolar/kopf (ворую внимание ;-) ).

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

      Самое читаемое