Pythonでクラウドのシステム構成図が書ける「Diagrams」を試す
GitHubレポジトリ
Diagrams
Diagrams as Code.
DiagramsはPythonコードでクラウドシステムアーキテクチャを描画することができます。新しいシステムアーキテクチャのデザインをプロトタイプするために生まれたツールで、デザインツールを使わずに済みます。また、既存のシステムアーキテクチャを記述したり視覚化することも可能です。Diagramsは現在、主要なプロバイダーをサポートしており、AWS、Azure、GCP、Kubernetes、Alibaba Cloud、Oracle Cloudなどが含まれます。また、オンプレミスノード、SaaS、主要なプログラミングフレームワークや言語もサポートしています。
「コードとしてのダイアグラム」により、アーキテクチャダイアグラムの変更を任意のバージョン管理システムで追跡することができます。
注意: このツールは実際のクラウドリソースを管理するものではなく、クラウドフォーメーションやTerraformコードを生成するわけでもありません。クラウドシステムアーキテクチャ図の作成のみに使用されます。
プロバイダー
- AWS
- Azure
- GCP
- IBM
- Kubernetes
- Alibaba Cloud
- Oracle Cloud
- OpenStack
- Firebase
- Digital Ocean
- Elastic
- Outscale
- オンプレミス
- ジェネリック
- プログラミング
- SaaS
- C4
公式ドキュメント
全然知らなかった・・・
Colaboratoryで。
要件
- Python-3.7以上
- Graphviz
Getting Started
パッケージインストール
!pip install diagrams
!pip freeze | grep diagrams
diagrams==0.23.4
サンプル。
from diagrams import Diagram
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
from diagrams.aws.network import ELB
with Diagram("web_service", show=False) as diag:
ELB("lb") >> EC2("web") >> RDS("userdb")
diag
おー、簡単
Diagramsクラス
Diagramクラスがグローバルなコンテキストになり、最初の引数が図のタイトルかつファイル名になる。
from diagrams import Diagram
from diagrams.aws.compute import EC2
with Diagram("Simple Diagram"):
EC2("web")
simple_diagram.png
というファイル名で出力されるので、これを表示。
from IPython.display import Image
display(Image('simple_diagram.png'))
ただし、ColaboratoryやJupyterの場合、上記のようにファイルを使ってセルに表示しなくても、以下で表示できる。
with Diagram("Simple Diagram") as diag:
EC2("web")
diag
その他のオプション
-
outformat
- 出力するファイル形式。
jpg
/png
/svg
/pdf
/dot
(Graphvizで使用される形式らしい)から選択できる。デフォルトはpng
。 - 配列で渡すとそれぞれの形式で出力することができる
- 出力するファイル形式。
-
filename
- 出力するファイル名を明示的に指定する。
- 拡張子は含めずに指定する。
-
show
- 自動でファイルを開くかどうか?
- ちょっとここは違いが確認できなかった。
-
graph_attr
/node_attr
/edge_attr
- Graphvizの属性のカスタマイズを指定。リファレンスはこちら。
全部指定するとこんな感じ。
from diagrams import Diagram
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
from diagrams.aws.network import ELB
graph_attr = {
"fontsize": "45",
"bgcolor": "grey"
}
node_attr = {
"fontsize": "20",
"fontcolor": "blue"
}
edge_attr = {
"color": "red"
}
with Diagram(
"Three Tier Architecture",
outformat=["png", "jpg"],
filename="tta",
show=False,
graph_attr=graph_attr,
node_attr=node_attr,
edge_attr=edge_attr,
) as diag:
ELB("LB") >> EC2("web") >> RDS("DB")
diag
!ls -lt tta*
-rw-r--r-- 1 root root 32705 Nov 4 08:57 tta.jpg
-rw-r--r-- 1 root root 41381 Nov 4 08:57 tta.png
ノード
ノードは個々のコンポーネントを表す。ノードは以下のように、プロバイダ・リソースタイプ・ノード名で呼び出す。
from diagrams.aws.compute import EC2
~~~ ~~~~~~~ ~~~
| | |
| | ノード名
| リソースタイプ
プロバイダ
例えば、Kubernetesだとこうなる
from diagrams import Diagram
from diagrams.k8s.compute import Pod, Deploy, RS
from diagrams.k8s.network import Service
with Diagram("K8S") as diag:
Service("Service") >> Deploy("Deployment") >> RS("ReplicaSet") >> [Pod("pod"),
Pod("pod")]
diag
上で少し使っているけども、ノード間をつなぐエッジは>>
/ <<
/ -
で表現する。
from diagrams import Diagram
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
with Diagram("Web Services", show=False) as diag:
EC2("Web1") >> RDS("DB") << EC2("Web2")
diag
with Diagram("Web Services", show=False) as diag:
EC2("Web1") - RDS("DB") - EC2("Web2")
diag
ただし、以下はちょっと想定と異なる動きになる。
from diagrams import Diagram
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
from diagrams.aws.network import ELB
with Diagram("Web Services", show=False) as diag:
ELB("LB") >> EC2("Web1") - RDS("DB") << EC2("Web2")
diag
-
(マイナス演算子)とシフト演算子を一緒に使用する際には、演算子の優先順位によって予期しない結果を引き起こす可能性があるため注意してください。
なるほど、記号的にイメージしてしまうけど、ここはあくまでも演算子なのね。こう書けば良い。
with Diagram("Web Services", show=False) as diag:
(ELB("LB") >> EC2("Web1")) - RDS("DB") << EC2("Web2")
diag
あと、
with Diagram("Web Services", show=False) as diag:
ELB("LB") >> EC2("Web1") >> RDS("DB")
RDS("DB") << EC2("Web1") << ELB("LB")
diag
複数の図を列挙した場合、出力は記載した順序とは逆になる。
あと、データの流れの方向を指定できる。これはノード、というかDiagramクラスのオプションだな。
with Diagram("Web Services", direction="TB") as diag:
ELB("LB") >> EC2("Web1") >> RDS("DB")
diag
指定できる方向は以下。
-
LR
(Left → Right) ※デフォルト -
RL
(Right → Left) -
TB
(Top → Bottom) -
BT
(Bottom → Top)
フローのグルーピングは配列的に指定する。
with Diagram("Web Services", direction="TB") as diag:
ELB("LB") >> [EC2("Web1"),
EC2("Web2"),
EC2("Web3")] >> RDS("DB")
diag
ただし、グルーピング同士を接続することはできない。例えばこう。
with Diagram("Web Services", direction="TB") as diag:
ELB("LB") >> [EC2("Web1"),
EC2("Web2"),
EC2("Web3")] >> [RDS("Primary"), RDS("Replica")]
diag
TypeError: unsupported operand type(s) for >>: 'list' and 'list'
ドキュメントにも書いてある
Pythonでは、リスト同士を直接結合することはできません。リスト間でのシフトや算術演算は許可されていないためです。
例えばこういう回避策はできそう
with Diagram("Web Services", direction="TB") as diag:
elb = ELB("LB")
web1 = EC2("Web1")
web2 = EC2("Web2")
web3 = EC2("Web3")
db_primary = RDS("Primary")
db_replica = RDS("Replica")
elb >> [web1, web2, web3]
web1 >> [db_primary, db_replica]
web2 >> [db_primary, db_replica]
web3 >> [db_primary, db_replica]
diag
ノードのインスタンスを作成して、それをエッジで明示的につなぐ感じ
クラスタ
ノードをグループとしてクラスタリングするには、with Cluster()
でDiagramクラスの中にコンテキストを追加する。
from diagrams import Cluster, Diagram
from diagrams.aws.network import ELB
from diagrams.aws.compute import EC2
with Diagram("Auto Scaling Group") as diag:
with Cluster("Auto Scaling Group"):
web_asg = [EC2("Web1"),
EC2("Web2"),
EC2("Web3")]
ELB("LB") >> web_asg
diag
もうちょっと複雑にしてみるとこんな感じ。
from diagrams import Cluster, Diagram
from diagrams.aws.network import ELB
from diagrams.aws.compute import EC2
with Diagram("Auto Scaling Group + DB Cluster") as diag:
with Cluster("Auto Scaling Group"):
web_asg = [EC2("Web1"),
EC2("Web2"),
EC2("Web3")]
with Cluster("DB Cluster"):
db_primary = RDS("Primary")
db_primary - [RDS("replica1"),
RDS("replica2")]
ELB("LB") >> web_asg >> db_primary
diag
クラスタはネストさせることもできる。
from diagrams import Cluster, Diagram
from diagrams.aws.network import ELB
from diagrams.aws.compute import EC2
with Diagram("Inside VPC") as diag:
with Cluster("VPC"):
with Cluster("Public Subnet"):
elb = ELB("LB")
with Cluster("Private Subnet"):
with Cluster("Auto Scaling Group"):
web_asg = [EC2("Web1"),
EC2("Web2"),
EC2("Web3")]
elb >> web_asg
diag
エッジ
ノード間のエッジに以下のプロパティを付与することができる。
- ラベル
- 色
- スタイル
例えば以下の例
from diagrams import Cluster, Diagram
from diagrams.aws.network import ELB
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
with Diagram("Web Services", direction="LR") as diag:
with Cluster("VPC"):
with Cluster("Public Subnet"):
elb = ELB("LB")
with Cluster("Private Subnet 1"):
web1 = EC2("Web1")
web2 = EC2("Web2")
web3 = EC2("Web3")
with Cluster("Private Subnet 2"):
db_primary = RDS("Primary")
db_replica = RDS("Replica")
elb >> [web1, web2, web3]
web1 >> [db_primary, db_replica]
web2 >> [db_primary, db_replica]
web3 >> [db_primary, db_replica]
diag
このエッジにいろいろプロパティを付与してみる。
from diagrams import Cluster, Diagram, Edge
from diagrams.aws.network import ELB
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
with Diagram("Web Services", direction="LR") as diag:
with Cluster("VPC"):
with Cluster("Public Subnet"):
elb = ELB("LB")
with Cluster("Private Subnet 1"):
web1 = EC2("Web1")
web2 = EC2("Web2")
web3 = EC2("Web3")
with Cluster("Private Subnet 2"):
db_primary = RDS("Primary")
db_replica = RDS("Replica")
elb >> Edge(color="blue", label="balancing", style="dotted") >> [web1, web2, web3]
[web1, web2, web3] >> Edge(color="red", label="WRITE", style="bold") >> db_primary
[web1, web2, web3] >> Edge(color="darkgreen", label="READ", style="dashed") >> db_replica
diag
まとめ
コードで管理できるってのが最大のメリットかな、あとアイコンが用意されてるのできれい。
ただ、自在に書くにはひと手間いるかなぁ。個人的にこういう構成図、設計段階ではある程度考えながら試行錯誤して整理したい感があるので、ドローツールを使って書いて、どっちかというと実装段階以降である程度固まってから記録として残していくという使い方のほうが有用な感を持った。
Diagramsをうまく使うには、ノードを全部インスタンスにしておいて、エッジでチマチマつなげるってのが、一番自由度は高そうな気がした。一番最後の例がそれ。