Container diagram¶
Once you understand how your system fits in to the overall IT environment, a useful next step is to zoom in to the system boundary with a container diagram. In C4, a container is an application or a data store. For example, a server-side web application, a client-side single-page application, a desktop application, a mobile app, a database schema, a folder on a file system, an Amazon Web Services S3 bucket, etc.
The container diagram shows the high-level shape of the software architecture and how responsibilities are distributed across it. It also shows the major technology choices and how the containers communicate with one another. It’s a simple, high-level technology focussed diagram that is useful for software developers and support/operations staff alike.
Example¶
The following example demonstrates how to define a container diagram using the Python DSL.
from c4 import (
Container,
ContainerDb,
ContainerDiagram,
ContainerQueue,
LayRight,
Person,
Rel,
RelDown,
RelUp,
SystemBoundary,
)
from c4.renderers.plantuml import LayoutOptions
with ContainerDiagram() as diagram:
customer = Person("customer", "Customer", "A customer")
with SystemBoundary("c1", "Customer Information"):
app = Container(
"app",
"Customer Application",
"Javascript, Angular",
"Allows customers to manage their profile",
)
customer_service = Container(
"customer_service",
"Customer Service",
"Java, Spring Boot",
"The point of access for customer information",
tags="microService",
)
message_bus = ContainerQueue(
"message_bus",
"Message Bus",
"RabbitMQ",
"Transport for business events",
)
reporting_service = Container(
"reporting_service",
"Reporting Service",
"Ruby",
"Creates normalised data for reporting purposes",
tags="microService",
)
audit_service = Container(
"audit_service",
"Audit Service",
"C#/.NET",
"Provides organisation-wide auditing facilities",
tags="microService",
)
customer_db = ContainerDb(
"customer_db",
"Customer Database",
"Oracle 12c",
"Stores customer information",
tags="storage",
)
reporting_db = ContainerDb(
"reporting_db",
"Reporting Database",
"MySQL",
"Stores a normalized version of all business data for ad hoc reporting purposes",
tags="storage",
)
audit_store = Container(
"audit_store",
"Audit Store",
"Event Store",
"Stores information about events that have happened",
tags="storage",
)
customer >> RelDown("Uses", "HTTPS") >> app
app >> RelDown('Updates customer information using', 'async, JSON/HTTPS') >> customer_service # fmt: off
customer_service >> RelUp("Sends events to", "WebSocket") >> app
customer_service >> RelUp('Sends customer update events to') >> message_bus # fmt: off
customer_service >> Rel("Stores data in", "JDBC") >> customer_db
message_bus >> Rel('Sends customer update events to') >> [reporting_service, audit_service] # fmt: off
reporting_service >> Rel("Stores data in") >> reporting_db
audit_service >> Rel("Stores events in") >> audit_store
LayRight(reporting_service, audit_service)
layout_options = (
LayoutOptions()
.add_element_tag(
"microService",
shape="EightSidedShape",
bg_color="CornflowerBlue",
font_color="white",
legend_text="micro service\neight sided",
)
.add_element_tag(
"storage",
shape="RoundedBoxShape",
bg_color="lightSkyBlue",
font_color="white",
)
.show_person_outline()
.show_legend()
)
diagram_code = diagram.as_plantuml(layout_options=layout_options)
Generated PlantUML source
@startuml
' convert it with additional command line argument -DRELATIVE_INCLUDE="relative/absolute" to use locally
!if %variable_exists("RELATIVE_INCLUDE")
!include %get_variable_value("RELATIVE_INCLUDE")/C4_Container.puml
!else
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml
!endif
AddElementTag("microService", $bgColor="CornflowerBlue", $fontColor="white", $shape=EightSidedShape(), $legendText="micro service\neight sided")
AddElementTag("storage", $bgColor="lightSkyBlue", $fontColor="white", $shape=RoundedBoxShape())
SHOW_PERSON_OUTLINE()
Person(customer, "Customer", "A customer")
System_Boundary(c1, "Customer Information") {
Container(app, "Customer Application", "Javascript, Angular", "Allows customers to manage their profile")
Container(customer_service, "Customer Service", "Java, Spring Boot", "The point of access for customer information", $tags="microService")
ContainerQueue(message_bus, "Message Bus", "RabbitMQ", "Transport for business events")
Container(reporting_service, "Reporting Service", "Ruby", "Creates normalised data for reporting purposes", $tags="microService")
Container(audit_service, "Audit Service", "C#/.NET", "Provides organisation-wide auditing facilities", $tags="microService")
ContainerDb(customer_db, "Customer Database", "Oracle 12c", "Stores customer information", $tags="storage")
ContainerDb(reporting_db, "Reporting Database", "MySQL", "Stores a normalized version of all business data for ad hoc reporting purposes", $tags="storage")
Container(audit_store, "Audit Store", "Event Store", "Stores information about events that have happened", $tags="storage")
Rel_Down(customer, app, "Uses", "HTTPS")
Rel_Down(app, customer_service, "Updates customer information using", "async, JSON/HTTPS")
Rel_Up(customer_service, app, "Sends events to", "WebSocket")
Rel_Up(customer_service, message_bus, "Sends customer update events to")
Rel(customer_service, customer_db, "Stores data in", "JDBC")
Rel(message_bus, reporting_service, "Sends customer update events to")
Rel(message_bus, audit_service, "Sends customer update events to")
Rel(reporting_service, reporting_db, "Stores data in")
Rel(audit_service, audit_store, "Stores events in")
}
Lay_Right(reporting_service, audit_service)
SHOW_LEGEND()
@enduml
The PlantUML source can be rendered into the following diagram:
