CLOVER🍀

That was when it all began.

Terraformのgraphコマンドで、構成を可視化してみる

これは、なにをしたくて書いたもの?

Terraformのリソースの依存関係を出力できないのかな?と思ったのですが、terraform graphコマンドでGraphvizのdot形式で出力可能な
ようなので、1度試してみることにしました。

Command: graph - Terraform by HashiCorp

terraform graph

正確には、Terraformの定義ファイルの構成または実行計画を、可視化するコマンドです。

Command: graph - Terraform by HashiCorp

    graph              Create a visual graph of Terraform resources

グラフを作成するディレクトリを指定して実行するようで、省略するとカレントディレクトリを対象にして処理を行うようです。

「terraform graph」のヘルプを見てみると、

$ terraform graph -help
Usage: terraform graph [options] [DIR]

以下のようなオプションを指定できることが確認できます。

Options:

  -draw-cycles     Highlight any cycles in the graph with colored edges.
                   This helps when diagnosing cycle errors.

  -type=plan       Type of graph to output. Can be: plan, plan-destroy, apply,
                   validate, input, refresh.

  -module-depth=n  (deprecated) In prior versions of Terraform, specified the
                   depth of modules to show in the output.

循環参照や、出力する種類を指定できるようです。出力対象にするモジュールの深さも指定できるようですが、今は非推奨の模様。

こちらを使って、動きをみてみましょう。

環境

今回の環境は、こちらです。

$ terraform version
Terraform v0.12.24

また、出力対象としては、MySQL Providerを使ったリソース定義を行います。

サンプルを作成する

作成するのは、MySQLデータベースと、ユーザー×2、ユーザーに紐付ける権限、という構成にします。

あまり意味はないですが、MySQLデータベースだけサブモジュールに切り出してみます。

ざっくり、こんな構成。

$ find main.tf modules -type f
main.tf
modules/my_mysql/outputs.tf
modules/my_mysql/main.tf
modules/my_mysql/variables.tf

モジュールは、こんな感じにしました。MySQL Providerは、ルートモジュールの方で宣言しています。
modules/my_mysql/main.tf

resource "mysql_database" "database" {
  name = var.database_name

  default_character_set = "utf8mb4"
  default_collation     = "utf8mb4_ja_0900_as_cs_ks"
}

中身は、データベース定義のみです。

あと、Input Variables、Output Variablesも一応作成。
modules/my_mysql/variables.tf

variable "mysql_endpoint" {
  default = "localhost:3306"
}

variable "mysql_admin_username" {}

variable "mysql_admin_password" {}

variable "database_name" {}

modules/my_mysql/outputs.tf

output "database_name" {
  value = mysql_database.database.name
}

ルートモジュールのメインの構成ファイル。こちらでは、ユーザーの作成と、権限の紐付けを行っています。
main.tf

terraform {
  required_version = ">= 0.12.24"
}

locals {
  endpoint                           = "172.17.0.2:3306"
  admin_username                     = "root"
  admin_password                     = "password"
  database_admin_user_username       = "adminuser"
  database_admin_user_password       = "password"
  database_admin_user_host           = "%"
  database_application_user_username = "appuser"
  database_application_user_password = "password"
  database_application_user_host     = "%"
}


provider "mysql" {
  endpoint = local.endpoint
  username = local.admin_username
  password = local.admin_password

  version = "1.9.0"
}

module "my_mysql" {
  source = "./modules/my_mysql"

  mysql_endpoint = "172.17.0.2:3306"

  mysql_admin_username = "root"
  mysql_admin_password = "password"

  database_name = "practice"
}

resource "mysql_user" "admin_user" {
  user               = local.database_admin_user_username
  plaintext_password = local.database_admin_user_password
  host               = local.database_admin_user_host
}

resource "mysql_grant" "admin_user" {
  user       = local.database_admin_user_username
  host       = local.database_admin_user_host
  database   = module.my_mysql.database_name
  privileges = ["ALL"]

  depends_on = [mysql_user.admin_user]
}

resource "mysql_user" "application_user" {
  user               = local.database_application_user_username
  plaintext_password = local.database_application_user_password
  host               = local.database_application_user_host
}

resource "mysql_grant" "application_user" {
  user       = local.database_application_user_username
  host       = local.database_application_user_host
  database   = module.my_mysql.database_name
  privileges = ["SELECT", "INSERT", "UPDATE", "DELETE"]

  depends_on = [mysql_user.application_user]
}

init等々。

$ terraform init
$ terraform version
Terraform v0.12.24
+ provider.mysql v1.9.0
$ terraform fmt -recursive
$ terraform validate

今回はここは主題ではありませが、一応、applyできることも確認しておきます。

$ terraform apply -auto-approve
$ terraform destroy -force

terraform graphで可視化してみる

では、「terraform graph」で構成を可視化してみましょう。

Command: graph - Terraform by HashiCorp

ドキュメントのサンプルでは、SVG形式で出力していますね。

$ terraform graph | dot -Tsvg > graph.svg

Graphvizで出力に指定できる形式は、こちら。

Output Formats

今回は、PNGにしてみましょう。

$ terraform graph | dot -Tpng > graph.png

出力結果は、こんな感じです。

f:id:Kazuhira:20200502222834p:plain

リソースだけではなくて、ローカル変数も含めて、変数なども表示されるんですね。

図形の種類について

ところで、各要素で図形が異なるようです。

パッと見、ルートは楕円、Providerはひし形、リソースは四角、ローカル変数やInput/Output Variablesはノートのようになっています。

これを確認するには、ソースコードのDotNode関数を見れば良さそうです。

https://github.com/hashicorp/terraform/blob/v0.12.24/terraform/node_provider_abstract.go#L88-L96

https://github.com/hashicorp/terraform/blob/v0.12.24/terraform/node_resource_abstract.go#L413-L421

https://github.com/hashicorp/terraform/blob/v0.12.24/terraform/node_root_variable.go#L56-L64

https://github.com/hashicorp/terraform/blob/v0.12.24/terraform/node_module_variable.go#L142-L150

https://github.com/hashicorp/terraform/blob/v0.12.24/terraform/node_output.go#L131-L139

https://github.com/hashicorp/terraform/blob/v0.12.24/terraform/node_local.go#L62-L70

https://github.com/hashicorp/terraform/blob/v0.12.24/terraform/transform_provider.go#L458-L469

  • Provider … diamond
  • リソース、データーソース … box
  • 変数(variable、local variable) … note

という感じですね。

今回は、Data Sourceを確認しませんでしたが、表示形式としてはboxになるようです。