Automatic C4 diagrams for a distributed microservice ecosystem with GitHub Actions
Tags: actionshackathon21, plantuml, c4, diagram
Published: 2021-12-09 01:44:22

[Instructions]: # (To submit to the GitHub Actions x DEV Hackathon 2021, please fill out all sections.)


### My Workflow
[Note]: # (Please make sure the project links to the appropriate GitHub Actions repository, and includes [an open source license](https://choosealicense.com/) and README.)

_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](https://github.com/acme-corp-tech/architecture)._

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](https://c4model.com/) 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/msosnsxtzezw1802hf0v.png)](https://raw.githubusercontent.com/wiki/acme-corp-tech/architecture/acme.svg)
 

Syntax example:
```uml
@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
```

```uml
@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
```

```
@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
```

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](https://github.com/acme-corp-tech/cart)) contains own diagram fragments at [`./resources/diagrams`](https://github.com/acme-corp-tech/cart/tree/master/resources/diagrams). 

Centralized renderer is implemented in a separate [`architecture`](https://github.com/acme-corp-tech/architecture) repository. Renderer knows the names of fragment owners, but does not know the contents of fragments. Fragments are fetched with a [script](https://github.com/acme-corp-tech/architecture/blob/main/diagrams/fetch-external.sh) every time the diagrams are rendered.

Centralized renderer owns [main frame](https://github.com/acme-corp-tech/architecture/blob/main/diagrams/acme.puml) that includes all fragments.

Every time any of the fragments changes, central renderer is [triggered](https://github.com/acme-corp-tech/cart/blob/master/.github/workflows/diagrams.yml) to rebuild the full picture, thus keeping the diagrams up to date without any manual effort.

Rendered SVG files are then pushed to [wiki](https://github.com/acme-corp-tech/architecture/wiki/Acme-Services) repository.

### Submission Category: 
DIY Deployments
[Note]: # (Maintainer Must-Haves, DIY Deployments, Interesting IoT, Phone Friendly, or Wacky Wildcards)


### Yaml File or Link to Code

[Note]: # (Our markdown editor supports pretty embeds. Try this syntax: `{% github link_to_your_repo %}` to share a GitHub repository)

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](https://github.com/acme-corp-tech/cart/blob/master/.github/workflows/diagrams.yml).

### Additional Resources / Info

* [C4 PlantUML](https://github.com/plantuml-stdlib/C4-PlantUML)
* Docker image with PlantUML renderer [`vearutop/plantuml`](https://hub.docker.com/r/vearutop/plantuml)
* GitHub Action for Dispatching Workflows [`benc-uk/workflow-dispatch`](https://github.com/benc-uk/workflow-dispatch)