terraform-provider-yandex
terraform-provider-yandex copied to clipboard
Работа с yandex_mdb_postgresql_cluster, вопросы и предложения по работе с ресурсом провайдера
Приветствую!
Мы сейчас активно стараемся вести управление инфраструктурой в Я.Облаке с помощью терраформа и переносить разнообразные костыли и велосипеды, которые придумывали ранее для появляющихся ресурсов в провайдере.
Один из активно сейчас используемых ресурсов в провайдере терраформа у нас сейчас это PostgreSQL кластер. И сейчас мы пытаемся его максимально использовать для управления разнообразными конфигурациями, которые у нас есть.
Возможно это только наша специфика использования и она не особо востребована, однако я решил поделиться. Вдруг и нам поможет :)
Общая суть в том, что у нас есть набор кластеров для проектов и в каждом кластере набор баз для этого проекта. Т.е.: проект1 - кластер1 - [база-приложения1, база-приложения2, ..., база-приложенияn] проект2 - кластер2 - [база-приложения21, база-приложения22, ..., база-приложения2n] и т.д.
Доступы к базам разграничены - на каждую базу свой пользователь.
Все по очень простой причине - много небольших микросервисов и даже минимальный кластер один сервис не загружает, чтобы для каждого приложения создавать отдельный кластер баз.
С чем я столкнулся и что хотелось бы починить, поменять(если возможно) или понять как предполагается использовать (может нам в подходе надо что-то изменить).
-
При импорте существующего кластера провайдер предлагает пересоздать всех пользователей и почти все базы. По этому поводу даже тикет в саппорте есть. При тестах выяснился любопытный ньюанс (про почти все базы) - базы без установленных расширений пересоздавать провайдер не предлагает. Если есть расширения, и даже если они указаны в описании, все равно настаивает на пересоздании.
-
Описывать кучу повторяющихся блоков довольно неудобно. К тому же когда неизвестно сколько их может быть - это про user/database/permission/extension блоки. Тут очень хочется использовать конструкцию dynamic блоков из терраформа. И вынести создание базы в отдельный модуль, например, с доп. ресурсами необходимыми. Однако я столкнулся с проблемой, когда описываю ресурс используе dynamic блоки, то провайдер предлагает каждый раз пересоздавать все ресурсы - и базы и пользователей (все, что разворачивается из dynamic). Что крайне странно и непонятно. При любом изменении или не изменении ресурса.
-
Оставили идею использования dynamic когда-нибудь в будущем и описали всех пользователей и базы в одном большом ресурсе. И тут все равно возникла проблема - при изменении расширений базы в блоке database -> extension провайдер хочет пересоздать базу. Т.е. удалить и создать новую, хотя эта операция не столь радикальна и расширения ставятся/убираются из консоли/командной строки/базы без таких методов.
-
Не хватает большей информации о создаваемых ресурсах (IP адреса хостов кластера или возможности их получить из какой-либо даты). Непосредственно IP адреса нужны например для конфигурирования провайдера postgres. По хосту он не работает. Вообще с postres провайдером есть свои особенности из-за того, что он проверяет все подключения еще на этапе plan. И все пользователи и доступы должны быть созданы до его использования. В свою очередь постгрес провайдер нужен для очень многих вещей - от выдачи прав в базе для пользователя (например на чтение), до изменения конфигурации базы/пользователей которые есть в веб-консоли/апи, но которые нельзя указать через яндекс терраформ провайдер.
-
Про пользователей. Вопрос в целом описан в #78 и вызван способом нашего использования баз и доступов. При наличии большого количества небольших баз и пользователей дефолтные значения того же connection limit не подходят. Однако указать их сейчас нет возможности и какие-то базовые параметры для пользователей тоже указать нет возможности (хотя для баз локаль хотя бы есть :) ) Можно делать многоходовку - создавая пользователя провайдером Я.Облака, а потом провайдером postgres конфигурировать, если бы не несколько ньюансов. Например, если пользователей уже очень много с лимитами по 10-15 коннектов и, к примеру, осталось 20-30 свободных коннектов в базе - пользователя уже не получится автоматически сиздать. Надо будет либо менять пользователей, уменьшая им пул подключений (что чревато), а потом создавать пользователя и все обратно откатывать. Либо создавать пользователя руками а потом.... а потом его невозможно импортировать в терраформе.
-
Про создание пользователей. Так же довольно нетривиально создавая пользователей указывать им пароли - никто не хочет их в коде хранить, хотелось бы их генерировать извне и отдавать при создании пользователя.
-
Еще про пользователей и их пароли. Очень странно выглядит работа с пользователями, если им менять пароль (или импортировать базу и потом прогнать plan) - провайдер предлагает каждый раз пересоздавать пользователя. При любом изменении. Что тоже не очень хорошо и, возможно, было бы все равно (это как с секретами волта, там терраформ ничего о состоянии секретов не знает и каждый раз их пересоздает), если бы не вероятность потерать все настройки для пользователя из-за удаления и пересоздания. А это означает потери как настроек со стороны managed баз, так и внутри, которые делались postgres провайдером.
Часть из описанного выше - технические ошибки, которые (я надеюсь) поправят. Другая часть - не ошибки, а относятся к концепции управления пользователями, базами и кластером у вас в облаке. И если с ошибками можно только ждать исправления, то с концепциями я кощунственно предлагаю пересмотреть и всех поделить :)
У вас даже в API (по документации ) ресурсы/объекты кластер БД, база данных и пользователь разделены и могут использоваться достаточно независимо. Я, когда городил прошлым летом свой велосипед для создания баз при помощи терраформа, использовал эту идею как основную - отдельно описывается кластер, отдельно пользователь, отдельно база и все их нужные мне параметры.
Так может быть имеет смысл разделить их и у вас в провайдере?
Сделать их отдельными ресурсами postgres_cluster, postgres_user, postgres_database. Тогда (возможно) будет проще добавить тот функционал коотрый сейчас есть в api/веб-консоли/командной строке отдельно для каждого из этих ресурсов, их отдельно можно настраивать. Их так же по отдельности или все вместе можно вынести будет в модуль(и) (если захочется все одним блоком описать).
Привет @asterix201,
Проблемы из п1, п3, п5, п7 похоже имеют одну причину - баг в сравнении состояний, из-за этого Terraform и пытается пересоздать сущности. Добавили в бэклог следуюшего спринта.
п4: IP адрес не планируем добавлять в output так как:
- пользователи могут по ошибке завязываться на IP адреса, тем самым провоцируя потерю возможности подключиться при их смене;
- IP адреса отсутствуют в публичной спецификации, а Terraform провайдер основан на ней.
Использования провайдера PostgreSQL (не Managed PostgreSQL) в случае многохостовых кластеров осложняется тем, что в output нет информации о том какой из хостов сейчас мастер, чтобы там через SQL что-то изменить. Кроме того интерфейс PostgreSQL и API Облака могут иметь совершенно разные сетевые доступы, что может запутать пользователей.
п6. Для того, чтобы не хранить в коде пароль можно воспользоватьcя random
провайдером, пример как это сделать для нескольких пользователей можно посмотреть тут.
Настройки пользователей мы конечно собираемся добавить, но пока не можем точно назвать сроки. На счет разделения на ресурсы есть определенные сомнения, так как это увеличит итоговую сложность кода и провайдера, и модулей пользователей, где основной случай 1-3 базы и столько же пользователей.
@asalimonov, спасибо за ответ!
Про IP адрес - я согласен, что его отдавать это совсем не лучшая идея, мы подобные запросы про IP адреса сервисов у себя пресекаем, чтобы пользовались именами. Однако я, пока, не могу придумать еще решения (коме как руками такие запросы делать).
Я столкнулся с необходимостью получить адрес когда потребовалось сделать вполне обычное, хоть и не частое, действие - создать пользователя и выдать ему права для доступа к уже имеющейся базы со своим владельцем. Собственно, чтобы раздать необходимые гранты на базу для отдельного пользователя, согласно документации, нужно уже лезть в базу и в базе выдавать необходимые права.
Чтобы это автоматизировать можно использовать провайдер PostgreSQL. И вот тут начинаются танцы с бубном:
- с одной стороны этот провайдер (PostgreSQL) не умеет ходить в кластеры баз по имени хоста/cname, только IP адрес;
- для PostgreSQL нужен именно мастер для изменений, который может меняться/переезжать;
- с другой стороны есть ограничения Я.Облака, такое как split-view DNS, когда находясь в одной сети я не могу зарезолвить имя в адрес в другой сети.
С последним была довольно интересная идея использовать DNS Provider, чтобы им получать IP мастера и дальше уже применять настройки. Но не получилось - CI/CD живут в отдельной от других сред сети (да и разные среды выполнения в разных сетях).
Может быть есть возможность в API облака, или сам сервис добавить возможность выдачи дополнительных прав пользователю (помимо CONNECT)?
С примером - спасибо большое!
Я пробовал через count делать и получалось "не очень".
Я бы в примеры предложил добавить - хорошо получается :) Там сейчас при нескольких пользователях один и тот же пароль получаться будет, если генерировать random_password
ом.
Есть еще вопрос.
Возможно ли провайдером отдавать cname? Я знаю, что он составляется по описанию в документации как c-<cluster_id>.rw.mdb.yandexcloud.net , но может возможно уже полный cname получать про создании ресурса?
Я столкнулся с необходимостью получить адрес когда потребовалось сделать вполне обычное, хоть и не частое, действие - создать пользователя и выдать ему права для доступа к уже имеющейся базы со своим владельцем. Собственно, чтобы раздать необходимые гранты на базу для отдельного пользователя, согласно документации, нужно уже лезть в базу и в базе выдавать необходимые права.
Мы в курсе этой проблемы, пока думаем как сделать более удобное решение. Генерализованный вариант решения, в т.ч. вне контекста данного случая - прокидывать внутрь периметра задачи для некоего воркера, который имеет доступ к внутренним ресурсам.
С последним была довольно интересная идея использовать DNS Provider, чтобы им получать IP мастера и дальше уже применять настройки. Но не получилось - CI/CD живут в отдельной от других сред сети (да и разные среды выполнения в разных сетях).
Да, это ровно таже самая проблема.
Я бы в примеры предложил добавить - хорошо получается :) Там сейчас при нескольких пользователях один и тот же пароль получаться будет, если генерировать random_passwordом.
Ага, обновлю как-нибудь на днях.
Возможно ли провайдером отдавать cname? Я знаю, что он составляется по описанию в документации как c-<cluster_id>.rw.mdb.yandexcloud.net , но может возможно уже полный cname получать про создании ресурса?
На мой взгляд это избыточно. Конкатенация строк поддерживается в HCL, то есть можно самостоятельно сделать output с таким результатом.
Добавлю к стартовым пунктам про пересоздание. Тоже самое случается и при изменении блоков host. Если я правильно пониманию механику, то проблема в том, что в state набор хостов это просто массив объектов без каких либо "уникальных" идентификаторов по которым их можно сравнить с планом. В результате когда мы к примеру удаляем 1 из 3 хостов, то у нас просто 2 элемента нового плана сравниваются с 3мя элементами старого стейта, без учёта какого либо идентификатора(да и непонятно как их сравнивать то, если в subnet + zone будет несколько инстансов) И получается такая картинка
~ host {
assign_public_ip = false
fqdn = "rc1a-6hgfqeq80tozgzd.mdb.yandexcloud.net"
~ subnet_id = "e9bb0l6rolpms6g2m4sl" -> "e2l3rsvsc3q9l4dr4j8v"
~ zone = "ru-central1-a" -> "ru-central1-b"
}
~ host {
~ assign_public_ip = false -> true
fqdn = "rc1b-hyx7v9tbym3xefq.mdb.yandexcloud.net"
~ subnet_id = "e2l3rsvsc3q9l4dr4j8v" -> "b0cd4m938uvgqa2iqfg0"
~ zone = "ru-central1-b" -> "ru-central1-c"
}
- host {
- assign_public_ip = true -> null
- fqdn = "rc1c-7kmirtiks6d3fu2.mdb.yandexcloud.net" -> null
- subnet_id = "b0cd4m938uvgqa2iqfg0" -> null
- zone = "ru-central1-c" -> null
}
Будем рады если вы сможете найти решение или предложить какой то workaround.
any news?
Приветствую!
Есть хорошие новости. Добавили большой объём изменений (https://github.com/yandex-cloud/terraform-provider-yandex/blob/master/CHANGELOG.md)
Постараюсь по пунктам расписать в течении пары недель, как работать в том или ином случае, что отображается в дифе и что будет происходить в кластере.
п5 для пользователя теперь можно выставлять настройки ограничивающие количество подключений
Для пользователя теперь доступны следующие настройки:
-
conn_limit
- (Optional) The maximum number of connections per user. (Default 50) -
settings
- (Optional) Map of user settings
The settings
block supports:
Full description https://cloud.yandex.com/docs/managed-postgresql/grpc/user_service#UserSettings
-
default_transaction_isolation
- defines the default isolation level to be set for all new SQL transactions.- 0: "unspecified"
- 1: "read uncommitted"
- 2: "read committed"
- 3: "repeatable read"
- 4: "serializable"
-
lock_timeout
- The maximum time (in milliseconds) for any statement to wait for acquiring a lock on an table, index, row or other database object (default 0) -
log_min_duration_statement
- This setting controls logging of the duration of statements. (default -1 disables logging of the duration of statements.) -
synchronous_commit
- This setting defines whether DBMS will commit transaction in a synchronous way.- 0: "unspecified"
- 1: "on"
- 2: "off"
- 3: "local"
- 4: "remote write"
- 5: "remote apply"
-
temp_file_limit
- The maximum storage space size (in kilobytes) that a single process can use to create temporary files. -
log_statement
- This setting specifies which SQL statements should be logged (on the user level).- 0: "unspecified"
- 1: "none"
- 2: "ddl"
- 3: "mod"
- 4: "all"
@superbotan Я протестировал последнюю версию С хостами, при попытке удалить непоследний хост из списка, получаем следующего рода diff
~ host {
~ subnet_id = "e2l4u9j29cal2vo8i854" -> "b0cclpfber2u5dni60um"
~ zone = "ru-central1-b" -> "ru-central1-c"
# (4 unchanged attributes hidden)
}
- host {
- assign_public_ip = false -> null
- fqdn = "rc1c-gnl9r2xuxqt262cg.mdb.yandexcloud.net" -> null
- priority = 0 -> null
- role = "REPLICA" -> null
- subnet_id = "b0cclpfber2u5dni60um" -> null
- zone = "ru-central1-c" -> null
}
Тоесть ситуация особо не поменялась, НО на самом деле хост никуда не перемещается, а всё остаётся как и должно было, без лишних пересозданий.
Таже самая история с отображением стейтов для db/users. Только есть небольшое отличие. Для db также отображается что объекты будут перемещены, но всё остаётся на своих местах.
А вот пользователи (кажется) начинают переименовываться, в соответствии с тем, как это указано в стейте. В логе операций в веб интерфейсе мы видим записи вида Modify user in PostgreSQL cluster
К сожалению нет возможности на данный момент приводит ли это к каким то проблемам доступности,если сервис в этот момент работает, но полагаю что может быть.
@pcheliniy, Добрый день! по первому пункту из первого сообщения: При импорте существующего кластера провайдер предлагает пересоздать всех пользователей и почти все базы. По этому поводу даже тикет в саппорте есть. При тестах выяснился любопытный ньюанс (про почти все базы) - базы без установленных расширений пересоздавать провайдер не предлагает. Если есть расширения, и даже если они указаны в описании, все равно настаивает на пересоздании.
Тут фактически 3 проблемы:
- Порядок ресурсов приходящих из облака не совпадает с порядком описанным в tf файле. Так как в провайдере используются списки, а терраформ сравнивает для списков в том числе порядок, возникает отображение изменения. Оно исправляется либо применением, либо изменением порядка в tf файле. Применение изменения для БД и для Хостов согласно коду и моим экспериментам, не приводит к внесению изменений в облако. В состояние
terraform.tfstate
же будет записан верный порядок, не вызывающий diff в terraform. - Пароль пользователей. Пароли - секретная информация и она не возвращается из облака. По этому получив состояние из облака состояние будет с не заполненными паролями. Исправление: или применить изменение и тогда будет внесено изменение в облако (переопределится пароль на указанный в TF файле) или в файле
terraform.tfstate
, который отвечает за состояние, прописать пароли, например так:"password": "ezIH+bqYFbU!Yk\u0026o",
. - Сравнение изменений у пользователя. Наличие обновления у пользователя проверяется на основании того, видит ли terraform эти изменения или нет. Эту ситуацию мы с коллегами обсудим и решим, что с этим делать.
@superbotan А может стоит вынести описание БД и юзеров просто в отдельные ресурсы? и проблема по сутиуйдет (я про сортировку юзеров и бд). потому как, если есть скажем 20 юзеров и надо добавить юзера чье имя "по середине" - ну странно видеть дифф более чем добавление юзера. можно например оставить в ресурсе yandex_mdb_postgresql_cluster (если остальные mdb так же сортируют юзеров, то и в них соотвественно) - типо главная БД и главный юзер, а остальное отдельными ресурсами.
Вообщем за 3 часа я написал, то о чем говорил выше. Есть отдельно ресурс самой MDB, и есть ресурсы отдельно DB и ресурс User. имхо стало в разы удобнее, нежели чем держать все в одном ресурсе (особенно когда мы говорим когда более 10-20 баз и более 50 юзеров).
Добрый день! Для того, что бы вынести БД и пользователей в отдельные ресурсы, нужно написать альтернативный ресурс для кластера и новые ресурсы для БД и Пользователей. Дополнить текущую реализацию сложно, так как требуется соблюсти обратную совместимость. Если Вами уже проделана эта работа, то не могли бы Вы сделать пулреквест с изменениями.
@superbotan к сожалению, это выполнено в виде отдельного провайдера, да и гоха не мой язык программирования (поэтому с пуллреквестом это точно не ко мне:)). Я в течении дня выложу на гитхаб и закину сюда ссылку.
@superbotan - https://github.com/webbankir/terraform-provider-wbyandex
@suslovsergey , круто! Прям про, про что изначально спрашивал :)
@superbotan С учетом все расширяющихся свойств у пользователя и параметров баз - что теперь можно довольно много дополнительных параметров как у пользователя, так и у баз добавлять. И, как видно, использование в подобном виде кластеров это вполне востребованное решение, то может рассмотрите разделение?
С доп. параметрами для пользователей и баз (и то небольшими) в "монолитном" виде конфиг разрастается очень сильно.
Еще предложение: добавьте плз в документацию провайдера ссылку на конфиг https://cloud.yandex.com/en-ru/docs/managed-postgresql/grpc/cluster_service#ConfigSpec1 и/или в самой документации к атрибутам кроме их типа вписывать еще и юнит (например, autovacuum_naptime integer => autovacuum_naptime integer (milliseconds).
PS. По поводу того, что провайдер "меняет" пользователей/базы данных: есть вот такой манифест:
variable "postgres_databases" {
type = list(object({
db_name = string
db_pass = string
db_extensions = list(string)
lc_type = string
lc_collate = string
}))
}
...
dynamic "database" {
for_each = var.postgres_databases
content {
name = database.value.db_name
owner = database.value.db_name
lc_type = database.value.lc_type
lc_collate = database.value.lc_collate
dynamic "extension" {
for_each = database.value.db_extensions
content {
name = extension.value
}
}
}
}
dynamic "user" {
for_each = var.postgres_databases
content {
name = user.value.db_name
password = user.value.db_pass
login = true
permission {
database_name = user.value.db_name
}
}
}
dynamic "host" {
for_each = var.host_networks
content {
zone = host.value.zone
subnet_id = host.value.id
assign_public_ip = true
}
}
lifecycle {
# выключаем случайное удаление базы
prevent_destroy = true
# а также не "обращаем внимания" на изменения в юзерах и базах, т.к. их лучше создавать вручную, через веб-консоль
ignore_changes = [user, database]
}
Т.е. как и указано в комменте манифеста, в качестве workaround проблемы с динамическими пользователями/базами используется секция lifecycle/ignore_changes, а базы и пользователи создаются через веб-интерфейс. Благо, что базы редко добавляются/меняются и их всего пара десятков пока :-) Может кому-то пригодится такой способ :-)
@superbotan Есть ли новости по управлению пользователями/базами через отдельные ресурсы (у меня ровно такая же беда с MySQL-ресурсом сейчас)?
Кстати, действительно ли сломается обратная совместимость, если просто добавить новые типы ресурсов, но оставить основной ресурс (yandex_mdb_***
) без изменений? Пусть в нем остается возможность задать пользователей и БД через блоки, как сейчас - это вполне удобно для первоначального создания базы.
Список узлов кластера - это да, проблема. В теории, решается через labeled-блоки, но это сломает совместимость.
@apilikov проблема c изменением позиции хостов всё ещё воспроизводится и изрядно мешает. Any ETA?
Не могли бы выделить эту проблему в отдельный тикет? @k0t3n
@apilikov https://github.com/yandex-cloud/terraform-provider-yandex/issues/204
Привет! Мы таки вытащили database и user в отдельные ресурсы для PG и MySQL https://github.com/yandex-cloud/terraform-provider-yandex/blob/master/CHANGELOG.md
@suslovsergey @virtualshuric
@Denchick Огонь!