PythonコードでサクッとAWS構成図を描く ※Fargate構成、Lambdaサーバーレス構成など

## 概要
PythonコードでAWS構成図を作成する記事となります❗❗❗
具体的には、[コードベースのDiagramsライブラリ](https://github.com/mingrammer/diagrams)を使って、下記AWS構成図を作成しております。
1. **Fargate構成図**
2. **Lambdaサーバーレス構成図**
3. **その他構成図**

コードベースで使用するDiagramsライブラリの概要は、下記記事が参考になります
- [GitHub_コードベースのDiagramsライブラリ](https://github.com/mingrammer/diagrams)
- [DevelopersIO_Diagramsを使ってPythonでシステム構成図を描く](https://dev.classmethod.jp/articles/diagrams-introduction/)

また、本記事は自身のスキルを証明する一つの材料として執筆しております。

:::note warn
本記事は下記のサービスにて公開しております。公開日時：2025年01月03日
複数のプラットフォームで発信することで、多くの方にご覧いただき、少しでも参考になれば幸いです。
- Zenn
- Qiita
- Twitter
- LinkedIn
- Findy
- Forkwell
- LAPRAS
- 職務経歴書のレジュメ
- etc
:::


## 1. Fargate構成図
### 構成図
![fargate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967556/96be79fc-86da-2487-eb20-cef00bd7ebc5.png)

### Pythonコード
```code:Python
from diagrams import Diagram, Cluster
from diagrams.onprem.client import User as HumanUser, Client as PC
from diagrams.aws.network import Route53, ALB
from diagrams.aws.security import CertificateManager
from diagrams.aws.compute import Fargate
from diagrams.aws.database import RDS
from diagrams.aws.network import VPC
from diagrams.custom import Custom

# 既存のローカルPCクラスター表示用スタイル（必要に応じてご利用ください）
local_pc_graph_attr = {
    "bgcolor": "transparent",  # 背景色なし
    "pencolor": "silver",  # シルバーの枠線
    "penwidth": "1",
}

with Diagram("PythonコードでサクッとAWS構成図を描く ※Fargate構成", show=False):
    # ユーザ & ローカルPC
    human_user = HumanUser("User")
    local_pc = PC("ローカルPC")

    # AWSクラウド枠
    with Cluster(
        "AWSクラウド",
        graph_attr={
            "bgcolor": "transparent",
            "pencolor": "orange",
            "penwidth": "1",
        },
    ):
        # DNS, ACM は再利用
        r53 = Route53("DNS")
        acm = CertificateManager("ACM")

        # VPC クラスタ
        with Cluster(
            "VPC",
            graph_attr={
                "bgcolor": "transparent",
                "pencolor": "#248814",  # 緑色
                "penwidth": "1",
            },
        ):
            # ALB
            alb = ALB("ALB")

            # 2つの AZ (例として AZ1, AZ2 と命名)
            with Cluster("AZ1"):
                # パブリックサブネット
                with Cluster("パブリックサブネット"):
                    # 必要に応じて NAT Gateway / Bastion など配置
                    pass

                # プライベートサブネット_アプリ専用
                with Cluster(
                    "プライベートサブネット_アプリ専用",
                    graph_attr={
                        "bgcolor": "#E3F2FD",
                        "style": "filled",
                    },
                ):
                    fargate_az1 = Fargate("Fargateコンテナ")

                # プライベートサブネット_RDS専用
                with Cluster(
                    "プライベートサブネット_RDS専用",
                    graph_attr={
                        "bgcolor": "#E3F2FD",
                        "style": "filled",
                    },
                ):
                    rds_az1 = RDS("RDS")

            with Cluster("AZ2"):
                # パブリックサブネット
                with Cluster("パブリックサブネット"):
                    pass

                # プライベートサブネット_アプリ専用
                with Cluster(
                    "プライベートサブネット_アプリ専用",
                    graph_attr={
                        "bgcolor": "#E3F2FD",
                        "style": "filled",
                    },
                ):
                    fargate_az2 = Fargate("Fargateコンテナ")

                # プライベートサブネット_RDS専用
                with Cluster(
                    "プライベートサブネット_RDS専用",
                    graph_attr={
                        "bgcolor": "#E3F2FD",
                        "style": "filled",
                    },
                ):
                    rds_az2 = RDS("RDS")

    # --- 接続関係を定義 (サンプル) ---

    # ユーザ → PC → DNS(Route53)
    human_user >> local_pc >> r53
    # DNS(Route53) → ALB (ACM で HTTPS 証明書)
    r53 >> alb
    alb >> acm

    # ALB → Fargateコンテナ(両AZ)
    alb >> fargate_az1
    alb >> fargate_az2

    # アプリコンテナ(Fargate) → RDS の疎通 (DB 接続イメージ)
    fargate_az1 >> rds_az1
    fargate_az2 >> rds_az2

```

## 2. Lambdaサーバーレス構成図
### 構成図

![lambda-serverless.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967556/1725ee88-b2c1-6ae4-6376-46bfffb7f214.png)



### Pythonコード
```code:Python
from diagrams import Diagram, Cluster, Edge
from diagrams.aws.network import Route53, APIGateway
from diagrams.aws.security import CertificateManager
from diagrams.aws.compute import Lambda
from diagrams.aws.database import RDS
from diagrams.onprem.client import User as HumanUser, Client as PC
from diagrams.custom import Custom

local_pc_graph_attr = {
    "bgcolor": "transparent",  # 背景色なし
    "pencolor": "silver",  # シルバーの枠線
    "penwidth": "1",
}

with Diagram(
    "PythonコードでサクッとAWS構成図を描く ※Fargate構成、Lambdaサーバーレス構成など",
    show=False,
):
    human_user = HumanUser("User")
    local_pc = PC("ローカルPC")

    with Cluster(
        "AWSクラウド",
        graph_attr={
            "bgcolor": "transparent",
            "pencolor": "orange",
            "penwidth": "1",
        },
    ):
        r53 = Route53("DNS")
        acm = CertificateManager("ACM")
        apigw = APIGateway("API Gateway")

        # VPC
        with Cluster(
            "VPC",
            graph_attr={
                "bgcolor": "transparent",
                "pencolor": "#248814",  # 緑色
                "penwidth": "1",
            },
        ):
            # プライベートサブネット
            with Cluster(
                "プライベートサブネット",
                graph_attr={
                    "bgcolor": "#E3F2FD",
                    "style": "filled",
                },
            ):
                lambda_func = Lambda("Lambda")

            # RDS Proxy
            rds_proxy = Custom(
                "RDS Proxy",
                "imgs/rds_proxy.png",
                shape="box",
                style="solid",
                fillcolor="transparent",
                color="#527FFF",
                penwidth="2",
                fontcolor="black",
            )

            # プライベートサブネット RDS用
            with Cluster(
                "プライベートサブネット (RDS)",
                graph_attr={
                    "bgcolor": "#E3F2FD",
                    "style": "filled",
                },
            ):
                rds_db = RDS("RDS")

    # ユーザ → PC → Route53
    human_user >> local_pc >> r53
    # Route53 → API Gateway → Lambda
    r53 >> apigw >> lambda_func

    # Lambda から RDS Proxy へ矢印
    lambda_func >> Edge() >> rds_proxy

    # RDS Proxy から RDS への矢印
    rds_proxy >> Edge(label="Connection Pool") >> rds_db

```

## 3. その他構成図
### 構成図

![other.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967556/62511012-c05b-bc64-578b-fdc1594d1ac1.png)


### Pythonコード
```code:Python
from diagrams import Diagram, Cluster
from diagrams.aws.network import Route53, APIGateway
from diagrams.aws.security import CertificateManager
from diagrams.aws.compute import Lambda
from diagrams.onprem.client import User as HumanUser, Client as PC
from diagrams.onprem.database import PostgreSQL
from diagrams.custom import Custom

# ローカルPC
local_pc_graph_attr = {
    # 背景色なし
    "bgcolor": "transparent",
    # シルバーの枠線
    "pencolor": "silver",
    "penwidth": "1",
}

with Diagram(
    "PythonコードでサクッとAWS構成図を描く ※Fargate構成、Lambdaサーバーレス構成など",
    show=False,
):
    human_user = HumanUser("User")
    local_pc = PC("ローカルPC")

    with Cluster(
        "AWSクラウド",
        graph_attr={
            "bgcolor": "transparent",
            "pencolor": "orange",
            "penwidth": "1",
        },
    ):
        r53 = Route53("DNS")
        acm = CertificateManager("ACM")
        apigw = APIGateway("API Gateway")

        with Cluster(
            "VPC",
            graph_attr={
                "bgcolor": "transparent",
                # 緑色
                "pencolor": "#248814",
                "penwidth": "1",
            },
        ):
            with Cluster(
                "プライベートサブネット",
                graph_attr={
                    "bgcolor": "#E3F2FD",
                    "style": "filled",
                },
            ):
                lambda_func = Lambda("Lambda")

    # ユーザ → PC → Route53
    human_user >> local_pc >> r53
    # Route53 → API Gateway → Lambda
    r53 >> apigw >> lambda_func

    # ローカルPC枠（クラスター）
    with Cluster("ローカルPC", graph_attr=local_pc_graph_attr):
        local_pc_dummy = Custom(
            "",
            "",
            shape="none",
            style="invis",
            width="0",
            height="0",
        )

        # DockerCompose
        with Cluster(
            "Docker Compose",
            graph_attr={
                "bgcolor": "transparent",
                "pencolor": "#2496ED",  # Docker公式カラー
                "penwidth": "1",
                "style": "filled",
            },
        ):

            with Cluster(
                "LocalStackコンテナ",
                graph_attr={
                    "bgcolor": "transparent",
                    # 濃い青色 (Navy)
                    "pencolor": "#000080",
                    "penwidth": "2",
                },
            ):
                local_apigateway = APIGateway("API Gateway")

                with Cluster(
                    "Appコンテナ",
                    graph_attr={
                        "bgcolor": "transparent",
                        # Docker公式カラー
                        "pencolor": "#2496ED",
                        "penwidth": "1",
                        "style": "filled",
                    },
                ):
                    local_lambda_func = Lambda("Lambda")
                    fastapi = Custom(
                        "FastAPI",
                        "../images/other/fastapi.png",
                        shape="box",
                        style="filled",
                        fillcolor="#FFFFFF",
                        color="#000000",
                        penwidth="2",
                        fontcolor="black",
                        fontsize="12",
                    )
            with Cluster(
                "DBコンテナ",
                graph_attr={
                    "bgcolor": "transparent",
                    # Docker公式カラー
                    "pencolor": "#2496ED",
                    "penwidth": "1",
                    "style": "filled",
                },
            ):
                postgres = PostgreSQL("PostgreSQL")

    #  ローカルPC
    local_pc - local_pc_dummy
    local_apigateway >> local_lambda_func >> postgres

```
## 使ってみた感想
細かい構成図が不要な場面では、積極的に[コードベースのDiagramsライブラリ](https://github.com/mingrammer/diagrams)で構成図を作成したいと思いました。
理由は、下記となります。
- 作業時間を短縮できる
  - 1度ソースコードを書いてしまえば、再利用や修正が容易
  - サイズや配置が自動調整され、GUIツールのように細かいサイズを決める作業に悩まなくて済む
  - ChatGPTを使って構成図を生成できる

逆に細かい構成図が求められる場面では、引き続き、「GUIベースのdraw.ioアプリ」を使っていきます。

## 実際にChatGPT o1 pro modeモデルに、構成図の追加を依頼してみた
ChatGPT o1 pro modeモデルに、構成図の追加を依頼した結果、Before➔Afterの出力に成功いたしました❗❗❗
Before➔After間で3つAWSリソースが増えております。

![chat-gpt-o1-pro-mode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967556/81a9d4ff-11ee-f27e-f63e-d5a3bddbebd7.png)

### プロンプト内容
>diagram.pyに下記1〜6を追加して頂けますでしょうか。
>1. lambdaの右に右矢印を追加してください
>2. 1で作成した右矢印の先にRDS Proxyを追加してください。Customクラスで作成してください。背景色は無しで、枠線はRDSサービスと同じ青色としてください
>3. 2で作成したRDS Proxyの右に矢印を追加してください。また矢印のテキストにConnection Poolを記載してください
>4. 3で作成した矢印の右には新規でプライベートサブネットを追加してください
>5. 4で作成したプライベートサブネット中に、RDSを配置してください。テキストはRDSとします。
>6. 1〜5で作成した図は、VPC枠の中に配置してください

>```code:Beforeコード
>from diagrams import Diagram, Cluster
>from diagrams.aws.network import Route53, APIGateway
>from diagrams.aws.security import CertificateManager
>from diagrams.aws.compute import Lambda
>from diagrams.onprem.client import User as HumanUser, Client as PC
>from diagrams.custom import Custom
>
>local_pc_graph_attr = {
>    # 背景色なし
>    "bgcolor": "transparent",
>    # シルバーの枠線
>    "pencolor": "silver",
>    "penwidth": "1",
>}
>
>with Diagram(
>    "PythonコードでサクッとAWS構成図を描く ※Fargate構成、Lambdaサーバーレス構成など",
>    show=False,
>):
>    human_user = HumanUser("User")
>    local_pc = PC("ローカルPC")
>
>    with Cluster(
>        "AWSクラウド",
>        graph_attr={
>            "bgcolor": "transparent",
>            "pencolor": "orange",
>            "penwidth": "1",
>        },
>    ):
>        r53 = Route53("DNS")
>        acm = CertificateManager("ACM")
>        apigw = APIGateway("API Gateway")
>
>        with Cluster(
>            "VPC",
>            graph_attr={
>                "bgcolor": "transparent",
>                # 緑色
>                "pencolor": "#248814",
>                "penwidth": "1",
>            },
>        ):
>            with Cluster(
>                "プライベートサブネット",
>                graph_attr={
>                    "bgcolor": "#E3F2FD",
>                    "style": "filled",
>                },
>            ):
>                lambda_func = Lambda("Lambda")
>
>    # ユーザ → PC → Route53
>    human_user >> local_pc >> r53
>    # Route53 → API Gateway → Lambda
>    r53 >> apigw >> lambda_func
>```