← System design and delivery · Chapter 2

Trace responsibility from containers to clusters

Use a stateless preview API to distinguish images, instances, probes, scheduling resources, and infrastructure state, then check ownership across container and cluster delivery.

After this guide, you can

Specify disposable instances and verify resource budgets, probe failure behavior, and narrowly scoped cloud permissions.

A document-preview API reads files from object storage and returns a public summary. With no local persistent business data, it is a useful containerization exercise. Packaging the program is only part of delivery: someone still owns runtime permissions, process health, traffic routing, resource budgets, and changes to cloud resources.

The teaching budget is eight CPU units and sixteen memory units. Two sets of instances request different amounts. These are simplified units, not a cloud instance specification or a measured throughput result.

Separate an image from a running instance

An image contains user-space programs, dependencies, and a default startup method. A container is an isolated process started from an image and normally shares the host kernel. A virtual machine has its own operating-system kernel. Images reduce dependency differences, while architecture, kernel capabilities, configuration, and external services still affect behavior.

An image tag can be moved to different content. Record the digest, source commit, build environment, and locked dependencies to trace a release. A tag called stable does not establish that it points to yesterday's tested image. Where possible, test and promote the same built artifact.

Do not copy secrets into a build and delete them in a later layer. Earlier layers and logs can retain them. Inject configuration and credentials through controlled runtime mechanisms. A non-root process, fewer writable directories, and reduced capabilities limit the impact of compromise, but container isolation does not replace security design.

Make instances disposable

A new preview instance must be able to continue work. Uploaded objects, completed results, and database records belong in named persistent systems. Local temporary files should contain reconstructable intermediate data. Define what happens when a restart removes them instead of assuming one instance stays alive indefinitely.

Shutdown has an order: stop admitting new requests, allow bounded time for existing work, then exit. Long operations often need durable background jobs so a rolling release does not leave users uncertain about completion. External storage has its own permissions, backup requirements, and failure behavior.

At the single-container stage, check startup arguments, missing configuration, port binding, log output, and exit codes. Successful startup with defaults does not establish that production networking and permissions work. The offline example here does not run Docker or validate an image.

Orchestration reconciles desired state

Kubernetes controllers observe actual state and try to bring it toward declared state, such as a specified Pod count. A Pod is a basic scheduling and execution unit. A Service provides stable access and routes traffic to eligible backends. Restarting a container, replacing a Pod, and scheduling a replacement on another node are different events.

Readiness indicates whether an instance should receive traffic. A failing instance should leave the eligible backend set. Liveness detects states that require a restart to recover. A startup probe accommodates slow initialization so other probes do not repeatedly declare the process broken. Probe endpoints need low cost, reliability, and appropriate timeouts and failure thresholds.

If a brief database outage makes every liveness probe fail, restarts will not fix the database and can add startup load. Distinguish process deadlock, dependency failure, and business rejection. Readiness failure can also remove every backend, so observe the effect and define degradation behavior.

Requests and limits have different effects

Estimate CPU and memory requests before choosing limits and replica counts. Requests express the resources scheduling needs to reserve. Limits constrain runtime use. Memory exhaustion may terminate a process, while CPU limits may increase processing latency. Test the actual behavior in the chosen environment.

The following example compares total requests with one budget. It assumes complete resource fields and nonnegative values, and it does not use a Kubernetes scheduler.

capacity = {"cpu": 8, "memory": 16}
pods = [{"cpu": 2, "memory": 4}, {"cpu": 3, "memory": 6}]
def fits(items):
    return all(sum(p[resource] for p in items) <= maximum
               for resource, maximum in capacity.items())
assert fits(pods)
assert not fits(pods + [{"cpu": 4, "memory": 2}])
print(fits(pods))

The actual output is True. The first two instances request five CPU units and ten memory units. Adding a request for four more CPU units raises the total to nine, which exceeds the budget of eight.

Aggregate capacity is only a necessary check. Real placement considers each node's capacity, reserved resources, taints, affinity, zones, and storage constraints. A cluster may have enough total memory yet no individual node capable of hosting a large Pod. Check downstream capacity before scaling, because extra instances can amplify database pressure.

Infrastructure code needs state and permissions

Terraform configuration declares resources, a plan describes intended changes, and state maps configuration to actual resources. Git supports configuration review, while state may contain sensitive values and requires protected storage. Configure concurrent-change locking where the selected backend supports it.

Review every creation, modification, and destruction in a plan. Confirm the environment, resource identifiers, and dependencies. Rolling back application code does not restore deleted cloud resources. Manual console changes create drift; explain that difference before incorporating it into configuration or restoring the previous state.

Cloud IAM separates the deployment identity from the runtime identity. This API needs to read a defined object scope in one environment; creating clusters or modifying permissions belongs to the delivery process. Prefer manageable workload identities and temporary credentials where the platform supports them. One administrator key combines several responsibility boundaries.

Exercise: make each responsibility concrete

Write a delivery specification containing an image digest, startup arguments, temporary directories, persistent storage, probe meanings, resource requests and limits, and the runtime identity's access scope. Include instance replacement, dependency outage, missing configuration, and insufficient capacity.

Accept the design when a new instance can start using the image and controlled configuration, replacement preserves completed business data, dependency failures avoid endless restarts, and unauthorized storage operations are denied. Extend the budget function to reject missing fields and negative values and to model per-node placement. Record the scheduling conditions it still excludes. A later real deployment needs its own platform, configuration, and observed results; offline assertions are not cluster verification.

Sources & further reading

Sources checked on 2026-11-10. Original engineering explanation; examples are teaching data, not production measurements.