Diagram as Code を触ってみる
Python のコードで様々なアーキテクチャ図を描く(= Diagram as Code)ことができる Diagrams というツールを見つけたので触ってみます。
Diagrams について
https://diagrams.mingrammer.com/
Diagrams は Python のコードで様々なアーキテクチャやワークフローの図を描くことができるライブラリです。
作図といえば draw.io や Lucidchart などの GUI ツールが有名なように思います。私もちょうど最近、AWS でのWebアプリケーションのインフラ構成図を作る機会があり draw.io を使いました。直感的で使いやすく自由度の高い GUI ツールですが、それだけにコンポーネントの配置やサイズ調整、接続の作成を進めるうちに細かい調整に気を取られて意外と時間がかかってしまったことに気付きました。そこで、コードでこういう図を作れないかなと思っていたところ Diagrams を見つけたので、今回試してみることにしました。
インストール
https://diagrams.mingrammer.com/docs/getting-started/installation
公式ドキュメントにインストールガイドがあります。Diagrams は Python ライブラリなので、pip や poetry で簡単にインストールできます。
poetry new diagrams-as-code
poetry add diagrams
図を描いていく
サンプルのアーキテクチャを考える
インストールが完了したので早速作図を試してみたいと思います。ここでは AWS を利用した一般的な SPA ウェブアプリケーションを想定して以下のような構成を考えてみました。
- Route 53 を使用してドメイン管理とDNSルーティングを行う
- ACM で SSL/TLS 証明書を発行する
- ALB(Application Load Balancer)に証明書を紐付け、ユーザーと ALB 間の HTTPS 通信をサポートする
- CloudFront にも証明書を紐付け、ユーザーと CloudFront 間の HTTPS 通信をサポートする
- CloudFront には WAF を適用し、セキュリティを強化する
- S3 にフロントエンドのコードを配置し静的ウェブホスティングを行い、CloudFront を通じてキャッシュ配信を行う
- ECS Fargate を利用し、プライベートサブネットにバックエンドサービスを配置する
- 同じくプライベートサブネットに RDS データベースを配置し、バックエンドサービスから接続する
- パブリックサブネットに ALB を配置し、バックエンドサービスへトラフィックをルーティングする
適度な数のコンポーネントがありサブネットなども登場するので、図示しがいがありそうです。
コンポーネントを並べる
アーキテクチャの想定を通して必要なコンポーネントが分かったので、まずは単にそれらを図上に並べてみます。
from diagrams import Diagram
from diagrams.aws.compute import ECS, Fargate
from diagrams.aws.database import RDS
from diagrams.aws.general import User
from diagrams.aws.network import ALB, CloudFront, Route53
from diagrams.aws.security import WAF, ACM
from diagrams.aws.storage import S3
with Diagram("Components", direction="TB"):
User("User")
Route53("DNS")
ACM("Certificate for CDN")
ACM("Certificate for ALB")
ALB("ALB")
CloudFront("CloudFront CDN")
WAF("WAF")
S3("S3 Bucket")
ECS("ECS")
Fargate("ECS Fargate")
Fargate("ECS Fargate")
Fargate("ECS Fargate")
RDS("RDB")
python diagrams.py
作図に利用するコンポーネントは Python クラスとして定義されています。必要なものをインポートしインスタンスを作成することで、コンポーネントが図示された画像を生成することができます。Diagram
がルートのコンポーネントとなり、その中にコンポーネントを配置していくイメージです。コードの通り、必要なサービスの名前を並べていくだけなのでとても簡単です。
今回は AWS サービスのみを使っていますが、そのほかにも様々なクラウドサービスやソフトウェアの図が用意されていますし、Custom
というクラスを使うと画像ファイルを使って独自の図を組み込むこともできます。公式ドキュメントに記載がありますので興味があればそちらも参照してみてください。
コンポーネントを接続する
それでは次に、接続線を使ってコンポーネント同士の関係性を図示してみます。今回はユーザーのトラフィックが流れていく様子を矢印で表現したいと思います。
with Diagram("Connecting Components"):
user = User('User')
dns = Route53("DNS")
lb = ALB("ALB")
worker1 = Fargate("ECS Fargate")
worker2 = Fargate("ECS Fargate")
worker3 = Fargate("ECS Fargate")
db = RDS("RDB")
s3Bucket = S3("S3 Bucket")
cdn = CloudFront("CloudFront CDN")
waf = WAF("WAF")
cdnCert = ACM("Certificate for CDN")
lbCert = ACM("Certificate for ALB")
user >> dns
dns >> lb
dns >> waf >> cdn
lb >> [worker1, worker2, worker3] >> db
lbCert >> lb
cdn >> s3Bucket
cdnCert >> cdn
コードから見て取れるように図の要素は Python クラスのインスタンスであるため、変数に格納することができます。
dns >> waf >> cdn
そして上記のように演算子 >>
でつなぐことで要素間に矢印を引くことができます。ここでは使っていませんが、-
でつなげば直線を描けますし、Edge
クラスを利用すると線色の変更などのカスタマイズが可能です。詳細は公式ドキュメントを参照してみてください。
先ほどまでは、単にコンポーネントが一列に並んでいるだけでしたが、接続線を追加することで要素の配置が変わったことが分かります。コンポーネントのツリー構造に従って自動配置されている関係で少し歪な見た目になっていますが、線を追うことでユーザーのトラフィックの流れを把握することができるようになりました。
コンポーネントをグループ化する
仕上げとして、インフラ構成要素の配置場所や要素同士の関連性をより分かりやすくするためにグループ化を利用してみます。Diagrams ではこれを Cluster
クラスで表現できます。
with Diagram(name := "Grouping Components", filename=format_name(name), outformat="png", show=False):
user = User('User')
with Cluster("AWS"):
dns = Route53("DNS")
s3Bucket = S3("S3 Bucket")
waf = WAF("WAF")
with Cluster("CDN"):
cdn = CloudFront("CloudFront CDN")
cdnCert = ACM("Certificate for CDN")
with Cluster("VPC"):
with Cluster("Public Subnet"):
with Cluster("Load Balancer"):
lb = ALB("ALB")
lbCert = ACM("Certificate for ALB")
with Cluster("Private Subnet"):
with Cluster("ECS Cluster"):
workers = [Fargate("ECS Fargate") for _ in range(3)]
db = RDS("RDB")
user >> dns
dns >> Edge(color="purple", label="backend") >> lb
dns >> Edge(color="invis") >> lbCert
lb >> Edge(color="darkorange", label="traffic routing") >> workers
lbCert >> Edge(color="invis") >> workers
workers >> Edge(color="darkblue") >> db
dns >> Edge(color="purple", label="frontend") >> cdn
cdn >> Edge(color="darkgreen", label="static site hosting") >> s3Bucket
cdn - Edge(color="darkred", label="protection") - waf
コードが少しだけ複雑になっていますが、グループ化によりアーキテクチャの各要素の関連性がより分かりやすくなり、全体像を俯瞰しやすくなったように思います。Diagrams の特徴として、with
文を使うことで Diagram
や Cluster
の中に要素を配置するという概念をコードで分かりやすく表現できていてよいなと感じました。図の正体は Python のコードなので、for
文などを使ってコンポーネントを簡潔に作成・管理できるのもいいですね。
またここでは Cluster
の利用に加えて、見た目の調節として以下の点も工夫してみました。
Edge
の色分けによる意味的な分類Edge
のラベルによる説明の追加Edge(color="invis")
で透明線を使ったコンポーネントの配置調整
実験目的のため、グループ化や色分けを必要以上に多用している部分はあるものの、2つ目の図に比べてかなり見やすくなったのではないでしょうか。
使ってみて感じたメリット・デメリット
一通り図を作成することができたので、ここで Diagrams を触ってみて率直に感じたメリット・デメリットをまとめておきます。
メリット
- 使いたいクラウドサービスの名前さえ知っていれば、Python のコードですぐ図に組み込める
- コードで書くことで要素の作成が冗長になりにくく、管理しやすい
- 自動配置により考えることが少なくなるので、素早くアーキテクチャ図を作成でき、再現性も高い
- クラスターが自動で色分けされたりエッジのカスタマイズができたりするので、ある程度整った見た目を作れる
デメリット
- 図の作成には Python 環境が必要になる
- 自動配置の利便性の反面、細かな調節は難しく、見やすく図示するために工夫が必要なこともある
全体としてはシンプルでいいツールだと感じました。特にやはり自動配置によるメリットが大きく、個人的には最近描いた AWS インフラ構成図についてもこれを使えばもっと速く作れたなと思っています。
ただ、シンプルで使いやすいツールであるがゆえに、細かい調節は得意ではないようです。今回の私の図でも透明線による配置調整(Edge(color="invis")
)を行いましたが、場合によっては納得のいく図を得るためにそのような追加の工夫が必要になることもありそうです。
したがって Diagrams は、複雑で包括的なアーキテクチャではなく、単一の目的やワークフローの流れを可視化するための図を素早く作成したいという場合にこそ大きなメリットを発揮するツールなのではないかと思いました。
まとめ
簡単にではありますが今回 Diagrams を使って一通り作図してみて、個人的にはとても気に入りました。可視化したいアーキテクチャがあるときに GUI ツールを使うのも悪くないですが、作っているうちに細かいところが気になってきて必要以上に時間を使ってしまうこともあるかと思います。そんな時にこのツールであれば迷いなく素早く作図できるような気がしました。
なので次回何かしらクラウドサービスなどを使ったシステムやワークフローを設計する際にも Diagrams を使ってみようかなと思います。
ご覧いただきありがとうございました。