DEV Community

Viacheslav Poturaev
Viacheslav Poturaev

Posted on

Automatic C4 diagrams for a distributed microservice ecosystem with GitHub Actions

My Workflow

TL;DR Big picture is split into service-level fragments and those fragments are delegated to service teams. Then fragments are automatically stitched together by a GitHub Action.

This way the heavy lifting of detailed description of service relations is deferred to the best experts - service owners.

Demo.

Documenting components and their relations in an ecosystem (such as a family of microservices) is very important. When the whole system grows it is easy to lose track of what's happening, where it is happening and why. Popular solution for this problem is high level documentation with diagrams.

C4 Model helps to describe the structure in a compact and clear way. Textual form of UML makes it a perfect fit for software repositories.

Image description

Syntax example:

@startuml "cart_components"
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

System_Boundary(cart_system, "[[https://github.com/acme-corp-tech/architecture/wiki/cart_system.svg Shopping cart]]") {
    Container(cart_service, "Cart Service", "Go", "Tracks cart contents", $sprite="go")
    ContainerDb(cart_storage, "Cart Service Storage", "Redis", "", $sprite="redis")
}

@enduml
Enter fullscreen mode Exit fullscreen mode
@startuml "cart_relations"
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

Rel(cart_service, cart_storage, "Stores cart contents")

@enduml
Enter fullscreen mode Exit fullscreen mode
@startuml "cart_system"
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

!include cart_components.puml
!include cart_relations.puml

@enduml
Enter fullscreen mode Exit fullscreen mode

Documentation that is maintained separately from the actual system tends to lag behind or even becomes obsolete and misleading. Keeping documentation closer to documented entity helps to sync them.

This workflow implements distributed storage of documentation with centralized renderer.

Each documented entity (microservice repository) contains own diagram fragments at ./resources/diagrams.

Centralized renderer is implemented in a separate architecture repository. Renderer knows the names of fragment owners, but does not know the contents of fragments. Fragments are fetched with a script every time the diagrams are rendered.

Centralized renderer owns main frame that includes all fragments.

Every time any of the fragments changes, central renderer is triggered to rebuild the full picture, thus keeping the diagrams up to date without any manual effort.

Rendered SVG files are then pushed to wiki repository.

Submission Category:

DIY Deployments

Yaml File or Link to Code

Main workflow to collect UML fragments and render complete diagrams as SVG:
https://github.com/acme-corp-tech/architecture/blob/main/.github/workflows/diagrams.yml.

Template workflow to trigger an update whenever fragment is changed:
https://github.com/acme-corp-tech/service-starter-kit/blob/master/.github/workflows/diagrams.yml.

This workflow is configured for every service that owns a fragment, example.

Additional Resources / Info

Discussion (0)