github.com/containerd/Containerd@v1.4.13/design/architecture.md (about)

     1  # Architecture
     2  
     3  To ensure clean separation of concerns, we have organized the units of
     4  containerd's behavior into _components_. _Components_ are roughly organized
     5  into _subsystems_. _Components_ that bridge subsystems may be referred to as
     6  _modules_. _Modules_ typically provide cross-cutting functionality, such as
     7  persistent storage or event distribution. Understanding these _components_ and
     8  their relationships is key to modifying and extending the system.
     9  
    10  This document will cover very high-level interaction. For details on each
    11  module, please see the relevant design document.
    12  
    13  The main goal of this architecture is to coordinate the creation and execution
    14  of _bundles_.  _Bundles_ contain configuration, metadata and root filesystem
    15  data and are consumed by the _runtime_. A _bundle_ is the on-disk
    16  representation of a runtime container. _Bundles_ are mutable and can be passed
    17  to other systems for modification or packed up and distributed. In practice, it
    18  is simply a directory on the filesystem. 
    19  
    20  ![Architecture](architecture.png)
    21  
    22  Note that while these architectural ideas are important to understand the
    23  system, code layout may not reflect the exact architecture. These ideas should
    24  be used as a guide for placing functionality and behavior and understanding the
    25  thought behind the design.
    26  
    27  ## Subsystems
    28  
    29  External users interact with services, made available via a GRPC API.
    30  
    31  - __*Bundle*__: The bundle service allows the user to extract and pack bundles
    32    from disk images.
    33  - __*Runtime*__: The runtime service supports the execution of _bundles_,
    34    including the creation of runtime containers.
    35  
    36  Typically, each subsystem will have one or more related _controller_ components
    37  that implement the behavior of the _subsystem_. The behavior of the _subsystem_
    38  may be exported for access via corresponding _services_.
    39  
    40  ## Modules
    41  
    42  In addition to the subsystems, we have several components that may cross
    43  subsystem boundaries, referenced to as components. We have the following
    44  components:
    45  
    46  - __*Executor*__: The executor implements the actual container runtime.
    47  - __*Supervisor*__: The supervisor monitors and reports container state.
    48  - __*Metadata*__: Stores metadata in a graph database. Use to store any
    49    persistent references to images and bundles. Data entered into the
    50    database will have schemas coordinated between components to provide access
    51    to arbitrary data. Other functionality includes hooks for garbage collection
    52    of on-disk resources.
    53  - __*Content*__: Provides access to content addressable storage. All immutable
    54    content will be stored here, keyed by content hash.
    55  - __*Snapshot*__: Manages filesystem snapshots for container images. This is
    56    analogous to the graphdriver in Docker today. Layers are unpacked into
    57    snapshots.
    58  - __*Events*__: Supports the collection and consumption of events for providing
    59    consistent, event driven behavior and auditing. Events may be replayed to
    60    various _modules_
    61  - __*Metrics*__: Each components will export several metrics, accessible via
    62    the metrics API. (We may want to promote this to a subsystem.
    63  
    64  ## Client-side components
    65  
    66  Some components are implemented on the client side for flexibility:
    67  
    68  - __*Distribution*__: Functions for pulling and pushing images
    69  
    70  ## Data Flow
    71  
    72  As discussed above, the concept of a _bundle_ is central to containerd. Below
    73  is a diagram illustrating the data flow for bundle creation.
    74  
    75  ![data-flow](data-flow.png)
    76  
    77  Let's take pulling an image as a demonstrated example:
    78  
    79  1. Instruct the Distribution layer to pull a particular image. The distribution
    80     layer places the image content into the _content store_. The image name and
    81     root manifest pointers are registered with the metadata store.
    82  2. Once the image is pulled, the user can instruct the bundle controller to
    83     unpack the image into a bundle. Consuming from the content store, _layers_
    84     from the image are unpacked into the _snapshot_ component.
    85  3. When the snapshot for the rootfs of a container is ready, the _bundle
    86     controller_ can use the image manifest and config to prepare the execution
    87     configuration. Part of this is entering mounts into the execution config
    88     from the _snapshot_ module.
    89  4. The prepared bundle is then passed off to the _runtime_ subsystem for
    90     execution. It reads the bundle configuration to create a running container.
    91