Создание современного REST API с помощью Go — часть 3

Эта статья является третьей в серии, в которой шаг за шагом описываются все аспекты реализации современного микросервиса REST API:

  1. Определение первой модели данных SQL с помощью sqlc
  2. Внедрение REST API с помощью Gin
  3. Настройка с помощью Viper
  4. Сборка и запуск в контейнере
  5. Контейнерные тесты

Весь код серии доступен по адресу:



Какой механизм конфигурации использовать?

Когда дело доходит до настройки приложения, существует множество вариантов. Вы можете использовать параметры командной строки, файл конфигурации, переменные среды, службы удаленной настройки (такие как etcd, консул и т. д.) или их комбинацию.

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

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

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

  • Файл конфигурации содержит все значения по умолчанию и встроен в двоичный файл go: вы не хотите ни открывать свой файл конфигурации, ни документировать его. Это деталь реализации; позже вы можете решить получить значения по умолчанию непосредственно из кода или получить их из службы удаленной настройки.
  • Любое значение может быть переопределено с помощью переменных среды: это ваш общедоступный механизм конфигурации, который должен быть задокументирован.

Это кажется большой работой, но, к счастью, для Go существует множество конфигурационных библиотек. Одной из самых известных библиотек является Viper, которая прекрасно справляется с нашим вариантом использования.

Реализация конфигурации

До сих пор мы следовали стандартной схеме для приложения Go, и структура нашего проекта выглядит следующим образом:

└── cmd
    └── microservice
        └── main.go

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

└── cmd
    └── microservice
        ├── config
        │   ├── config.go
        │   └── config.yml
        └── main.go

Определение нашей модели конфигурации

Нет, здесь мы не будем рассматривать подходы «сначала код, сначала конфигурация»! Единственное правило, которому вы должны следовать, — это разбивать конфигурацию на блоки, понятные пользователю. Для нашего примера приложения у нас есть только данные конфигурации для базы данных, поэтому наша конфигурация тривиальна:

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

Конфигурационный файл

Viper поддерживает множество форматов конфигурационных файлов. Мы собираемся использовать YAML для этого урока:

Как упоминалось ранее, файл конфигурации содержит все значения по умолчанию для нашего приложения.

Примечание о безопасности

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

В этом руководстве мы переопределяем конфигурацию с помощью переменных среды. Хотя это нормально для работы с локальным стеком, фактическое производственное развертывание с надежной защитой, скорее всего, будет опираться на инструмент управления секретами, такой как Hashicorp Vault в сочетании с секретами Kubernetes.

Встраивание файла конфигурации

Для встраивания нашего конфигурационного файла мы используем директиву //go:embed. Как следует из названия, он позволяет внедрить любой файл в бинарный файл go и использовать его как переменную во время выполнения:

Чтение конфигурации

Теперь мы можем прочитать нашу конфигурацию по умолчанию с помощью Viper:

  1. Мы включаем механизм переопределения переменных окружения,
  2. Мы читаем конфигурацию, используя ReadConfig: сначала будут считаны значения по умолчанию из встроенной конфигурации, а затем переопределены значениями, полученными из переменных среды, если они есть.
  3. Разместите результат в нашей модели конфигурации

Переопределение значений с использованием переменных среды

Переопределение конфигурации с использованием переменных среды работает путем определения переменной, имя которой является «путем» параметра в модели конфигурации:

параметр.для.переопределения → PREFIX_PARAMETER_TO_OVERRIDE

Например, если мы хотим переопределить значение postgres.password, мы определяем переменную среды APP_POSTGRES_PASSWORD, так как мы настроили префикс APP для нашего приложения.

Завершение

Теперь мы можем соответствующим образом обновить нашу основную функцию:

Что дальше?

Теперь, когда мы реализовали конфигурацию, мы рассмотрим как запустить сервер API в контейнере!