# Начало работы с Nubes Terraform Это руководство поможет вам установить инструменты, настроить доступ и развернуть вашу первую инфраструктуру в облаке Nubes, используя Terraform. ## 0. Установка Terraform Для работы с инфраструктурой как кодом (IaC) потребуется утилита Terraform (версии 1.0 или выше). 1. **Скачивание**: * Официальный сайт: [hashicorp.com/terraform/install](https://developer.hashicorp.com/terraform/install) * *Для пользователей из РФ (без VPN):* [Yandex Cloud Mirror](https://hashicorp-releases.yandexcloud.net/terraform/) 2. **Установка**: * Распакуйте скачанный архив. * Поместите исполняемый файл (`terraform` или `terraform.exe`) в папку, доступную в переменной окружения `PATH`. 3. **Проверка**: * Откройте терминал (PowerShell, CMD, Bash или Terminal в macOS). * Введите команду `terraform -version`. Вы должны увидеть номер версии. ## 1. Подготовка конфигурации Создайте рабочую директорию для вашего проекта и создайте основной файл конфигурации `main.tf`. ```hcl title="main.tf" terraform { required_providers { nubes = { source = "terra.k8c.ru/nubes/nubes" version = "2.1.23" # Поставьте нужную вам версию провайдера } } } provider "nubes" { api_endpoint = "https://deck-api.ngcloud.ru/api/v1/index.cfm" api_token = var.api_token } variable "api_token" { type = string sensitive = true } ``` !!! info "TEST стенд (обязательные адреса)" Эта документация относится к TEST стенду. - Личный кабинет: https://deck-test.ngcloud.ru/dashboard/ - API endpoint: https://deck-api-test.ngcloud.ru/api/v1 !!! tip "Безопасность" Никогда не храните токен прямо в файле `main.tf`, если планируете загружать код в систему контроля версий (git). Используйте `variables.tf` или файл `terraform.tfvars`. ## 2. Получение API токена Токен (Access Token) необходим провайдеру для авторизации ваших действий в облаке. Если нет ТОКЕНА доступа или хотите создать новый - В Личном Кабинете - на странице Профиля пользователя https://deck.ngcloud.ru/authorization/profile во вкладке Токены - нажать "Выпустить тех-токен" Значение токена показывается только при его создании, надо его сохранить Создайте файл `terraform.tfvars` и сохраните токен там: ```hcl title="terraform.tfvars" api_token = "eyJhbGciOiJ..." # Ваш длинный токен ``` ## 3. Описание ресурсов Добавьте ресурсы, которые вы хотите создать, в файл `main.tf` или `resources.tf`. Пример создания S3 бакета: ```hcl resource "nubes_s3bucket" "my_files" { resource_name = "bucket_0" bucket_name = "my-unique-bucket-name" s3_user_uid = "235e0546-..." # UID Корневой услуги S3 } ``` Или Postgres кластера: ```hcl resource "nubes_postgres" "db" { resource_name = "pg-tst0" resource_realm = "k8s-3.ext.nubes.ru" # Платформа развертывания s3_uid = "235e0546-..." # UUID услуги S3 для бэкапов resource_c_p_u = 2000 # 2 vCPU (в милликорах) resource_memory = 4096 # 4 GB (в МБ) resource_disk = "20" # 20 GB resource_instances = 1 } ``` Подробные примеры конфигураций смотрите в разделе **Resources** документации. ## 4. Запуск Теперь вы готовы применить конфигурацию: 1. **Инициализация**: `terraform init` (загружает плагин провайдера). 2. **План**: `terraform plan` (показывает, что будет сделано). 3. **Применение**: `terraform apply` (создает инфраструктуру). ## 5. Почему провайдер использует Suspend/Adopt Для этой логики используются два флага. - `suspend_on_destroy` - `adopt_existing_on_create` ### `suspend_on_destroy` - `true` (по умолчанию) - при `terraform destroy` инстанс уходит в `Suspend`; - при удалении ресурса из манифеста — тоже `Suspend`. - `false` - Terraform удаляет ресурс только из state; - в облаке инстанс не меняется. ### `adopt_existing_on_create` - `false` (по умолчанию) - если инстанс уже существует, Terraform вернёт ошибку. - `true` - Terraform может взять существующий инстанс под управление. ### Как это связано с `terraform import` Это похоже на `terraform import`, но срабатывает в обычном `apply`. - найден `running` → `adopt`; - найден `suspended` + обязательные параметры совпадают → `resume + adopt`. ### Важно Один инстанс должен быть только в одном state. Если подключить один инстанс к двум манифестам, получится конфликт управления: - первый `apply` меняет ресурс; - второй `apply` откатывает или перезаписывает изменения. --- Следующий шаг: изучите [Справочник по командам Terraform](terraform-basics.md) для уверенной работы. ## Примеры ### Lucee & Postgress Lucee и NodeJS — это два отдельных UI для CRUD‑операций, оба работают с одной и той же таблицей в Postgres. ```hcl title="resources.tf" resource "nubes_postgres" "db2" { # Основной Postgres-кластер для демо. resource_name = "pg-tst0" s3_uid = "235e0546-..." resource_realm = "k8s-3.ext.nubes.ru" # Платформа развертывания resource_instances = 1 resource_memory = 512 resource_c_p_u = 500 resource_disk = "1" app_version = "17" json_parameters = jsonencode({ # Выключаем подробные логи подключений в демо. log_connections = "off" log_disconnections = "off" }) enable_pg_pooler_master = false enable_pg_pooler_slave = false allow_no_s_s_l = false auto_scale = false auto_scale_percentage = 10 auto_scale_tech_window = 0 auto_scale_quota_gb = "1" need_external_address_master = false } resource "nubes_lucee" "app1" { # Lucee UI, который читает/пишет в Postgres. resource_name = "lucy1" resource_realm = nubes_postgres.db2.resource_realm domain = "web03" # Пример домена приложения git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testlucee.git" json_env = jsonencode({ # JDBC datasource для Lucee. testds_class = "org.postgresql.Driver" testds_bundleName = "org.postgresql.jdbc" testds_bundleVersion = "42.6.0" testds_connectionString = "jdbc:postgresql://${nubes_postgres.db2.state_out_flat["internalConnect.master"]}:5432/postgres" testds_username = nubes_postgres.db2.vault_secrets["adminUser"] testds_password = nubes_postgres.db2.vault_secrets["adminPass"] testds_connectionLimit = "5" testds_liveTimeout = "15" testds_validate = "false" }) resource_c_p_u = 300 resource_memory = 512 resource_instances = 1 app_version = "5.4" depends_on = [nubes_postgres.db2] } resource "nubes_nodejs" "app3" { # NodeJS демо, работающий с тем же Postgres. resource_name = "node_0" resource_realm = nubes_postgres.db2.resource_realm domain = "node" git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testnode.git" health_path = "/healthz" app_version = "23" json_env = jsonencode({ # Переменные подключения к Postgres. PGHOST = nubes_postgres.db2.state_out_flat["internalConnect.master"] PGPORT = "5432" PGUSER = nubes_postgres.db2.vault_secrets["adminUser"] PGPASSWORD = nubes_postgres.db2.vault_secrets["adminPass"] PGSSLMODE = "require" DATABASE_URL = format( "postgresql://%s:%s@%s:5432/postgres", nubes_postgres.db2.vault_secrets["adminUser"], nubes_postgres.db2.vault_secrets["adminPass"], nubes_postgres.db2.state_out_flat["internalConnect.master"] ) }) resource_c_p_u = 300 resource_memory = 256 resource_instances = 1 depends_on = [nubes_postgres.db2] } ``` ### Пример (PROD_STAND/RABBIT) Ниже полный пример `resources.tf` для RabbitMQ + Lucee UI + NodeJS воркера. Комментарий: UI Lucee отправляет CRUD‑запросы в RabbitMQ, а применение изменений в Postgres выполняет отдельный воркер на NodeJS. Сервис Postgres должен быть запущен заранее. В данном примере используется Postgres из раздела https://terra.k8c.ru/docs/nubes/nubes/2.1.7/30_registry/guides/getting-started/#lucee-postgress ```hcl title="resources.tf" # RabbitMQ кластер для демо. resource "nubes_rabbitmq" "rb1" { resource_name = "rabbit_0" resource_realm = "k8s-3.ext.nubes.ru" resource_instances = 1 resource_memory = 512 resource_c_p_u = 500 resource_disk = 5 need_external_address_master = false need_external_address_slave = false } # Lucee UI, который пишет в Rabbit и читает из Postgres. resource "nubes_lucee" "rabbit_ui" { resource_name = "rb-lucee-ui" resource_realm = "k8s-3.ext.nubes.ru" domain = "rb-ui" app_version = "5.4" git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/rabbit-lsd" resource_c_p_u = 300 resource_memory = 512 resource_instances = 1 # Переменные окружения для datasource, Rabbit и UI. json_env = jsonencode({ testds_bundleName = "org.postgresql.jdbc" testds_bundleVersion = "42.6.0" testds_class = "org.postgresql.Driver" testds_connectionLimit = "5" testds_connectionString = "jdbc:postgresql://${var.PGHOST}:5432/postgres" testds_liveTimeout = "15" testds_username = var.PGUSER testds_password = var.PGPASSWORD testds_validate = "false" PG_TABLE = "rabbit_messages" UI_LOG_TABLE = "rabbit_ui_log" RABBIT_HOST = try(nubes_rabbitmq.rb1.state_out_flat["internalConnect.master"], nubes_rabbitmq.rb1.state_out_flat["inernalConnect.master"]) RABBIT_PORT = "5672" RABBIT_USER = nubes_rabbitmq.rb1.vault_secrets["adminUser"] RABBIT_PASSWORD = nubes_rabbitmq.rb1.vault_secrets["adminPass"] RABBIT_VHOST = "/" RABBIT_QUEUES = "crud_queue" RABBIT_DURABLE = "true" RABBIT_ADMIN_URL = "https://${nubes_rabbitmq.rb1.state_out_flat["externalConnect.admin.fqdn"]}/#/" NODEWORKER_URL = "https://nodeworker.nodejsk8s.services.ngcloud.ru/" }) depends_on = [nubes_rabbitmq.rb1] } # NodeJS воркер, который переносит CRUD из очереди в Postgres. resource "nubes_nodejs" "rabbit_nodeworker" { resource_name = "nodeworker" resource_realm = "k8s-3.ext.nubes.ru" domain = "nodeworker" app_version = "23" git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/rabbit-nodeworker.git" health_path = "/healthz" resource_c_p_u = 100 resource_memory = 256 resource_instances = 1 # Параметры подключения к Rabbit и Postgres. json_env = jsonencode({ RABBIT_HOST = try(nubes_rabbitmq.rb1.state_out_flat["internalConnect.master"], nubes_rabbitmq.rb1.state_out_flat["inernalConnect.master"]) RABBIT_PORT = "5672" RABBIT_USER = nubes_rabbitmq.rb1.vault_secrets["adminUser"] RABBIT_PASSWORD = nubes_rabbitmq.rb1.vault_secrets["adminPass"] RABBIT_VHOST = "/" RABBIT_QUEUES = "crud_queue" RABBIT_DURABLE = "true" RABBIT_PREFETCH = "1" REQUEUE_ON_ERROR = "true" PGHOST = var.PGHOST PGPORT = "5432" PGUSER = var.PGUSER PGPASSWORD = var.PGPASSWORD PGDATABASE = "postgres" PGSSLMODE = "require" PG_TABLE = "rabbit_messages" }) depends_on = [nubes_rabbitmq.rb1] } # Ручной триггер redeploy для воркера. resource "nubes_nodejs_redeploy" "rabbit_nodeworker_redeploy" { nodejs_id = nubes_nodejs.rabbit_nodeworker.id resource_realm = "k8s-3.ext.nubes.ru" run_id = "redeploy-2026-02-23-011" } ``` ```hcl title="variables.tf" // Postgres уже запущен, значения берутся из UI Личного кабинета. variable "PGUSER" { type = string default = "postgres" } variable "PGPASSWORD" { type = string default = "" # пароль укажите вручную, в примере не публикуем } variable "PGHOST" { type = string default = "postgresqlk8s-master..svc.k8s-3.ext.nubes.ru" # оставьте префикс и суффикс, меняется только } ``` ```hcl title="terraform.tfvars" # Инструкция по получению токена: раздел "Получение API токена" api_token = "eyJhbGciOiJ..." ```