The Container Is Not the Boundary: Designing ML Systems That Stay Simple as They Scale

tfc

Hatched by tfc

Aug 12, 2026

11 min read

88%

0

A team can spend months dividing an application into services, then discover that it has merely divided one problem into twelve deployment problems. Another team can place a large application in a single deployable unit and still achieve clearer boundaries, safer change, and faster delivery.

The difference is not whether software is packaged in containers. It is whether the boundaries that matter have been designed deliberately.

This distinction becomes especially important in machine learning systems. A model may need a reproducible build environment, specialized libraries, a predictable inference process, and the ability to run at scale. Containers solve much of that operational problem. But they do not automatically solve the architectural problem. A container can isolate software from its environment while leaving the software itself tangled inside.

The deeper lesson is this: deployment isolation and architectural modularity are different dimensions of design. Confusing them leads organizations to mistake a collection of independently packaged components for a system that is genuinely understandable and adaptable.

The seductive promise of the container

Containers are powerful because they make a software environment portable. Instead of hoping that a model behaves the same way on a developer’s laptop, a training machine, and a production service, a team can define the environment more explicitly: operating system libraries, language runtime, framework versions, dependencies, startup behavior, and the application itself.

For machine learning, this matters enormously. A model is not just a file containing learned parameters. It is a relationship among data preparation, code, numerical libraries, hardware assumptions, configuration, and serving logic. Change one part and the result may change in ways that are difficult to diagnose. A container provides a stable vessel for that relationship.

Cloud platforms use this idea at several points in the model life cycle. A prebuilt image can provide a supported framework and algorithm. A custom image can capture an organization’s specialized requirements. The same general mechanism can support training and inference, while the platform handles much of the surrounding infrastructure.

This is a major improvement over treating deployment as an improvised ritual. It allows teams to say, in effect: this is the environment in which this computational behavior is expected to work.

But the container’s greatest strength can also become its greatest source of confusion. Because a container is a visible boundary, teams may assume it is an architectural boundary. They see several images in a registry and infer that the system is modular. Yet the images may contain code that is tightly coupled, duplicate business rules, share undocumented assumptions, and require coordinated releases.

A container can be a carefully sealed room. It cannot decide whether the rooms in a building have been arranged intelligently.

A container makes a boundary operationally real. It does not make the boundary conceptually meaningful.

The overlooked middle ground: one deployable system, many coherent modules

A modular monolith offers a useful correction to the reflex that every meaningful boundary must become a network boundary. It keeps an application in one deployable unit while organizing the code into modules with explicit responsibilities and controlled dependencies.

Imagine an online lending application with modules for customer identity, credit assessment, loan pricing, repayment, and notifications. In a tangled monolith, any part of the code may reach into any other part. In a modular monolith, the application can still be built and deployed as one unit, but each module exposes a deliberate interface. The pricing module does not directly manipulate the repayment module’s internal tables. The notification module receives a defined event or command rather than discovering private implementation details.

This arrangement preserves many benefits associated with service oriented systems. Teams can reason about ownership. Tests can target meaningful units. Changes can be localized. Internal implementation can evolve without forcing every other part of the application to understand it.

At the same time, the organization avoids some costs of distributed deployment: network failures, serialization formats, service discovery, version skew, duplicated observability, complex local development, and the need to operate many independently changing systems.

The point is not that a modular monolith is always superior. The point is that modularity is primarily about dependency control, not process count. A system becomes modular when its parts can change with limited knowledge of one another. Whether those parts run in one process or several is a later decision.

This idea has particular force in machine learning. A production prediction system often contains several logically distinct concerns:

  • Data validation and feature preparation
  • Model selection and loading
  • Prediction and postprocessing
  • Business policy and decision thresholds
  • Monitoring, logging, and feedback collection

These concerns do not automatically deserve separate services or separate containers. They do deserve clear interfaces.

For example, a model may output a probability of default. A business policy may convert that probability into an approval decision based on risk appetite, regulation, and product rules. If the policy is embedded invisibly inside model code, changing a lending threshold may require rebuilding and redeploying the entire modeling environment. If the two concerns are separated inside a well structured application, policy can evolve without corrupting the model’s technical boundary.

The operational unit can remain simple while the intellectual structure becomes precise.

The real design question is not “How many services?”

Architecture discussions often begin with the wrong measurement. Teams ask how many services they should create, how many containers they should run, or whether a system is monolithic enough to be considered modern. These are easy questions to count, but poor questions to guide design.

A more useful question is: Which changes should be allowed to travel together, and which changes should be able to move independently?

Consider three kinds of change in an ML platform:

  1. Updating a numerical library because of a security vulnerability.
  2. Retraining a model because new data has arrived.
  3. Changing the business rule that determines how predictions are acted upon.

These changes have different risk profiles and different owners. A numerical library update may affect reproducibility and require broad validation. A model refresh may be frequent but should preserve the serving contract. A business rule change may need review by domain experts and regulators, not by the data science team alone.

If all three are forced into one indivisible artifact, delivery becomes unnecessarily slow. If each is split into a separate network service too early, the system acquires operational complexity before the boundaries have matured. A modular monolith provides a third option: keep the runtime arrangement simple while separating the change surfaces in code, configuration, testing, and release discipline.

This suggests a practical framework based on four forms of coupling:

Knowledge coupling

How much must one component know about another’s internals? A strong boundary minimizes this. A prediction component should not need to understand how a customer record is stored, and a policy component should not need to know which tensor library produced a score.

Change coupling

How often must two components be modified together? If a tiny adjustment in one area routinely requires edits across the system, the boundary is probably false or incomplete.

Failure coupling

When one component fails, what else becomes unavailable? Keeping components in one deployable unit may be acceptable when failures are expected to be rare, fast to detect, or safely contained. Separating them can make sense when independent failure behavior is a primary requirement.

Scaling coupling

Do components need resources at different rates? Model inference may require accelerators, while policy evaluation may be inexpensive. If one part needs to scale dramatically beyond the others, an independent runtime boundary may eventually be justified.

These four forms of coupling are more informative than the simple distinction between monolith and microservices. They tell us why a boundary exists and what benefit it is supposed to create.

Containers should follow boundaries, not invent them

A disciplined architecture can use containers at multiple levels without pretending that every container is a separate business capability.

At the broadest level, a container can package an entire modular application. This is often a sensible starting point for a model training or inference system. The application has one versioned runtime environment, one deployment process, and one clearly defined entry point. Internally, however, the code is divided into modules whose contracts are tested and documented.

At a later stage, one module may become a separate container if the reason is concrete. Perhaps model inference needs a hardware profile that the policy engine does not. Perhaps a preprocessing component is reused by several workloads. Perhaps a team needs to release it independently. Perhaps its failure must be isolated so that a monitoring pathway remains available when prediction is degraded.

The crucial sequence is first clarify the boundary, then choose the packaging. Reversing that sequence produces architecture by inventory. Teams look at the tools available, see that launching another container is easy, and create a new component because they can. The result is often a system with many physical boundaries and few meaningful ones.

A useful analogy is a commercial kitchen. Containers are like refrigerators or sealed storage units: they preserve ingredients and make handling predictable. Modules are like stations with defined responsibilities: pastry, grill, preparation, plating. A kitchen does not become well organized merely because every ingredient sits in its own refrigerator. The workflow depends on clear ownership, appropriate handoffs, and limited cross contamination.

Machine learning systems have their own forms of contamination. Training code may leak into serving code. Feature definitions may be duplicated between batch and online paths. Business decisions may be hidden inside model postprocessing. Configuration may be scattered across deployment scripts and application logic. Containers can preserve these problems with remarkable reliability.

Reproducibility is not the same as correctness. A container can reproduce a flawed dependency graph, an ambiguous data contract, or an untestable decision rule. Reliable packaging amplifies whatever structure it contains, good or bad.

A practical architecture for the next system you build

Suppose a team is building a service that predicts whether a transaction is fraudulent. The initial system needs a feature transformation pipeline, a model, a scoring endpoint, and a decision policy. The team expects frequent model retraining but only occasional changes to the policy.

A reasonable first design might use one deployable application packaged in a custom container. Inside it are four modules:

  • A feature module that validates inputs and produces a versioned feature representation.
  • A model module that loads a specified artifact and returns a score with metadata.
  • A policy module that translates the score into an action according to explicit rules.
  • An observability module that records inputs, outputs, latency, model version, and policy version.

Each module has a narrow interface. The model module does not decide whether to block a transaction. The policy module does not transform raw customer data. The observability module does not quietly alter the result it records.

The container defines the runtime contract: required dependencies, startup behavior, health checks, and resource assumptions. The modules define the intellectual contract: what each part means, what it accepts, and what it promises. Tests verify both levels.

This structure gives the team room to learn. If model inference later requires a specialized accelerator, the model module can become a separate service or container without redesigning the entire system. If the policy remains lightweight, it can stay where it is. If feature generation becomes a shared capability, it can be extracted after its interface has been proven through use.

Extraction then becomes an architectural consequence rather than a speculative act.

Before creating a new runtime boundary, ask five questions:

  1. Does this component have a stable and meaningful contract?
  2. Does it need to scale independently?
  3. Does it need a different security or hardware boundary?
  4. Would independent failure improve the system’s behavior?
  5. Can the team afford the operational cost of releasing and observing it separately?

If the answers are mostly no, a module inside the existing deployment may be the more mature choice. Simplicity is not an absence of architecture. It is often the result of architecture that has resisted unnecessary commitments.

Key Takeaways

  • Separate conceptual boundaries from deployment boundaries. First define responsibilities, interfaces, and ownership. Only then decide whether a boundary needs its own process or container.
  • Use change patterns as an architectural guide. Components that change for different reasons are candidates for modular separation, even when they remain in one deployable unit.
  • Treat containers as reproducibility tools, not proof of modularity. A container stabilizes an environment. It does not guarantee clean dependencies or coherent design.
  • Extract services in response to evidence. Independent scaling, failure isolation, hardware needs, security requirements, or team ownership are stronger reasons than fashion or numerical symmetry.
  • Keep model logic and decision policy distinct. A prediction is not a decision. Separating those concepts improves testing, governance, explainability, and future change.

The most sophisticated system is not the one with the most containers. It is the one whose boundaries correspond to real differences in responsibility, risk, and change.

A modular monolith and a containerized machine learning workload may seem like ideas from different architectural conversations. One concerns the shape of code, the other the packaging of execution. Together they reveal a more general principle: good architecture preserves the right kinds of independence without purchasing more complexity than the problem requires.

The question is therefore not whether your system is a monolith, a set of services, or a collection of containers. Ask instead what the system allows to change safely, what it forces to change together, and where failure or scale truly demands separation.

When those answers are clear, the technology becomes easier to choose. Containers become vessels rather than identities. Modularity becomes a property of thought and design rather than a count of running processes. And simplicity stops meaning “everything is in one place.” It starts meaning that every boundary has earned its cost.

Sources

← Back to Library

Hatch New Ideas with Glasp AI 🐣

Glasp AI allows you to hatch new ideas based on your curated content. Let's curate and create with Glasp AI :)

Start Hatching 🐣