Diagrams as Code
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.
Installation de Graphviz
Dans un premier procédons à l’installation de Graphviz :
Debian et dérivées :
sudo apt install graphviz
Rhel et dérivées :
sudo yum install graphviz
Arch et dérivées :
sudo pacman -S graphviz
Sur macOS :
brew install graphviz
Sur windows :
choco install graphviz#ouwinget 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 :
poetry add --dev diagramspoetry install --only dev
Plus classiquement avec pip
:
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 :
from diagrams import Diagramfrom diagrams.aws.compute import EC2from diagrams.aws.database import RDSfrom 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
etpdf
.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
andedge_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 Diagramfrom 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, Diagramfrom diagrams.aws.compute import ECSfrom diagrams.aws.database import RDSfrom 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
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, Edgefrom diagrams.k8s.compute import Podfrom diagrams.k8s.network import Ingfrom diagrams.gcp.network import LoadBalancingfrom 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
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, Clusterfrom diagrams.custom import Customfrom 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
Un autre exemple :
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 :
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.