Терраформирование снежинки ️

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

Введите… 🥁🥁🥁 Snowflake!

Snowflake — это облачная платформа для данных x, где x = [хранилище, озера, проектирование, наука, применение, обмен]. То есть все, что связано с данными.

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

Что может быть лучше, чем Snowflake ++ Terraform?

В этой статье мы покажем, как мы использовали Terraform для настройки ресурсов Snowflake при работе над Weather Nowcasting — развертывании модели на границе. Кроме того, мы покажем, как загрузить содержимое контейнера Azure в таблицу Snowflake.


Существует более 1700 провайдеров для управления множеством различных ресурсов и услуг. Среди них вы также можете найти несколько провайдеров для Snowflake, но самым используемым является провайдер chanzuckerberg. Мы взяли за основу наш шаблон Terraform и опишем шаг за шагом, как вы можете создавать ресурсы Snowflake с помощью нашего шаблона.

Информация об учетной записи Snowflake

Для того чтобы подключить Snowflake к коду Terraform, вам в первую очередь потребуется узнать некоторую информацию о вашей учетной записи.

Идентификатор учетной записи однозначно идентифицирует учетную запись Snowflake в вашей организации, а также во всей глобальной сети облачных платформ и облачных регионов, поддерживающих Snowflake. [snowflake.com].

URL-адрес содержит всю необходимую информацию: https://app.snowflake.com/<region-id>.<cloud-provider>/<account-locator>/worksheets.

<!—kg-card-end: markdown—><!—kg-card-begin: markdown—>

Account locator — это идентификатор, присваиваемый Snowflake при создании учетной записи. Его значение можно увидеть либо в URL, либо выполнив следующую команду в рабочем листе: SELECT current_account() as YOUR_ACCOUNT_LOCATOR;.

<!—kg-card-end: markdown—><!—kg-card-begin: markdown—>

Snowflake region id представляет облачный регион, в котором находится учетная запись. Его значение можно увидеть либо в URL, либо выполнив следующую команду в рабочем листе: SELECT current_region() as YOUR_SNOWFLAKE_REGION_ID;.

Затем в возвращенном значении необходимо выполнить поиск (в этой таблице) и выбрать соответствующий ему идентификатор облачного региона.

На данном этапе ваша информация должна быть, например, такой:

SNOWFLAKE_ACCOUNT = xy12345


Подключение Snowflake & Terraform

Для того чтобы установить соединение между Snowflake и Terraform, вам также необходимо предоставить некоторые учетные данные, а именно пользователя и пароль.

Создайте RSA-ключ для аутентификации

Мы будем использовать ключ RSA, но существуют и другие способы аутентификации. Вы можете ознакомиться с ними здесь.

Следующие команды создадут пару открытый/закрытый ключ:

cd ~/.ssh

Теперь вы должны иметь возможность просмотреть свой открытый ключ, который должен иметь содержание, похожее на следующее:

-----BEGIN PUBLIC KEY-----

<!—kg-card-end: markdown—><!—kg-card-begin: markdown—>

Создание пользователя службы для аутентификации

<!—kg-card-end: markdown—><!—kg-card-begin: markdown—>

Чтобы создать нового пользователя, который будет использоваться для установления соединения с Terraform, вы можете выполнить следующие команды в рабочем листе. Обратите внимание, что мы напрямую связываем пользователя с только что созданным RSA-ключом в качестве метода аутентификации:

USE ROLE ACCOUNTADMIN;
CREATE OR REPLACE USER "tf-snow" RSA_PUBLIC_KEY='<PUBLIC_KEY>' DEFAULT_ROLE=PUBLIC MUST_CHANGE_PASSWORD=FALSE;
GRANT ROLE SYSADMIN TO USER "tf-snow";
GRANT ROLE SECURITYADMIN TO USER "tf-snow";

Войти в полноэкранный режим Выйти из полноэкранного режима

До этого момента у вас должна быть следующая информация:

SNOWFLAKE_USER = tf-snow


Структура проекта


Рисунок 1. Структура папки Terraform

Корневая папка содержит файлы main.tf, variables.tf и .terraform.lock.hcl. Последний представляет собой файл блокировки зависимостей, и вы можете прочитать о нем подробнее здесь.

<!—kg-card-end: markdown—><!—kg-card-begin: markdown—>

Мы решили создать только два окружения, prod и staging. Таким образом, вы заметите, что это имена tfvars, которые мы будем представлять в дальнейшем.

Более того, в коде вы часто будете видеть var.env или local.env_upper, что является версией var.env в верхнем регистре.

<!—kg-card-end: markdown—><!—kg-card-begin: markdown—>

В папке backend у нас есть prod.tfvars и staging.tfvars. Каждый файл содержит ключевое значение, которое соответствует имени файла, содержащего состояние ресурсов в любой момент времени, например, prod.tfvars имеет содержание key = "prod.tfstate".


Рисунок 2. Файлы бэкенда

Папка vars содержит prod.tfvars и staging.tfvars, но они содержат ссылки на переменные окружения. Например, prod.tfvars имеет следующее содержание:

env = "prod"
subscription_id = env.ARM_SUBSCRIPTION_ID
tenant_id = env.ARM_TENANT_ID

Войти в полноэкранный режим Выйти из полноэкранного режима

<!—kg-card-end: markdown—><!—kg-card-begin: markdown—>

Вы можете заметить еще две папки, а именно azure и snowflake. Это модули, которые позже будут описаны более подробно. Подробнее о модулях Terraform вы можете прочитать здесь.


Настройте провайдер Snowflake

<!—kg-card-end: markdown—><!—kg-card-begin: markdown—>

Чтобы определить провайдера Snowflake, вы должны включить следующие блоки кода в ваш файл main.tf:

<!—kg-card-end: markdown—><!—kg-card-begin: markdown—>

terraform {
  required_version = ">= 1.1"
  required_providers {
    snowflake = {
      source = "chanzuckerberg/snowflake"
      version = "0.31.0"
    }
  }
}

provider "snowflake" {
  features {}
  alias = "terraform"
  role = "ACCOUNTADMIN"
}

module "snowflake" {
  source = "./snowflake"
  env = var.env
}

Вход в полноэкранный режим Выход из полноэкранного режима

<!—kg-card-end: markdown—><!—kg-card-begin: markdown—>

Теперь нам нужно создать файл main.tf в модуле snowflake, поскольку это источник, определенный в предыдущем шаге. Его содержимое должно содержать следующее:

<!—kg-card-end: markdown—><!—kg-card-begin: markdown—>

terraform {
  required_providers {
    snowflake = {
      source = "chanzuckerberg/snowflake"
      version = "0.31.0"
    }
  }
}

provider "snowflake" {
  alias = "terraform"
  role = "ACCOUNTADMIN"
}

Войдите в полноэкранный режим Выйти из полноэкранного режима

Далее мы продолжим описывать все необходимые шаги для правильной настройки ресурсов. Весь код вы можете найти в нашем репозитории Github.


Инициализация Snowflake

Есть 3 обязательных ресурса, которые нам необходимо создать. Это: база данных, схема и хранилище.

resource "snowflake_database" "main" {
  provider = snowflake.terraform
  name = "WEATHER_${local.env_upper}"
}

resource "snowflake_warehouse" "weather" {
  provider = snowflake.terraform
  name = "WEATHER_WHS_${local.env_upper}"
  warehouse_size = "xsmall"
  auto_suspend = 60
}

resource "snowflake_schema" "datawarehouse" {
  provider = snowflake.terraform
  database = snowflake_database.main.name
  name = "DATAWAREHOUSE_${local.env_upper}"
  is_managed = false
}

Войдите в полноэкранный режим Выход из полноэкранного режима

<!—kg-card-end: markdown—><!—kg-card-begin: markdown—>

Наш сценарий включал получение содержимого JSON-файла в режиме реального времени из контейнера Azure. Таким образом, нам нужна была только таблица с одним столбцом типа VARIANT.

<!—kg-card-end: markdown—><!—kg-card-begin: markdown—>

resource "snowflake_table" "sensor" {
  provider = snowflake.terraform
  database = snowflake_database.main.name
  schema = snowflake_schema.datawarehouse.name
  name = "WEATHER_JSON_${local.env_upper}"
  column {
    name = "var"
    type = "VARIANT"
    comment = "Raw sensor data"
  }
}

Вход в полноэкранный режим Выход из полноэкранного режима

Для того чтобы иметь возможность настраивать наш JSON-ввод, мы решили создать пользовательский формат файла:

resource "snowflake_file_format" "json" {
  provider = snowflake.terraform
  name = "JSON_DQ_${local.env_upper}"
  database = snowflake_database.main.name
  schema = snowflake_schema.datawarehouse.name
  format_type = "JSON"
  strip_outer_array = true
  compression = "NONE"
  binary_format = "HEX"
  date_format = "AUTO"
  time_format = "AUTO"
  timestamp_format = "AUTO"
  skip_byte_order_mark = true
}

Войти в полноэкранный режим Выйти из полноэкранного режима

Создание интеграции хранилища

Интеграция хранилища — это объект Snowflake, который хранит сгенерированную сущность управления идентификацией и доступом (IAM) для вашего внешнего облачного хранилища, а также дополнительный набор разрешенных или заблокированных мест хранения. [snowflake.com].

Мы подошли к той части, где выбранный поставщик облачных услуг становится важным; в данном случае мы работаем с Azure. Итак, для этого шага на вашей учетной записи Azure уже должны быть созданы учетная запись хранилища (Standard general-purpose v2) и контейнер. Теперь вы можете связать Snowflake с контейнером, как показано ниже:

  provider = snowflake.terraform
  type = "EXTERNAL_STAGE"
  storage_provider = "AZURE"
  azure_tenant_id = data.azurerm_client_config.current.tenant_id
  name = "AZURE_INTEGRATION_${local.env_upper}"
  comment = "A storage integration for Azure blobs."
  enabled = true
  storage_allowed_locations = ["azure://<storage-account-name>.blob.core.windows.net/<container-name>"]
}

Войдите в полноэкранный режим Выйти из полноэкранного режима

Создание интеграции уведомлений

Интеграция уведомлений — это объект Snowflake, который обеспечивает интерфейс между Snowflake и сторонними облачными службами очередей сообщений. [snowflake.com].

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

resource "snowflake_notification_integration" "azure_queue" {
  provider = snowflake.terraform
  name = "WEATHER_NOTIFICATION_${local.env_upper}"
  enabled = true
  type = "QUEUE"
  notification_provider = "AZURE_STORAGE_QUEUE"
  azure_storage_queue_primary_uri = "https://<storage-account-name>.queue.core.windows.net/<queue-name>"
  azure_tenant_id = data.azurerm_client_config.current.tenant_id
}

Вход в полноэкранный режим Выход из полноэкранного режима

Создание этапа

Этап используется для загрузки данных из файлов в таблицы Snowflake и выгрузки данных из таблиц в файлы. [snowflake.com].

Для этого этапа важно отметить, что вам необходимо сгенерировать SAS Token для вашего контейнера.

resource "snowflake_stage" "snowstage" {
  provider = snowflake.terraform
  name = "SNOWPIPE_STAGE_${local.env_upper}"
  url = "azure://<storage-account-name>.blob.core.windows.net/<container-name>"
  database = snowflake_database.main.name
  schema = snowflake_schema.datawarehouse.name
  credentials = "AZURE_SAS_TOKEN='${var.sas_token}'"
  file_format = "FORMAT_NAME = ${local.qualified_file_format_name}"
}

Вход в полноэкранный режим Выход из полноэкранного режима

Создание трубы

Труба создается для определения оператора COPY INTO

используемого Snowpipe для загрузки данных из очереди ввода в таблицы. [snowflake.com].

Теперь, когда мы успешно связали хранилище Azure blob storage со Snowflake, мы можем создать трубу, которая будет использоваться для загрузки данных из хранилища blob storage в нашу таблицу snowflake.

resource "snowflake_pipe" "snowpipe" {
  provider = snowflake.terraform
  database = snowflake_database.main.name
  schema = snowflake_schema.datawarehouse.name
  name = "WEATHER_PIPE_DQ_${local.env_upper}"

  copy_statement = "copy into ${local.qualified_sensor_table_name} from @${local.qualified_stage_name} file_format = (format_name = ${local.qualified_file_format_name})"
  auto_ingest = true
  integration = snowflake_notification_integration.azure_queue.name
}


Ручные шаги

На данном этапе все ваши ресурсы созданы, и все должно быть настроено. Но если вы попытаетесь протестировать поток данных, вы заметите досадную ошибку, подобную этой:

COULD NOT ACCESS QUEUE; THIS REQUEST IS NOT AUTHORIZED TO PERFORM THIS OPERATION USING THIS PERMISSION. (STATUS CODE:403; ERROR CODE:AUTHORIZATIONPERMISSIONMISMATCH)”

Теперь пришло время снова перейти к вашим рабочим таблицам Snowflake и предоставить доступ к вашему контейнеру хранения. Чтобы сделать это, необходимо выполнить два шага.

Первый состоит в поиске информации для интеграции хранилища. Это можно сделать с помощью команды: desc STORAGE INTEGRATION <NAME OF YOUR STORAGE INTEGRATION>;.

Теперь вы увидите таблицу со всеми свойствами вашей интеграции хранилища. Важными из них являются следующие:

Вторым шагом будет выполнение тех же действий, но для интеграции уведомлений: DESC NOTIFICATION INTEGRATION <NAME OF YOUR NOTIFICATION INTEGRATION>;.


Применение изменений

Как вы уже знаете, чтобы применить изменения, внесенные в код Terraform, на ресурсах Snowflake, необходимо выполнить несколько команд. Мы кратко представим, что нужно сделать на этом шаге.

Инициализация Terraform

используется для инициализации рабочего каталога, содержащего файлы конфигурации Terraform. Это первая команда, которую следует выполнить после создания новой конфигурации Terraform или клонирования существующей из системы управления версиями. Безопасно выполнять эту команду несколько раз. [terraform.com].

например, terraform init -backend-config backend/staging.tfvars

Формат Terraform

используется для переписывания конфигурационных файлов Terraform в канонический формат и стиль. Эта команда применяет подмножество соглашений о стиле языка Terraform, а также другие незначительные корректировки для удобства чтения. [terraform.com].

например, terraform fmt -check -recursive

Terraform validate

проверяет конфигурационные файлы в каталоге, обращаясь только к конфигурации и не обращаясь ни к каким удаленным сервисам, таким как удаленное состояние, API провайдеров и т.д. [terraform.com].

например, terraform validate

Terraform plan

создает план выполнения, который позволяет вам предварительно просмотреть изменения, которые Terraform планирует внести в вашу инфраструктуру. [terraform.com].

например, terraform plan -var-file vars/staging.tfvars

Terraform apply

выполняет действия, предложенные в плане Terraform. [terraform.com].

например, terraform apply -var-file vars/staging.tfvars


Заключение

Теперь все должно быть настроено, и как только вы загрузите файл в контейнер, его содержимое должно быть скопировано в таблицу. Для примера рассмотрим файл JSON со следующим содержимым:

{
  "Body": {
    "ts": "2022-04-08T15:07:29.130826",
    "tz": "CEST",
    "message": {
      "temperature": 29.17,
      "humidity": 22.5,
      "pressure": 994.53,
      "light": 159.26,
      "uv": 0.04,
      "ir": 278
    }
  }
}

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


Рисунок 3. Запись в таблице из файла JSON


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

С помощью terraform plan мы проверяем, что изменения, применяемые к ресурсам, действительно соответствуют нашим целям. Затем, с помощью terraform apply вы действительно применяете эти изменения!

Управляя нашей учетной записью Snowflake через Terraform, мы автоматизировали этот процесс, чреватый ошибками. Таким образом, нет необходимости вручную обновлять один и тот же ресурс в каждой среде. Кроме того, используя CI/CD, мы еще больше упростили управление ресурсами.

Действительно, провайдер Snowflake для Terraform задокументирован, но вы можете обнаружить, что не все ресурсы обновляются или что некоторые содержат ошибки копирования-вставки. Просто не принимайте все как должное и спросите себя, имеют ли некоторые свойства смысл!

Наконец, мы призываем вас попробовать воссоздать этот проект и рассказать нам о том, как все прошло!


  • Репозиторий GitHub, где вы можете найти исходный код для этой статьи в блоге<!—kg-card-end: markdown—>

Оцените статью
devanswers.ru
Добавить комментарий