Перезапускать модули при обновлении 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
...
Часто файлы конфигурации или секреты вводятся в виде файлов конфигурации в контейнеры. В зависимости от приложения может потребоваться перезагрузка, если они будут обновлены с последующим 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. « Конфигуратор» работает следующим образом с использованием настраиваемых ресурсов:
Конфигуратор связывает жизненный цикл развертывания с configMap. Когда конфигурационная карта обновляется, для нее создается новая версия. Все развертывания, которые были прикреплены к configMap, получают непрерывное обновление с привязанной к нему последней версией configMap.
Когда вы откатываете развертывание до более старой версии, оно возвращается к версии 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
если это в конечном итоге работает.
(не делай этого; это выглядит слишком плохо)