Само собой разумеется, что данные являются важнейшим активом для любой организации. Поэтому очень важно, чтобы платформа, обрабатывающая все эти данные, могла делать это с учетом масштабируемости и скорости.
Введите… 🥁🥁🥁 Snowflake!
Snowflake — это облачная платформа для данных x
, где x = [хранилище, озера, проектирование, наука, применение, обмен]
. То есть все, что связано с данными.
С другой стороны, Terraform — это инструмент инфраструктуры как кода, который позволяет определять облачные ресурсы в человекочитаемых конфигурационных файлах, которые можно редактировать, повторно использовать и совместно использовать.
Что может быть лучше, чем Snowflake ++ Terraform?
В этой статье мы покажем, как мы использовали Terraform для настройки ресурсов Snowflake при работе над Weather Nowcasting — развертывании модели на границе. Кроме того, мы покажем, как загрузить содержимое контейнера Azure в таблицу Snowflake.
Существует более 1700 провайдеров для управления множеством различных ресурсов и услуг. Среди них вы также можете найти несколько провайдеров для Snowflake, но самым используемым является провайдер chanzuckerberg. Мы взяли за основу наш шаблон Terraform и опишем шаг за шагом, как вы можете создавать ресурсы Snowflake с помощью нашего шаблона.
- Информация об учетной записи Snowflake
- Подключение Snowflake & Terraform
- Создайте RSA-ключ для аутентификации
- Создание пользователя службы для аутентификации
- Структура проекта
- Настройте провайдер Snowflake
- Инициализация Snowflake
- Создание интеграции хранилища
- Создание интеграции уведомлений
- Создание этапа
- Создание трубы
- Ручные шаги
- Применение изменений
- Инициализация Terraform
- Формат Terraform
- Terraform validate
- Terraform plan
- Terraform apply
- Заключение
Информация об учетной записи 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—>