この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
大阪オフィスの玉井です。
Infrastructure as Code(IaC)を実現するためのツールとしておなじみのTerraformですが、実はSnowflakeにも対応しています。というわけで、実際にやってみました。
概要など
厳密にいうと、Chan Zuckerberg InitiativeがSnowflake用のproviderを開発しており、それを利用して、TerraformでSnowflakeを管理することができます。
下記のウェビナーで詳しい説明があるのでどうぞ。
ちなみに、「DevOps: Terraforming Snowflake」という名前の、Snowflake公式のチュートリアルがあります(私もやりました)。
やってみた
環境
- macOS Big Sur 11.4
- Terraform v1.0.0
やってみる内容
「開発者に、個人用のSnowflakeリソース一式を用意してあげる」っていうのを想定して、下記をTerraformで一気に作ってみたいと思います。
- ユーザー
- ロール
- DB
- スキーマ
- 仮想ウェアハウス
ちなみに、テーブルは今回つくりません(理由は後述)。
Snowflakeとの認証
Terraformが(ユーザーに代わって)Snowflakeのリソースを作成するので、まずはTerraform用のユーザーを作成します。割当ロールについて、今回はとりあえずSYSADMIN
とSECURITYADMIN
を使えるようにしていますが、本番運用する際は、より適切なカスタムロールを作って、それを割り当てる方が良いです。
CREATE USER "tf-snow" DEFAULT_ROLE=PUBLIC MUST_CHANGE_PASSWORD=FALSE;
GRANT ROLE SYSADMIN TO USER "tf-snow";
GRANT ROLE SECURITYADMIN TO USER "tf-snow";
続いて、Terraformが使用するSnowflakeに対する認証情報の準備です。公式ドキュメントを見るに、tfファイルにベタ書きすることもできそうですが、今回は、冒頭で紹介したチュートリアルにならって、環境変数に認証に必要な情報を入れて、それをProvider側で使用する方法をとります。
環境変数にぶちこんでいきます。
> export SNOWFLAKE_USER="tf-snow"
> export SNOWFLAKE_ACCOUNT="Snowflakeのアカウント名(URLの最初)"
> export SNOWFLAKE_REGION="Snowflakeのリージョン名(URLの真ん中)"
コード本体
今回のコードは以下の通り。今回はとりあえず全部main.tf
に書いています。
terraform {
required_providers {
snowflake = {
source = "chanzuckerberg/snowflake"
version = "0.22.0"
}
}
}
provider "snowflake" {
role = "SYSADMIN"
}
resource "snowflake_database" "db" {
name = "TIGER_DB"
}
resource "snowflake_schema" "schema" {
database = snowflake_database.db.name
name = "TIGER_SCHEMA"
is_managed = false
data_retention_days = 90
}
resource "snowflake_warehouse" "warehouse" {
name = "TIGER_WAREHOUSE"
initially_suspended = true
warehouse_size = "xsmall"
max_cluster_count = 1
min_cluster_count = 1
auto_suspend = 60
}
provider "snowflake" {
alias = "security_admin"
role = "SECURITYADMIN"
}
resource "snowflake_role" "role" {
provider = snowflake.security_admin
name = "TIGER_ROLE"
}
resource "snowflake_database_grant" "grant" {
database_name = snowflake_database.db.name
privilege = "USAGE"
roles = [snowflake_role.role.name]
with_grant_option = false
}
resource "snowflake_schema_grant" "grant" {
database_name = snowflake_database.db.name
schema_name = snowflake_schema.schema.name
privilege = "USAGE"
roles = [snowflake_role.role.name]
with_grant_option = false
}
resource "snowflake_warehouse_grant" "grant" {
warehouse_name = snowflake_warehouse.warehouse.name
privilege = "USAGE"
roles = [snowflake_role.role.name]
with_grant_option = false
}
resource "snowflake_user" "user" {
provider = snowflake.security_admin
name = "SATORU_SAYAMA"
default_warehouse = snowflake_warehouse.warehouse.name
default_role = snowflake_role.role.name
default_namespace = "${snowflake_database.db.name}.${snowflake_schema.schema.name}"
}
resource "snowflake_role_grants" "grants" {
role_name = snowflake_role.role.name
users = [snowflake_user.user.name]
}
コードの中身自体は読めばそのままわかるものばかりだと思います。仮想ウェアハウスの自動サスペンド時間など、細かい設定が可能です。リソースによっては、ロールを使い分ける必要があるので、Multiple Providersで対応しているところがポイントでしょうか。
実行する
実行はTerraform側の話なので、普通にやります(Snowflakeだからといって特殊なことはない)。
> terraform init
Initializing the backend...
Initializing provider plugins...
- Reusing previous version of chanzuckerberg/snowflake from the dependency lock file
- Using previously-installed chanzuckerberg/snowflake v0.22.0
Terraform has been successfully initialized!
...(略)
> terraform apply
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# snowflake_database.db will be created
+ resource "snowflake_database" "db" {
+ data_retention_time_in_days = (known after apply)
+ id = (known after apply)
+ name = "TIGER_DB"
}
# snowflake_database_grant.grant will be created
+ resource "snowflake_database_grant" "grant" {
+ database_name = "TIGER_DB"
+ id = (known after apply)
+ privilege = "USAGE"
+ roles = [
+ "TIGER_ROLE",
]
+ with_grant_option = false
}
...(中略)...
Plan: 9 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
snowflake_role.role: Creating...
snowflake_database.db: Creating...
snowflake_warehouse.warehouse: Creating...
snowflake_role.role: Creation complete after 1s [id=TIGER_ROLE]
snowflake_warehouse.warehouse: Creation complete after 1s [id=TIGER_WAREHOUSE]
...(中略)...
Apply complete! Resources: 9 added, 0 changed, 0 destroyed.
確認する
Snowflake側を確認します。いや〜見事に作成できていますね。
補足など
テーブル
このProviderには、テーブルを作成するResourceもちゃんとあります(カラムも指定できる)。しかし、テーブルとなってくると、データそのものをどうするか?ということを考える必要が出てきます。それはすなわち「どういうデータ分析をするのか?」ということにつながってくるのですが、Terraformの段階で、そこも一緒に考えるのは、あまり得策ではないと考えたので、テーブル作成は省きました。テーブルやビューの作成や変換は別手段(dbtなど)でやったほうがいいと思います。
他にもやれそうなこと
その他のリソース
このProviderは、他にもStage、File Format、Pipe、Streamなどの、Snowflake独自のリソースにも対応しています。これらもTerraformで管理することで、より複雑なSnowflake環境を簡単に用意することができそうです。
変数を使う
今回のように「その人のための環境を用意する」という目的の場合、作成するリソース名に変数を使用し、実行時に名前を入れることで、汎用的に使用できるようにできそうです。
おわりに
Snowflakeも、運用規模が大きくなると、手動でリソースを作成するのが辛くなってきますし、ヒューマンエラーのリスクもあります。リソース設定のクエリを準備するのもアリですが、Terraformの方が、(クエリよりも)コードの可読性が高かったり、CI/CDに組み込めたりするので、気になった方は是非やってみてください。