Перезапускать модули при обновлении configmap в Kubernetes?

Я знаю, что говорили о возможности автоматического перезапуска модулей при изменении конфигурации карты, но, насколько мне известно, это еще не доступно в Kubernetes 1.2.

Так что (я думаю) я хотел бы сделать, это "повторный перезапуск" ресурса развертывания, связанного с модулями, потребляющими карту конфигурации. Возможно ли, и если да, то как принудительно запустить повторный запуск развертывания в Kubernetes, не меняя ничего в реальном шаблоне? В настоящее время это лучший способ сделать это или есть лучший вариант?

13 ответов

Решение

Сигнализация модуля при обновлении карты конфигурации - это функция, которая находится в разработке ( https://github.com/kubernetes/kubernetes/issues/22368).

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

Вы также можете, например: смонтировать одну и ту же карту конфигурации в 2 контейнерах, выставить проверку работоспособности http во втором контейнере, которая завершится неудачно, если хеш содержимого карты конфигурации изменится, и указать это как пробу жизнеспособности первого контейнера (поскольку контейнеры в Pod совместно используют одно и то же пространство имен сети). Kubelet перезапустит ваш первый контейнер для вас при сбое датчика.

Конечно, если вам не важно, на каких узлах находятся модули, вы можете просто удалить их, и контроллер репликации "перезапустит" их за вас.

В настоящее время лучшее решение этой проблемы (на которое есть глубокие ссылки в https://github.com/kubernetes/kubernetes/issues/22368 ссылка на который есть в ответе одного из братьев и сестер) - это использовать Deployments и считать ваши ConfigMaps неизменяемыми.

Если вы хотите изменить свою конфигурацию, создайте новую ConfigMap с изменениями, которые вы хотите внести, и направьте свое развертывание на новую ConfigMap. Если новый конфиг будет поврежден, Развертывание откажется уменьшать ваш рабочий ReplicaSet. Если новый конфиг работает, то ваш старый ReplicaSet будет масштабирован до 0 реплик и удален, а новые модули будут запущены с новым конфигом.

Не так быстро, как просто редактирование ConfigMap на месте, но гораздо безопаснее.

Лучший способ сделать это - запустить Reloader.

https://github.com/stakater/Reloader

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

У вас есть размещение foo и ConfigMap называется foo-configmap, Вы хотите катить стручки развертывания каждый раз, когда изменяется конфигурация. Вам нужно запустить Reloader с:

kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml

Затем укажите эту аннотацию в своем развертывании:

kind: Deployment
metadata:
  annotations:
    configmap.reloader.stakater.com/reload: "foo-configmap"
  name: foo
...

https://github.com/kubernetes/helm/blob/master/docs/charts_tips_and_tricks.md#user-content-automatically-roll-deployments-when-configmaps-or-secrets-change

Часто файлы конфигурации или секреты вводятся в виде файлов конфигурации в контейнеры. В зависимости от приложения может потребоваться перезагрузка, если они будут обновлены с последующим helm upgrade, но если сама спецификация развертывания не изменилась, приложение продолжает работать со старой конфигурацией, что приводит к несогласованному развертыванию.

sha256sum Функция может использоваться вместе с include функция, обеспечивающая обновление раздела шаблона развертывания при изменении другой спецификации:

kind: Deployment
spec:
  template:
    metadata:
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
[...]

В моем случае по ряду причин $.Template.BasePath не работал, но $.Chart.Name делает:

spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: admin-app
      annotations:
        checksum/config: {{ include (print $.Chart.Name "/templates/" $.Chart.Name "-configmap.yaml") . | sha256sum }}

Если k8> 1,15; затем перезапуск развертывания сработал для меня лучше всего как часть CI / CD с путем подключения пути конфигурации приложения с помощью монтирования тома. Плагин или настройка перезагрузчика restartPolicy: Alwaysв манифесте развертывания YML у меня не работал. Никаких изменений кода приложения не требуется, работает как для статических ресурсов, так и для микросервиса.

      kubectl rollout restart deployment/<deploymentName> -n <namespace> 

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

например:

metadata:
  labels:
    configmap-version: 1

Была эта проблема, когда развертывание было на поддиаграмме, а значения, контролирующие его, были в файле значений родительской диаграммы. Вот что мы использовали для запуска перезапуска:

spec:
  template:
    metadata:
      annotations:
        checksum/config: {{ tpl (toYaml .Values) . | sha256sum }}

Очевидно, это вызовет перезапуск при любом изменении значения, но в нашей ситуации это работает. То, что изначально было в дочерней диаграмме, будет работать, только если config.yaml в самой дочерней диаграмме изменится:

    checksum/config: {{ include (print $.Template.BasePath "/config.yaml") . | sha256sum }}

Рассмотрите возможность использования (или kubectl apply -k), а затем использовать его мощные configMapGeneratorхарактерная черта. Например, из: https://kubectl.docs.kubernetes.io/references/kustomize/kustomization/configmapgenerator/

      apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

# Just one example of many...
- name: my-app-config
  literals:
  - JAVA_HOME=/opt/java/jdk
  - JAVA_TOOL_OPTIONS=-agentlib:hprof

  # Explanation below...
  - SECRETS_VERSION=1

Затем просто укажите в своих развертываниях. При сборке с помощью он автоматически найдет и обновит ссылки на my-app-config с обновленным суффиксом, например my-app-config-f7mm6mhf59.

Бонус, обновление секретов: я также использую эту технику для принудительной перезагрузки секретов (поскольку они действуют одинаково). Хотя лично я управляю своими секретами полностью отдельно (используя Mozilla sops), вы можете связать карту конфигурации вместе со своими секретами, например, в вашем развертывании :

      # ...
spec:
  template:
    spec:
      containers:
        - name: my-app
          image: my-app:tag
          envFrom:
            # For any NON-secret environment variables. Name is automatically updated by Kustomize
            - configMapRef:
                name: my-app-config

            # Defined separately OUTSIDE of Kustomize. Just modify SECRETS_VERSION=[number] in the my-app-config ConfigMap
            # to trigger an update in both the config as well as the secrets (since the pod will get restarted).
            - secretRef:
                name: my-app-secrets

Затем просто добавьте переменную, как в свою ConfigMap, как я сделал выше. Затем каждый раз, когда вы меняете my-app-secrets, просто увеличьте значение SECRETS_VERSION, который не служит никакой другой цели, кроме как вызвать изменение в kustomize'd Имя ConfigMap, что также должно привести к перезапуску вашего модуля. Итак, это становится:

Как автоматически перезапускать модули Kubernetes и модули, связанные с развертыванием, при изменении/обновлении их карты конфигурации?

Если вы используете configmap в качестве среды, вы должны использовать внешнюю опцию.

Kubernetes автоматически перезагружает карту конфигурации , если она смонтирована как том (если есть подпуть, она не будет работать с этим).

Когда ConfigMap, используемый в данный момент в томе, обновляется, спроецированные ключи также в конечном итоге обновляются. kubelet проверяет актуальность смонтированного ConfigMap при каждой периодической синхронизации. Однако kubelet использует свой локальный кеш для получения текущего значения ConfigMap. Тип кэша настраивается с помощью поля ConfigMapAndSecretChangeDetectionStrategy в структуре KubeletConfiguration. ConfigMap можно распространять с помощью часов (по умолчанию), на основе ttl или путем перенаправления всех запросов непосредственно на сервер API. В результате общая задержка с момента обновления ConfigMap до момента проецирования новых ключей в Pod может составлять период синхронизации kubelet + задержка распространения кеша, где задержка распространения кеша зависит от выбранного кеша. тип (соответствует задержке распространения часов, ttl кеша,

Официальный документ: https://kubernetes.io/docs/concepts/configuration/configmap/#mounted-configmaps-are-updated-automatically

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

Простой пример Configmap

      apiVersion: v1
kind: ConfigMap
metadata:
  name: config
  namespace: default
data:
  foo: bar

Конфигурация POD

      spec:
  containers:
  - name: configmaptestapp
    image: <Image>
    volumeMounts:
    - mountPath: /config
      name: configmap-data-volume
    ports:
    - containerPort: 8080
  volumes:
    - name: configmap-data-volume
      configMap:
        name: config

Пример: https://medium.com/@harsh.manvar111/update-configmap-without-restarting-pod-56801dce3388 .

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

Вот мои 20 центов:

  • Ответ с использованием меток, упомянутых , не будет работать, если вы обновляете метки. Но будет работать, если вы всегда добавляете ярлыки. Подробнее здесьздесь .

  • Упомянутый ответ, на мой здесьвзгляд, является наиболее элегантным способом сделать это быстро, но при этом возникла проблема с обработкой удалений. Я добавляю к этому ответу:

Решение

Я делаю это в одном из операторов Kubernetes, где в одном цикле согласования выполняется только одна задача.

  • Вычислить хэш данных карты конфигурации. Скажите, что это приходит как v2.
  • Создайте ConfigMap с метками: и, если он не существует, и ВОЗВРАТ. Если он существует, ПЕРЕЙДИТЕ НИЖЕ.
  • Найдите все развертывания, которые имеют метку, но не имеют. Если такие развертывания обнаружены, УДАЛИТЕ их и ВОЗВРАТ. ИНАЧЕ ПЕРЕЙДИТЕ НИЖЕ.
  • Удалите все ConfigMap с меткой, но без ELSE GO НИЖЕ.
  • Создать развертывание deployment-v2 с этикетками product: prime и version: v2 и имея конфигурационную карту, прикрепленную как cm-v2 и RETURN, ELSE ничего не делать.

Вот и все! Это выглядит длинным, но это может быть самая быстрая реализация и, в принципе, с обработкой инфраструктуры как крупного рогатого скота (неизменяемость).

Кроме того, указанное выше решение работает, когда в вашем развертывании Kubernetes есть стратегия обновления Recreate . Логика может потребовать небольших настроек для других сценариев.

Добавление неизменяемого свойства в конфигурационную карту полностью позволяет избежать этой проблемы. Использование хеширования конфигурации помогает в непрерывном обновлении, но не помогает при откате. Вы можете взглянуть на этот проект с открытым исходным кодом - «Конфигуратор» - https://github.com/gopaddle-io/configurator.git. « Конфигуратор» работает следующим образом с использованием настраиваемых ресурсов:

  1. Конфигуратор связывает жизненный цикл развертывания с configMap. Когда конфигурационная карта обновляется, для нее создается новая версия. Все развертывания, которые были прикреплены к configMap, получают непрерывное обновление с привязанной к нему последней версией configMap.

  2. Когда вы откатываете развертывание до более старой версии, оно возвращается к версии configMap, которая была до выполнения скользящего обновления.

Таким образом, вы можете поддерживать версии карты конфигурации и упростить откат и откат к вашему развертыванию вместе с картой конфигурации.

Вероятно, это не в стиле Kubernetes, но у меня работает — используйте inotifywait в отдельном потоке изнутри контейнера, чтобы просмотреть каталог конфимапа:

inotifywait --recursive --event attrib /opt/config

Другой способ - вставить его в командный раздел Deployment:

...
command: [ "echo", "
  option = value\n
  other_option = value\n
" ]
...

В качестве альтернативы, чтобы сделать его более похожим на ConfigMap, используйте дополнительное развертывание, которое будет просто размещать эту конфигурацию в command раздел и выполнить kubectl create добавив к его имени уникальную "версию" (например, вычисление хеша содержимого) и изменив все развертывания, использующие эту конфигурацию:

...
command: [ "/usr/sbin/kubectl-apply-config.sh", "
  option = value\n
  other_option = value\n
" ]
...

Я пожалуй выложу kubectl-apply-config.sh если это в конечном итоге работает.

(не делай этого; это выглядит слишком плохо)

Другие вопросы по тегам