Diagramsを使ってサクッとインフラ図を描く【Python】
Diagramsの基本
PythonライブラリのDiagramsを使うと、こんな感じのインフラ図がサクッと描ける。
ソースコード
sample1.py
from diagrams import Cluster, Diagram, Edge
from diagrams.generic.os import Raspbian
from diagrams.onprem.client import User
from diagrams.onprem.network import Nginx
from diagrams.programming.framework import Flask
from diagrams.programming.language import Python
with Diagram("基本", show=False, outformat="png", filename="../sample1"):
user_request = User("User Request")
with Cluster(label="Raspberry Pi"):
nginx = Nginx("Nginx Server")
with Cluster("REST API", direction="TB"):
flask = Flask("Flask")
python = Python("Application")
user_request >> Edge(label="80 port") >> nginx >> Edge(label="Proxy\n5000 port") >> flask
Diagramsをpipでインストールしておく
Diagramsはpipパッケージで配布されている。Python3で使うので、pip3でインストールする:
zsh
pip3 install Diagrams
画像の余白を狭くする
デフォルトの画像出力だと、余白が広すぎる。Graphviz がバックエンドとして使用されているので、Graphviz の属性を調整して余白を変更することができる:
ソースコード
sample2.py
from diagrams import Cluster, Diagram, Edge
from diagrams.generic.os import Raspbian
from diagrams.onprem.client import User
from diagrams.onprem.network import Nginx
from diagrams.programming.framework import Flask
from diagrams.programming.language import Python
with Diagram("基本", show=False, outformat="png", filename="../sample2", direction="LR", graph_attr={"pad":"0.2,0.2"}):
user_request = User("User Request")
with Cluster(label="Raspberry Pi"):
nginx = Nginx("Nginx Server")
with Cluster("REST API", direction="TB"):
flask = Flask("Flask")
python = Python("Application")
user_request >> Edge(label="80 port") >> nginx >> Edge(label="Proxy\n5000 port") >> flask
複雑なリレーション図もDiagramsで描ける
ソースコード
c4.py
from diagrams import Diagram
from diagrams.c4 import Person, Container, Database, System, SystemBoundary, Relationship
graph_attr = {
"splines": "spline",
"pad":"0.2,0.2",
}
with Diagram("複雑な図", show=False, outformat="png", filename="../c4", direction="TB", graph_attr=graph_attr):
customer = Person(
name="Personal Banking Customer", description="A customer of the bank, with personal bank accounts."
)
with SystemBoundary("Internet Banking System"):
webapp = Container(
name="Web Application",
technology="Java and Spring MVC",
description="Delivers the static content and the Internet banking single page application.",
)
spa = Container(
name="Single-Page Application",
technology="Javascript and Angular",
description="Provides all of the Internet banking functionality to customers via their web browser.",
)
mobileapp = Container(
name="Mobile App",
technology="Xamarin",
description="Provides a limited subset of the Internet banking functionality to customers via their mobile device.",
)
api = Container(
name="API Application",
technology="Java and Spring MVC",
description="Provides Internet banking functionality via a JSON/HTTPS API.",
)
database = Database(
name="Database",
technology="Oracle Database Schema",
description="Stores user registration information, hashed authentication credentials, access logs, etc.",
)
email = System(name="E-mail System", description="The internal Microsoft Exchange e-mail system.", external=True)
mainframe = System(
name="Mainframe Banking System",
description="Stores all of the core banking information about customers, accounts, transactions, etc.",
external=True,
)
customer >> Relationship("Visits bigbank.com/ib using [HTTPS]") >> webapp
customer >> Relationship("Views account balances, and makes payments using") >> [spa, mobileapp]
webapp >> Relationship("Delivers to the customer's web browser") >> spa
spa >> Relationship("Make API calls to [JSON/HTTPS]") >> api
mobileapp >> Relationship("Make API calls to [JSON/HTTPS]") >> api
api >> Relationship("reads from and writes to") >> database
api >> Relationship("Sends email using [SMTP]") >> email
api >> Relationship("Makes API calls to [XML/HTTPS]") >> mainframe
customer << Relationship("Sends e-mails to") << email
よく使うアイコン
ソースコード
favorite.py
from diagrams import Cluster, Diagram, Edge
from diagrams.onprem.client import User
from diagrams.onprem.client import Client
from diagrams.onprem.client import Users
from diagrams.onprem.database import Mysql
from diagrams.onprem.certificates import LetsEncrypt
from diagrams.onprem.network import Nginx
from diagrams.onprem.vcs import Github
from diagrams.firebase.base import Firebase
from diagrams.generic.device import Mobile
from diagrams.generic.device import Tablet
from diagrams.generic.network import Firewall
from diagrams.generic.network import Router
from diagrams.generic.network import VPN
from diagrams.generic.os import Android
from diagrams.generic.os import IOS
from diagrams.generic.os import Raspbian
from diagrams.generic.os import Ubuntu
from diagrams.generic.os import Windows
from diagrams.generic.place import Datacenter
from diagrams.generic.storage import Storage
from diagrams.programming.flowchart import Action
from diagrams.programming.flowchart import Database
from diagrams.programming.flowchart import Decision
from diagrams.programming.framework import Flask
from diagrams.programming.framework import Laravel
from diagrams.programming.language import Bash
from diagrams.programming.language import C
from diagrams.programming.language import Cpp
from diagrams.programming.language import Java
from diagrams.programming.language import Javascript
from diagrams.programming.language import Kotlin
from diagrams.programming.language import Latex
from diagrams.programming.language import Nodejs
from diagrams.programming.language import Php
from diagrams.programming.language import Python
from diagrams.programming.language import Swift
from diagrams.saas.cdn import Cloudflare
from diagrams.saas.chat import Discord
from diagrams.saas.chat import Line
from diagrams.saas.chat import Slack
with Diagram("よく使うノードアイコン", show=False, outformat="png", filename="../favorite", direction="LR", graph_attr={"pad":"0.2,0.2"}):
with Cluster("OnPrem"):
user_request = User("User")
users = Users("Users")
client = Client("Client")
mysql = Mysql("MySQL")
nginx = Nginx("Nginx")
letsEncrypt = LetsEncrypt("LetsEncrypt")
github = Github("Github")
user_request - users - client - mysql - nginx - letsEncrypt - github
with Cluster("Firebase"):
firebase = Firebase("Firebase")
with Cluster("Generic"):
mobile = Mobile("Mobile")
tablet = Tablet("Tablet")
raspbian = Raspbian("Raspbian")
ubuntu = Ubuntu("Ubuntu")
windows = Windows("Windows")
ios = IOS("iOS")
android = Android("Android")
datacenter = Datacenter("Datacenter")
storage = Storage("Storage")
router = Router("Router")
firewall = Firewall("Firewall")
vpn = VPN("VPN")
mobile - tablet - raspbian - ubuntu - windows - ios - android - datacenter - storage - router - firewall - vpn
with Cluster("Programming"):
action = Action("Action")
database = Database("Database")
decision = Decision("Decision")
flask = Flask("Flask")
laravel = Laravel("Laravel")
bash = Bash("Bash")
c = C("C")
cpp = Cpp("C++")
java = Java("Java")
javascript = Javascript("Javascript")
kotlin = Kotlin("Kotlin")
latex = Latex("Latex")
nodejs = Nodejs("Nodejs")
php = Php("PHP")
python = Python("Python")
swift = Swift("Swift")
action - database - decision - flask - laravel - bash - c - cpp - java - javascript - kotlin - latex - nodejs - php - python - swift
with Cluster("SaaS"):
cloudflare = Cloudflare("Cloudflare")
discord = Discord("Discord")
line = Line("Line")
slack = Slack("Slack")
cloudflare - discord - line - slack
他にもたくさんアイコン画像が公開されている:
オリジナル画像を入れる
GitHub - mingrammer/diagrams: :art: Diagram as Code for prototyping cloud system architectures
ソースコード
original.py
import os
from diagrams import Diagram, Edge
from diagrams.custom import Custom
# 現在のファイルのディレクトリを取得
current_dir = os.path.dirname(__file__)
# 画像ファイルへのパスを組み立てる
arduino_image_path = os.path.join(current_dir, "computer_one-board_microcomputer.png")
watering_image_path = os.path.join(current_dir, "watering-can.png")
plant_image_path = os.path.join(current_dir, "plant.png")
with Diagram("オリジナル画像を表示する", show=False, outformat="png", filename="../original", direction="LR", graph_attr={"pad":"0.2,0.2"}):
arduino = Custom("Arduino", arduino_image_path)
watering = Custom("Watering", watering_image_path)
plant = Custom("Plant", plant_image_path)
watering << Edge(label="Control") << arduino
plant >> Edge(label="Notification") >> arduino
【注意】 画像を上の階層へ出力する場合、絶対パスでないと画像が表示されなかったため気をつけること。
関連記事
アイデアノート > シェル・Python