サイトロゴ

Diagramsを使ってサクッとインフラ図を描く【Python】

著者画像
Toshihiko Arai

Diagramsの基本

PythonライブラリのDiagramsを使うと、こんな感じのインフラ図がサクッと描ける。

ソースコード

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でインストールする:

pip3 install Diagrams

画像の余白を狭くする

デフォルトの画像出力だと、余白が広すぎる。Graphviz がバックエンドとして使用されているので、Graphviz の属性を調整して余白を変更することができる:

ソースコード

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で描ける

ソースコード

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

よく使うアイコン

ソースコード

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

他にもたくさんアイコン画像が公開されている: - Diagrams Docs

オリジナル画像を入れる

https://github.com/mingrammer/diagrams/

ソースコード

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

【注意】 画像を上の階層へ出力する場合、絶対パスでないと画像が表示されなかったため気をつけること。


関連記事