How to Create Architecture Diagram as Code for a 2-Tier Bookstore Application
Creating architecture diagrams as code
is a modern approach that offers numerous benefits over traditional diagramming methods, including architecture diagram automation, and consistency. This approach allows for version-controlled, easily reproducible, and modifiable diagrams that can evolve alongside your application.
This article will guide you through the process of creating an architecture diagram for a 2-tier bookstore application in AWS Cloud using Python
and its [diagrams
] library.
Why Diagrams as Code?
Diagrams as code offer several advantages over traditional diagramming tools:
- Version Control: Changes to diagrams can be tracked over time.
- Automation: Diagrams can be automatically updated as part of your CI/CD pipeline.
- Consistency: Ensures uniformity in the presentation of your architecture.
Diagram as code makes it easy to Architects and Developers to update their architecture diagram, and use version control to maintain various versions of the Architecture.
Tools & Technology Used
We'll use the [diagrams
] Python library, which allows for creating cloud system architecture diagrams using code. It supports various providers, including AWS, GCP, Azure, and many more.
Prerequisites
- Python 3.x installed on your system
- Basic understanding of Python programming
- Familiarity with virtual environments in Python
Sample Application: Bookstore 2-Tier Architecture
Our sample application is a simple bookstore with a 2-tier architecture consisting of a frontend and a backend, along with a database. It also includes a CI/CD pipeline and monitoring services.
To run the Python code that generates an architecture diagram for a bookstore application, follow these detailed steps. These steps include setting up a virtual environment, installing dependencies, and running the script.
Step 1: Setting Up a Python Virtual Environment
First, you need to create a virtual environment. A virtual environment is a self-contained directory that contains a Python installation for a particular version of Python, plus a number of additional packages.
- Open your terminal.
- Navigate to the directory where you want to store your project.
- Run the following command to create a virtual environment named
venv
:
python3 -m venv venv
Activate the Virtual Environment
Activate the virtual environment to use it for your project.
- On macOS and Linux:
source venv/bin/activate
- On Windows:
.\venv\Scripts\activate
Install the Required Libraries
With the environment activated, install the diagrams
library, which enables you to generate architecture diagrams using Python code.
pip install diagrams graphviz
Step 2: Writing the Diagram Code
Create a new Python file named [architecture.py
] and open it in your favorite text editor.
Copy the following code into the file. This code defines the architecture of a simple bookstore application with a 2-tier architecture, including a frontend, a backend, a database, a CI/CD pipeline, and monitoring services.
from diagrams import Diagram, Cluster, Edge
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
from diagrams.aws.network import ELB, Route53
from diagrams.aws.general import Client
from diagrams.onprem.network import Internet
from diagrams.onprem.monitoring import Prometheus, Grafana
from diagrams.programming.framework import React
from diagrams.custom import Custom
graph_attr = {'ranksep': '1.0'} #, 'rankdir': 'TB'}
with Diagram("Two Tier Application Architecture", show=False, graph_attr=graph_attr):
with Cluster("User Network"):
client = Client("User")
internet = Internet("Internet")
with Cluster("CI/CD Pipeline"):
with Cluster("Source Code"):
react = React("React")
terraform = Custom("Terraform", "./tf.png")
github_actions = Custom("GitHub Actions", "./ghactions.png")
with Cluster("AWS Cloud"):
with Cluster("VPC"):
with Cluster("Public Subnet"):
dns = Route53("DNS")
lb = ELB("Load Balancer")
# public_subnet = Subnet("Public Subnet")
dns >> lb
with Cluster("Private Subnet for Backend"):
# private_subnet_backend = Subnet("Private Subnet")
backend = EC2("Backend (Node.js)")
db = RDS("Database (MongoDB)")
backend >> db
with Cluster("Private Subnet for Frontend"):
# private_subnet_frontend = Subnet("Private Subnet")
frontend = EC2("Frontend (React)")
# private_subnet_frontend >> frontend
with Cluster("Monitoring"):
prometheus = Prometheus("Prometheus")
grafana = Grafana("Grafana")
client >> internet >> dns
react >> github_actions
terraform >> github_actions
lb >> Edge(label="HTTP/HTTPS") >> frontend
lb >> Edge(label="HTTP/HTTPS") >> backend
backend >> Edge(label="Database Connection") >> db
backend >> prometheus
frontend >> prometheus
db >> prometheus
prometheus >> grafana
# Connecting CI/CD Pipeline to AWS Cloud
github_actions >> Edge(color="blue", style="dashed", label="Deploy to AWS Cloud") >> dns
# Creating Custom Node
# Custom Node: We can create a custom node to represent the subnet.
# The diagrams library allows you to create custom nodes with your own images,
# which can be useful for representing components that are not available as predefined classes.
# from diagrams import Node
# class Subnet(Node):
# _icon_dir = "path/to/custom/icons"
# _icon = "subnet.png"
Full source code has been available in GitHub. Please check it out here.
Python Code Break down of the Architecture Diagram
Let's break down the Python code used to generate the architecture diagram step-by-step:
from diagrams import Diagram, Cluster, Edge
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
from diagrams.aws.network import ELB, Route53
from diagrams.aws.devtools import Codepipeline, Codebuild
from diagrams.aws.general import Client
from diagrams.onprem.network import Internet
from diagrams.onprem.container import Docker
from diagrams.onprem.monitoring import Prometheus, Grafana
from diagrams.programming.language import Python
Imports
-
Diagram, Cluster, Edge: Core components from the
diagrams
library to create diagrams, group components, and define connections. -
AWS Components: Various AWS components (
EC2
,RDS
,ELB
,Route53
,Codepipeline
,Codebuild
,Client
) to represent different parts of the architecture. -
On-Prem Components: Components for non-cloud (on-prem) services (
Internet
,Docker
,Prometheus
,Grafana
). -
Programming Language: Represents GitHub Actions with a generic programming language icon (
Python
).
Creating the Diagram
with Diagram("Two Tier Application Architecture", show=False, graph_attr=graph_attr):
with Cluster("User Network"):
client = Client("User")
internet = Internet("Internet")
-
Diagram: The main context for the diagram, with the title "Bookstore Application Architecture".
show=False
prevents the diagram from being immediately displayed. - Client: Represents the user accessing the application.
- DNS: Uses Route53 to represent the DNS service.
CI/CD Pipeline
with Cluster("CI/CD Pipeline"):
with Cluster("Source Code"):
react = React("React")
terraform = Custom("Terraform", "./tf.png")
github_actions = Custom("GitHub Actions", "./ghactions.png")
- Cluster: Groups components logically. Here, it groups the CI/CD pipeline components.
-
GitHub Actions: Represented using a generic programming language user uploaded icon (
ghactions.png
). - React and Custom: MERN code and Terraform code representation (with user uploaded Terraform icon). They are integrated with the GitHub action workflow for CICD deployment.
AWS Cloud & Monitoring Components
with Cluster("AWS Cloud"):
with Cluster("VPC"):
with Cluster("Public Subnet"):
dns = Route53("DNS")
lb = ELB("Load Balancer")
# public_subnet = Subnet("Public Subnet")
dns >> lb
with Cluster("Private Subnet for Backend"):
# private_subnet_backend = Subnet("Private Subnet")
backend = EC2("Backend (Node.js)")
db = RDS("Database (MongoDB)")
backend >> db
with Cluster("Private Subnet for Frontend"):
# private_subnet_frontend = Subnet("Private Subnet")
frontend = EC2("Frontend (React)")
# private_subnet_frontend >> frontend
with Cluster("Monitoring"):
prometheus = Prometheus("Prometheus")
grafana = Grafana("Grafana")
- AWS Cloud Cluster: Groups all AWS cloud components.
- Load Balancer (ELB) and DNS: Distributes traffic between frontend and backend services. DNS used to be exposed to the public internet.
- VPC Cluster: VPC cluster has been created to indicate private and public subnet networks for UI layer and backend layer.
- Backend Service Cluster: Contains the backend server (Node.js on EC2) and the database (MongoDB on RDS).
- Frontend Service Cluster: Contains the frontend server (React on EC2).
- Monitoring Cluster: Contains Prometheus for metrics collection and Grafana for visualization.
Defining Connections
client >> internet >> dns
react >> github_actions
terraform >> github_actions
lb >> Edge(label="HTTP/HTTPS") >> frontend
lb >> Edge(label="HTTP/HTTPS") >> backend
backend >> Edge(label="Database Connection") >> db
backend >> prometheus
frontend >> prometheus
db >> prometheus
prometheus >> grafana
-
Connections: Represented using
>>
operator, defining the flow and connections between components. - client >> internet >> dns: The user accesses the DNS service, via public internet.
- react >> github_actions: Represents the CI/CD pipeline flow from MERN Code into integration GitHub Actions.
- terraform >> github_actions: Represents the CI/CD pipeline flow from Terraform infra deployment code into integration GitHub Actions.
- lb >> Edge(label="HTTP/HTTPS") >> frontend: The load balancer directs traffic to the frontend services.
- lb >> Edge(label="HTTP/HTTPS") >> backend: The load balancer directs traffic to the backend services.
- backend >> Edge(label="Database Connection") >> db: The backend service connects to the MongoDB database.
- backend >> prometheus and frontend >> prometheus: Both frontend and backend services send metrics to Prometheus.
- prometheus >> grafana: Prometheus metrics are visualized using Grafana.
- github_actions >> Edge(color="blue", style="dashed", label="Deploy to AWS Cloud") >> dns: Depicts to connection from GitHub Action to AWS Cloud infra deployment and code deployment into servers
Summary of Diagram Breakdown
The Python script leverages the diagrams
library to create a structured, version-controlled architecture diagram. It groups related components into clusters, defines the interactions between them using directed edges, and ensures the entire infrastructure is visually represented in a clear, consistent manner. This approach makes it easy to update and maintain the architecture diagram as the application evolves.
Adding custom node for user-defined components
Let us see how to create a custom node in Python using the diagrams
library. This library allows developers to visually represent their infrastructure and systems.
The purpose of creating a custom node is to represent a user-defined architecture component and ICON/logo.
Method 1: Defining the from diagrams.custom import Custom
Diagrams Custom module, and using this section along with the valid logo/ICON PNG image of the architecture component.
For example, we have added Terraform Icon using this method.
We need to store the license free PNG image for this purpose.
from diagrams.custom import Custom
terraform = Custom("Terraform", "./tf.png")
Method 2:
As depicted on the commented out example, a custom node definition for subnet has been added.
A subnet is part of VPC architecture &, and is a logical subdivision of an IP network. The ability to create custom nodes is particularly useful when the predefined classes provided by the diagrams
library do not cover all the components you need to represent in your architecture diagrams.
- The code snippet begins by importing the
Node
class from thediagrams
library. - This
Node
class is the base class for all diagram nodes, and custom nodes can be created by subclassing it. - The subclass shown in the example is named
Subnet
, indicating its intended use to represent subnetworks.
Within the Subnet
class, two class attributes are defined:
-
_icon_dir
: This attribute specifies the directory path where custom icons are stored. In this example, it's set to"path/to/custom/icons"
, which should be replaced with the actual path to the directory containing the icon files. -
_icon
: This attribute specifies the filename of the icon image that will be used to visually represent the node in the diagram. Here, it is set to"subnet.png"
, indicating that an image file namedsubnet.png
in the specified directory will be used as the icon for the subnet node.
By defining these attributes, the Subnet
class tells the diagrams
library where to find the custom icon and which icon to use when rendering the subnet node in a diagram. This allows for a more customized and visually accurate representation of the system's architecture.
Step 3: Generating the Diagram
Ensure the Python script ([architecture.py
] is saved in your project directory.
Run the script to generate the architecture diagram. Ensure your virtual environment is activated, then execute:
python architecture.py
This command executes the script, which generates a PNG image named Bookstore Application Architecture.png
in the same directory, illustrating the architecture of the bookstore application.
Understanding the Diagram Bookstore Application Architecture.png
- User Network: Represents the entry point for users, connecting through the internet to our application.
- CI/CD Pipeline: Showcases the automation for deploying our React frontend and Terraform configurations.
- AWS Cloud: Hosts our application, including the load balancer, DNS service, backend service (Node.js), frontend service (React), and database (MongoDB).
- Monitoring: Utilizes Prometheus for monitoring and Grafana for visualization.
Step 4: Deactivating the Virtual Environment
Once you're done working in the virtual environment, you can deactivate it by running:
deactivate
This command returns you to the systemโs default Python interpreter with all its installed libraries.
By following these steps, you've successfully set up a virtual environment, installed necessary dependencies, and run a Python script to generate an architecture diagram for a bookstore application.
Benefits & Use-cases of Diagram as code
Diagrams as code offer numerous benefits in real-time project scenarios, providing a powerful and efficient way to manage and visualize complex system architectures. Here are some typical use-cases:
Documentation and Communication
Architecture Documentation: Automatically generate up-to-date diagrams that accurately reflect the current state of the system architecture. This ensures that documentation is always current and avoids the pitfalls of manually maintained diagrams.
Team Communication: Facilitate better communication among team members by providing a clear and consistent visualization of the architecture, which can be easily shared and discussed.Infrastructure as Code (IaC) Integration
IaC Synchronization: Use diagrams as code to keep architecture diagrams in sync with the actual infrastructure managed by tools like Terraform, CloudFormation, or Ansible. This provides a visual representation of the infrastructure that matches the code.
Automated Updates: Automatically update architecture diagrams as part of the CI/CD pipeline whenever changes are made to the IaC scripts. This ensures that diagrams reflect the latest infrastructure changes.CI/CD Pipeline Integration
Pipeline Visualization: Visualize the CI/CD pipeline stages and the flow of code from development to production. This helps in understanding the deployment process and identifying potential bottlenecks.
Deployment Architecture: Generate diagrams that show the architecture of the deployed application, including microservices, databases, and other components. This can be especially useful for troubleshooting and optimizing deployment strategies.Microservices and Distributed Systems
Service Dependencies: Visualize the dependencies and interactions between microservices in a distributed system. This helps in understanding the overall system behavior and identifying potential points of failure.
Dynamic Environments: Automatically generate diagrams for dynamic environments where services and dependencies may frequently change. This ensures that the architecture diagram remains accurate and up-to-date.Architecture diagram AI automation:
If you want to create AI to generate architecture diagram for given prompt, then we can use this method of generating diagrams
Conclusion
You've now successfully created an architecture diagram as code for a 2-tier bookstore application. This method allows for easy updates, version control, and integration into CI/CD pipelines, making it an efficient tool for modern software development practices.
Docs Reference
Follow me on,
Share your views about creating Architecture Diagrams as code.
Top comments (1)
Building a robust and scalable 2-tier architecture for a bookstore application can be both an exciting and challenging endeavor. Utilizing Infrastructure as Code (IaC) tools allows for efficient, repeatable, and manageable deployment processes. In this guide, we will outline the architecture diagram as code for a 2-tier bookstore application using the lost life mod approach.
Overview of the 2-Tier Architecture
A 2-tier architecture typically consists of:
Presentation Tier (Frontend): The user interface where customers interact with the bookstore application.
Data Tier (Backend): The database and application logic that handle data storage, processing, and retrieval.