TerraformでSnowflakeのリソースを作成してみた
大阪オフィスの玉井です。
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に組み込めたりするので、気になった方は是非やってみてください。