Как снова загрузить параметры конфигурации после запуска службы

#c# #.net #microservices #azure-aks #azure-secrets

#c# #.net #микросервисы #azure-акс #azure-секреты

Вопрос:

Мое приложение размещено в AKS, секреты хранятся в хранилище Azure secrets. То, что есть у моего клиента, — это созданный том, в котором хранится /mnt/secrets-store этот каталог, содержащий все секреты для моего приложения.

Например:

  • RabbitMQ—Пароль
  • DB—ConnectionString

По-видимому, это стандартная практика для моего текущего клиента. Тогда решение состоит в том, чтобы читать файл каждый раз, когда они хотят загрузить настройки. Все это указано в диаграммах healm.

    volumeMounts:
        - name: secrets-store-inline
          mountPath: "/mnt/secrets-store"
          readOnly: true
        {{- end}}
 

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

Примечание: Моя служба не имеет прямого доступа к Azure key Vault, и это не то, что можно изменить. Все, к чему у меня есть доступ, — это эти файлы.

Что я сделал, так это создал пользовательский IConfigurationBuilder интерфейс под названием UseAzureKeyVaultMountedSecrets everything is very straight forward с этим. Он просто проверяет наличие папки, а затем загружает секреты, заменяя все, что есть в appsettings..json для этого ключа является именем.

   public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .UseAzureKeyVaultMountedSecrets()
                .UseSerilog((context, config) => config.ReadFrom.Configuration((context.Configuration)))
                .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
 

Локально для тестирования я просто создал папку с файлами в ней, и это работает как шарм. Однако при размещении на AKS у меня начались проблемы. Мои проверки работоспособности показывают, что он может обнаружить mnt dir. Но он их не читает.

После довольно продолжительной отладки я обнаружил, что проблема заключается в том, что каталог mnt недоступен при запуске микросервиса в модуле. Это первое после запуска модуля, что он может получить доступ к каталогу mnt.

Есть ли решение для этого?

  • Как я могу заставить его уменьшить громкость перед запуском в AKS?
  • Можно ли снова загрузить настройки после запуска службы? Если это так. тогда мне интересно, мог бы я затем создать что-то вроде IHostedService, который просто продолжал бы пытаться получить к нему доступ, а затем остановиться, как только он их захватил.

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

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

1. Ваша служба вообще может быть запущена без секретов? Если нет, я бы посоветовал UseAzureKeyVaultMountedSecrets может просто остановиться на некоторое время, пока не появится mnt. Например, сделайте задержку до ~ 30 секунд или около того

2. Поправьте меня, если я ошибаюсь, для этого потребуется, чтобы мои службы имели прямое подключение к Azure Key vault. Мой клиент отказался от этой опции, моя служба не может иметь прямой связи с Azure key vault. (все государственные данные жестко заблокированы.)

3. почему? проверьте, есть ли mnt, если нет, подождите

4. Насколько я знаю, вы не можете установить ожидание в program.cs. Модуль не завершит загрузку. Сначала появляется, когда модуль завершает загрузку, что каталог mnt существует. У меня есть add logging, который показывает это.

5. Также просмотры используются в startup.cs для настройки нескольких одиночек. Если я хочу, пока после завершения запуска не будет поздно.

Ответ №1:

@christian-sauer прав, я считаю, что ваша «проблема» заключается в том, что для отображения этих «виртуальных» файлов требуется некоторое время, поскольку они отображаются из Azure Vault. т. е. монтирование завершено, и поэтому инициализация pod продолжается, но для отображения файлов требуется время, пока проецируются секреты.

Поэтому вам нужно заставить свое приложение подождать, пока они появятся. Я не совсем понимаю, что вы подразумеваете под «Модуль не завершит загрузку». Все будет хорошо. Просто ваш процесс будет выполнять небольшую дополнительную работу во время запуска.

Итак, просто добавьте небольшой цикл, который проверяет наличие файлов в этой папке, а затем продолжайте. Потребуется немного усилий, чтобы сделать его надежным, и вам нужно будет поэкспериментировать и понаблюдать, как выглядят эти файлы. т.е. все ли они появляются сразу? Или они появляются с течением времени? Может быть, вы пересчитываете файлы, ждете, пересчитываете еще раз. Если счетчик стабилен в течение некоторого периода времени (500 мс?), То разорвите цикл и продолжайте. Если это займет слишком много времени (10 секунд, 30 секунд?), Тогда бросьте, и процесс (и модуль) завершится неудачей. Какое поведение является правильным.

Вы правы, думая о проверках работоспособности, но … конфигурация — сложная штука. Как вы уже указали, он должен быть доступен до того, как другие вещи могут быть загружены.

Возможно, используйте ConfigureHostConfiguration расширение IHostBuilder для выполнения цикла проверки файлов. Это достаточно рано, так что запуск блокируется до того, как что-либо ссылается на config. (Примечание: существует два этапа: конфигурация хоста; Конфигурация приложения).

Вы правы, это действительно блокирует процесс, пока проверка работает. Это совершенно нормально.


Для полноты картины… вы можете подумать об использовании IOptionsMonitor вместо (обновляет IConfiguration, когда базовый поставщик обнаруживает изменение. обновление файла ie). Кажется «хорошим», но…

  1. будет ли он обновлен к тому времени, когда он понадобится другим вашим частям? Возможно, вы сможете реорганизовать эти фрагменты, чтобы подключиться к измененному событию и повторно инициализировать себя. Здесь будут драконы.
  2. В k8s «файлы», которые вы читаете, часто являются символическими ссылками. SystemFileWatcher не будет перехватывать изменения, поскольку атрибуты символьных ссылок не изменяются, только данные, на которые они указывают.

Итак, KISS, просто заблокируйте процесс, пока не появятся файлы

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

1. Мой клиентский разработчик сказал, что mnt недоступен до полного запуска приложения. Возможно, стоит попробовать, спасибо за совет 🙂 Это также должно быть довольно легко добавить.

2. хммм, это было бы необычно (по моему опыту). Монтирование происходит до запуска контейнера. Вопрос: как k8s узнает, что процесс «полностью запущен»? как он узнает, когда вся начальная загрузка «завершена»; когда все IHostedServices запущены? Сначала добавьте небольшую консоль «logging» в Main. Проверьте, существует ли папка / монтирование, перечислите файлы. Добавьте таймер, который повторяет это, чтобы видеть, когда появляются файлы.

3. kubernetes.io/docs/concepts/storage/volumes в разделе «Фон» «Процесс в контейнере видит представление файловой системы, составленное из исходного содержимого образа контейнера, плюс тома (если они определены), установленные внутри контейнера».

4. Проверьте, существует ли папка / монтирование, перечислите файлы. <— я на самом деле добавил пользовательские показатели для Prometheus. Как только это появится, я смогу увидеть каталог. Но по мере того, как он загружает мои журналы, его там нет. Сейчас добавляю таймер, но я не могу отложить его до утра.

5. Я ненавижу, когда они это делают: (Я почти уверен, что volumeMounts монтируются до вызова ENTRYPOINT / CMD вашего контейнера (согласно этой ссылке на документ). Я думаю, что специалист по «devops» немного запутался. Наименее спорным способом доказать это будет поставить ведение журнала консоли на первое место в Main.