ここに terraform graph があるじゃろ?これをこうして…こうじゃ。

github.blog

GitHub のマークダウンファイルにおいて、Mermaid.js が使えるようになったので、練習のために terraform graph の出力を、わかりやすく Mermaid 構文に変換して、README.md ファイル等に埋め込む GitHub Action を作成しました。

サンプルとして、以下のような Terraform AWS provider の使用例 の出力で説明します。

[root] aws_elb.web (expand) aws_elb.web [root] aws_instance.web (expand) aws_instance.web [root] aws_elb.web (expand)->[root] aws_instance.web (expand) [root] aws_security_group.elb (expand) aws_security_group.elb [root] aws_elb.web (expand)->[root] aws_security_group.elb (expand) [root] aws_key_pair.auth (expand) aws_key_pair.auth [root] aws_instance.web (expand)->[root] aws_key_pair.auth (expand) [root] aws_security_group.default (expand) aws_security_group.default [root] aws_instance.web (expand)->[root] aws_security_group.default (expand) [root] aws_subnet.default (expand) aws_subnet.default [root] aws_instance.web (expand)->[root] aws_subnet.default (expand) [root] var.aws_amis var.aws_amis [root] aws_instance.web (expand)->[root] var.aws_amis [root] aws_internet_gateway.default (expand) aws_internet_gateway.default [root] aws_vpc.default (expand) aws_vpc.default [root] aws_internet_gateway.default (expand)->[root] aws_vpc.default (expand) [root] provider["registry.terraform.io/hashicorp/aws"] provider["registry.terraform.io/hashicorp/aws"] [root] aws_key_pair.auth (expand)->[root] provider["registry.terraform.io/hashicorp/aws"] [root] var.key_name var.key_name [root] aws_key_pair.auth (expand)->[root] var.key_name [root] var.public_key_path var.public_key_path [root] aws_key_pair.auth (expand)->[root] var.public_key_path [root] aws_route.internet_access (expand) aws_route.internet_access [root] aws_route.internet_access (expand)->[root] aws_internet_gateway.default (expand) [root] aws_security_group.default (expand)->[root] aws_vpc.default (expand) [root] aws_security_group.elb (expand)->[root] aws_vpc.default (expand) [root] aws_subnet.default (expand)->[root] aws_vpc.default (expand) [root] aws_vpc.default (expand)->[root] provider["registry.terraform.io/hashicorp/aws"] [root] output.address output.address [root] output.address->[root] aws_elb.web (expand) [root] var.aws_region var.aws_region [root] provider["registry.terraform.io/hashicorp/aws"]->[root] var.aws_region [root] provider["registry.terraform.io/hashicorp/aws"] (close) [root] provider["registry.terraform.io/hashicorp/aws"] (close) [root] provider["registry.terraform.io/hashicorp/aws"] (close)->[root] aws_elb.web (expand) [root] provider["registry.terraform.io/hashicorp/aws"] (close)->[root] aws_route.internet_access (expand) [root] root [root] root [root] root->[root] output.address [root] root->[root] provider["registry.terraform.io/hashicorp/aws"] (close)

初手、出力された GraphViz の DOT フォーマットを、単純に Mermaid 構文に置き換えます。

flowchart LR
n0["aws_elb.web"]
n1["aws_instance.web"]
n2["aws_internet_gateway.default"]
n3["aws_key_pair.auth"]
n4["aws_route.internet_access"]
n5["aws_security_group.default"]
n6["aws_security_group.elb"]
n7["aws_subnet.default"]
n8["aws_vpc.default"]
n9(["output.address"])
na[/"provider<br/>[&quot;registry.terraform.io/hashicorp/aws&quot;]"\]
nb(["var.aws_amis"])
nc(["var.aws_region"])
nd(["var.key_name"])
ne(["var.public_key_path"])
n0-->n1
n0-->n6
n1-->n3
n1-->n5
n1-->n7
n1-->nb
n2-->n8
n3-->na
n3-->nd
n3-->ne
n4-->n2
n5-->n8
n6-->n8
n7-->n8
n8-->na
n9-->n0
na-->n0
na-->n4
na-->nc

各リソースと値を、種類ごとに subgraph にまとめ、スタイルを適用して、リソースを強調します。

%%tfmermaid
%%{init:{"theme":"default","themeVariables":{"lineColor":"#6f7682","textColor":"#6f7682"}}}%%
flowchart LR
classDef r fill:#5c4ee5,stroke:#444,color:#fff
classDef v fill:#eeedfc,stroke:#eeedfc,color:#5c4ee5
classDef ms fill:none,stroke:#dce0e6,stroke-width:2px
classDef vs fill:none,stroke:#dce0e6,stroke-width:4px,stroke-dasharray:10
classDef ps fill:none,stroke:none
classDef cs fill:#f7f8fa,stroke:#dce0e6,stroke-width:2px
subgraph "n0"["ELB Classic"]
n1["aws_elb.web"]:::r
end
class n0 cs
subgraph "n2"["EC2 (Elastic Compute Cloud)"]
n3["aws_instance.web"]:::r
n4["aws_key_pair.auth"]:::r
end
class n2 cs
subgraph "n5"["VPC (Virtual Private Cloud)"]
n6["aws_internet_gateway.default"]:::r
n7["aws_route.internet_access"]:::r
n8["aws_security_group.default"]:::r
n9["aws_security_group.elb"]:::r
na["aws_subnet.default"]:::r
nb["aws_vpc.default"]:::r
end
class n5 cs
subgraph "nc"["Output Values"]
nd(["output.address"]):::v
end
class nc vs
ne[/"provider<br/>[&quot;registry.terraform.io/hashicorp/aws&quot;]"\]
subgraph "nf"["Input Variables"]
ng(["var.aws_amis"]):::v
nh(["var.aws_region"]):::v
ni(["var.key_name"]):::v
nj(["var.public_key_path"]):::v
end
class nf vs
n1-->n3
n1-->n9
n3-->n4
n3-->n8
n3-->na
n3--->ng
n6-->nb
n4-->ne
n4--->ni
n4--->nj
n7-->n6
n8-->nb
n9-->nb
na-->nb
nb-->ne
nd--->n1
ne-->n1
ne-->n7
ne--->nh

provider は 1 個しかなく、役割は自明なので省略します。

%%tfmermaid
%%{init:{"theme":"default","themeVariables":{"lineColor":"#6f7682","textColor":"#6f7682"}}}%%
flowchart LR
classDef r fill:#5c4ee5,stroke:#444,color:#fff
classDef v fill:#eeedfc,stroke:#eeedfc,color:#5c4ee5
classDef ms fill:none,stroke:#dce0e6,stroke-width:2px
classDef vs fill:none,stroke:#dce0e6,stroke-width:4px,stroke-dasharray:10
classDef ps fill:none,stroke:none
classDef cs fill:#f7f8fa,stroke:#dce0e6,stroke-width:2px
subgraph "n0"["ELB Classic"]
n1["aws_elb.web"]:::r
end
class n0 cs
subgraph "n2"["EC2 (Elastic Compute Cloud)"]
n3["aws_instance.web"]:::r
n4["aws_key_pair.auth"]:::r
end
class n2 cs
subgraph "n5"["VPC (Virtual Private Cloud)"]
n6["aws_internet_gateway.default"]:::r
n7["aws_route.internet_access"]:::r
n8["aws_security_group.default"]:::r
n9["aws_security_group.elb"]:::r
na["aws_subnet.default"]:::r
nb["aws_vpc.default"]:::r
end
class n5 cs
subgraph "nc"["Output Values"]
nd(["output.address"]):::v
end
class nc vs
subgraph "ne"["Input Variables"]
nf(["var.aws_amis"]):::v
ng(["var.aws_region"]):::v
nh(["var.key_name"]):::v
ni(["var.public_key_path"]):::v
end
class ne vs
n1-->n3
n1-->n9
n3-->n4
n3-->n8
n3-->na
n3--->nf
n6-->nb
n4--->nh
n4--->ni
n7-->n6
n8-->nb
n9-->nb
na-->nb
nd--->n1

矢印は、依存元から依存先を指しているのですが、値の代入元から代入先を向くほうが直感的なので、逆にします。

%%tfmermaid
%%{init:{"theme":"default","themeVariables":{"lineColor":"#6f7682","textColor":"#6f7682"}}}%%
flowchart LR
classDef r fill:#5c4ee5,stroke:#444,color:#fff
classDef v fill:#eeedfc,stroke:#eeedfc,color:#5c4ee5
classDef ms fill:none,stroke:#dce0e6,stroke-width:2px
classDef vs fill:none,stroke:#dce0e6,stroke-width:4px,stroke-dasharray:10
classDef ps fill:none,stroke:none
classDef cs fill:#f7f8fa,stroke:#dce0e6,stroke-width:2px
subgraph "n0"["ELB Classic"]
n1["aws_elb.web"]:::r
end
class n0 cs
subgraph "n2"["EC2 (Elastic Compute Cloud)"]
n3["aws_instance.web"]:::r
n4["aws_key_pair.auth"]:::r
end
class n2 cs
subgraph "n5"["VPC (Virtual Private Cloud)"]
n6["aws_internet_gateway.default"]:::r
n7["aws_route.internet_access"]:::r
n8["aws_security_group.default"]:::r
n9["aws_security_group.elb"]:::r
na["aws_subnet.default"]:::r
nb["aws_vpc.default"]:::r
end
class n5 cs
subgraph "nc"["Output Values"]
nd(["output.address"]):::v
end
class nc vs
subgraph "ne"["Input Variables"]
nf(["var.aws_amis"]):::v
ng(["var.aws_region"]):::v
nh(["var.key_name"]):::v
ni(["var.public_key_path"]):::v
end
class ne vs
n3-->n1
n9-->n1
n4-->n3
n8-->n3
na-->n3
nf--->n3
nb-->n6
nh--->n4
ni--->n4
n6-->n7
nb-->n8
nb-->n9
nb-->na
n1--->nd

左から、リソースが作成されていく流れが俯瞰しやすくなったように思います。Terraform 設定ファイルを含む Github リポジトリにおいて、次のとおりに Github Action を使用することで、このようなグラフが自動的に README.md ファイルに埋め込まれます。

github.com

  • 下記の内容の .github/workflows/tfmermaid.yml ファイルを作成する
name: tfmermaid
on:
  push:
jobs:
  generate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: asannou/tfmermaid-action@v1
        with:
          file: README.md
      - name: commit
        run: |
          git add README.md
          if ! git diff --cached --quiet --exit-code
          then
            git config user.name "github-actions[bot]"
            git config user.email "github-actions[bot]@users.noreply.github.com"
            git commit -m "generated"
            git push
          fi
  • README.md ファイルの埋め込む場所に %%tfmermaid とコメントされた mermaid コードブロックを配置する
 ```mermaid
 %%tfmermaid
 ```

状況に合わせて、provider を表示したり、var 等を省略したり、矢印を順方向にしたり、グラフ全体の向き を変更する等のオプションも用意しています。

      - uses: asannou/tfmermaid-action@v1
        with:
          file: README.md
          include: provider
          exclude: var,local,output,data
          arrow-direction: forward
          orientation: RL

その他の例は https://github.com/asannou/tfmermaid-action/blob/v1/README.md#examples で確認してください。