Aller au contenu

Diagrams as Code

logo devops

Diagrams sont deux librairies, une en Python l’autre en Go, permettant de créer rapidement des schémas d’architecture. Le gros avantage est qu’il n’y ouva pas besoin de recourir à un éditeur pour les créer, si ce n’est la présence de Graphviz sur votre poste de travail. On peut aussi imaginer d’ajouter un petit bout de code dans votre CI pour les générer automatiquement à chaque détection de sa modification.

Diagrams permet de créer des schémas pour la plupart des systèmes de Cloud : AWS, Azure, GCP, AlibabaCloud,… mais aussi pour le On-Premise et même pour les clusters Kubernetes.

diagram as code aws

Installation de Graphviz

Dans un premier procédons à l’installation de Graphviz :

Debian et dérivées :

Terminal window
sudo apt install graphviz

Rhel et dérivées :

Terminal window
sudo yum install graphviz

Arch et dérivées :

Terminal window
sudo pacman -S graphviz

Sur macOS :

Terminal window
brew install graphviz

Sur windows :

Terminal window
choco install graphviz
#ou
winget install graphviz

Ecrire des schémas en Go Python

Installation de la librairie

Personnellement j’utilise pour gérer mes dépendances python sur la grande majorité de mes projets écrits en python. Pour ne pas ajouter de librairies non indispensables à mes projets, ce genre de librairies je l’installe au niveau des dépendances dev :

Terminal window
poetry add --dev diagrams
poetry install --only dev

Plus classiquement avec pip :

Terminal window
pip install diagrams

Ecrire un schéma

En plus de la librairie principale, il faut importer celles prenant en charge votre système de cloud et qui permettra d’instancier des Nodes.

Prenons par exemple le schéma suivant :

diagram as code aws

from diagrams import Diagram
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
from diagrams.aws.network import ELB

Ensuite, on instancie un Diagram, dans lequel on ajoute des instances des nodes.

with Diagram("Client to Application Flow", show=False):
ELB("lb") >> [EC2("worker1"),
EC2("worker2"),
EC2("worker3"),
EC2("worker4"),
EC2("worker5")] >> RDS("events")

Pour connecter les nodes entre eux il faut utiliser les opérateurs <<, >> en fonction de la direction ou - pour une connexion sans direction. Ici notre ELB est connecté aux cinq instances EC2.

On peut utiliser les options suivantes au moment de l’instanciation de la classe diagrams :

  • format="jpg" : pour choisir un format d’image parmi : png, jpg, svg et pdf.
  • filename="nom-de-limage" l’extension est fonction de celle choisie.
  • show="False" permet de dire qu’il ne faut pas ouvrir l’image une fois générée.
  • graph_attr, node_attr and edge_attr permet de définir des propriétés de rendu comme la couleur du fond, la taille des polices de caractère…
from diagrams import Diagram
from diagrams.aws.compute import EC2
graph_attr = {
"fontsize": "45",
"bgcolor": "transparent"
}
with Diagram("Simple Diagram", show=False, graph_attr=graph_attr):
...

Pour regrouper des nodes en cluster on utilisera la librairie Cluster :

from diagrams import Cluster, Diagram
from diagrams.aws.compute import ECS
from diagrams.aws.database import RDS
from diagrams.aws.network import Route53
with Diagram("Simple Web Service with DB Cluster", show=False):
dns = Route53("dns")
web = ECS("service")
with Cluster("DB Cluster"):
db_primary = RDS("primary")
db_primary - [RDS("replica1"),
RDS("replica2")]
dns >> web >> db_primary

diagram as code aws

Pour regrouper les nodes en fonction par exemple de leur réseau, ou de leur utilité on utilisera les edges :

from diagrams import Cluster, Diagram, Node, Edge
from diagrams.k8s.compute import Pod
from diagrams.k8s.network import Ing
from diagrams.gcp.network import LoadBalancing
from diagrams.onprem.network import Nginx
with Diagram("Cluster nesting", show=False):
gcp_lb = LoadBalancing("GCP LB")
with Cluster("Kubernetes"):
with Cluster("Nginx"):
nginx= Nginx("")
with Cluster("MyApp"):
myapp_ing = Ing("")
with Cluster("Pods"):
myapp_pods = Pod("myapp")
with Cluster("MySQL"):
myapp_db = Pod("myapp-db")
gcp_lb >> Edge(headport="c", tailport="c", minlen="1", lhead='cluster_Kubernetes') >> nginx
nginx >> Edge(headport="c", tailport="c", minlen="1", lhead='cluster_MyApp') >> myapp_ing >> Edge(headport="c", tailport="c", minlen="1", lhead='cluster_MyApp pods') >> myapp_pods >> myapp_db

diagram as code aws

En plus des librairies de base il est possible de créer des classes custom utilisant des icones externes (en local, ou en ligne) :

from diagrams import Diagram, Cluster
from diagrams.custom import Custom
from urllib.request import urlretrieve
with Diagram("Custom with remote icons", show=False, filename="custom_remote", direction="LR"):
# download the icon image file
diagrams_url = "https://github.com/mingrammer/diagrams/raw/master/assets../../../assets/diagrams.webp"
diagrams_icon = "diagrams.png"
urlretrieve(diagrams_url, diagrams_icon)
diagrams = Custom("Diagrams", diagrams_icon)
with Cluster("Some Providers"):
openstack_url = "https://github.com/mingrammer/diagrams/raw/master/resources/openstack/openstack.png"
openstack_icon = "openstack.png"
urlretrieve(openstack_url, openstack_icon)
openstack = Custom("OpenStack", openstack_icon)
elastic_url = "https://github.com/mingrammer/diagrams/raw/master/resources/elastic/saas/elastic.png"
elastic_icon = "elastic.png"
urlretrieve(elastic_url, elastic_icon)
elastic = Custom("Elastic", elastic_icon)
diagrams >> openstack
diagrams >> elastic

diagram as code aws

Un autre exemple :

diagram as code aws

Toutes les classes sont décrites dans la documentation en ligne. Cette documentation est très complète et regorge d’exemples, d’ailleurs je les ai utilisé pour écrire ce billet.

Ecrire des schémas en Go

Pour installer la version go de Diagrams :

Terminal window
go get github.com/blushft/go-diagrams

Créez votre premier diagramme d’architecture en Go

Cette librairie reprend le même principe que celle en python :

d, err := diagram.New(diagram.Label("my-diagram"), diagram.Filename("diagram"))
if err != nil {
log.Fatal(err)
}
fw := generic.Network.Firewall().Label("fw")
sw := generic.Network.Switch().Label("sw")
d.Connect(fw, sw)

Par contre, pas de trace de documentation ! Il faudra s’inspirer des exemples présent sur le projet.

Conclusion

Vraiment sympathique ces Diagrams as Code non ? Personnellement, je vais l’utiliser dans mes futurs projets. Reste juste à créer une image de container pour l’utiliser dans vos CI. Je l’ajouterai rapidement d’ailleurs.