14.3.1.1 Single Service Deployment
A focused guide to Single Service Deployment, connecting core concepts with practical Docker and container operations.
Single service deployment refers to deploying one application as its own independent, self-contained deployable unit, with its own image, its own lifecycle, and its own scaling decisions, as distinct from a multi-service stack where several interdependent containers are deployed and managed together as one coordinated unit.
Distinguishing single service from single container
A single service can still run multiple replicas for redundancy; what makes it a single service deployment is that exactly one logical application is being deployed and managed, independently of any other service, rather than the number of running container instances behind it:
docker run -d --name my-api-1 my-api:1.4.0
docker run -d --name my-api-2 my-api:1.4.0
docker run -d --name my-api-3 my-api:1.4.0
services:
api:
image: my-api:1.4.0
deploy:
replicas: 3
Both examples represent a single service deployment, with three replicas, deployed and updated together as one unit, independently of whatever other services might exist elsewhere in the broader system.
When single service deployment is the right shape
A single service deployment is appropriate when an application is genuinely self-sufficient: it owns its own data store or connects to one externally, has no tight coupling to other internally developed services that must be deployed in lockstep with it, and can be deployed, scaled, and rolled back without coordinating those actions against any other service's deployment schedule.
docker compose -f docker-compose.yml up -d --no-deps api
The ability to deploy this one service with --no-deps, without needing to also restart or redeploy anything else, is a useful practical test of whether a service genuinely qualifies as independently deployable in this sense.
Independent versioning and release cadence
A key benefit of single service deployment is that the service's release cadence is entirely its own; it can be deployed multiple times a day, or once a quarter, without that decision affecting or being affected by any other service's schedule:
docker build -t registry.example.com/my-api:1.5.0 .
docker push registry.example.com/my-api:1.5.0
docker service update --image registry.example.com/my-api:1.5.0 my-api
This independence is one of the primary motivations for decomposing a larger system into separate services in the first place; a monolith deployed as a single unit forces every component inside it onto the same release schedule, while genuinely independent single service deployments do not.
Networking a standalone service
A single service deployment still needs a defined way for clients, whether external users or other internal services, to reach it, typically through a published port or a service discovery mechanism rather than direct container-to-container linkage:
docker run -d -p 443:3000 --name my-api my-api:1.4.0
services:
api:
image: my-api:1.4.0
networks:
- public
networks:
public:
external: true
Connecting to a shared, external network rather than defining the network inline as part of the service's own Compose file keeps the service's deployment definition genuinely self-contained, since it does not need to also define infrastructure shared with other services.
Configuration and secrets remain self-contained
A single service deployment should own its own configuration and secrets, rather than depending on values defined as part of another service's deployment:
services:
api:
image: my-api:1.4.0
env_file:
- api-production.env
secrets:
- api_db_password
A service that reads its configuration from a file or secret defined and managed elsewhere as part of a different service's deployment has a hidden dependency that undermines the independence the single service deployment pattern is meant to provide.
Observability scoped to the service
Logging, metrics, and tracing for a single service deployment should be identifiable and queryable independently of any other service, so an operator investigating an issue with this specific service is not forced to sift through another service's signal to find what is relevant:
docker run -d --name my-api --log-opt tag="my-api" my-api:1.4.0
const logger = createLogger({ service: 'my-api', version: '1.5.0' });
Tagging logs and metrics with the service's own name and version, consistently, is a small but important practice that keeps a single service deployment genuinely separable for debugging purposes, even when its logs are aggregated into the same centralized system as every other service's.
Scaling decisions made independently
Because a single service deployment is not coupled to any other service's lifecycle, its scaling decisions, replica count, resource limits, autoscaling thresholds, can be tuned purely based on its own traffic and resource usage pattern, without needing to account for another service's resource needs sharing the same scaling decision:
docker service scale my-api=6
services:
api:
deploy:
replicas: 6
resources:
limits:
memory: 512M
cpus: "1"
Common mistakes
- Defining a service's configuration or networking in a way that quietly depends on another service's deployment having already happened, undermining its claimed independence.
- Coupling a service's deployment schedule to another service's release process out of habit, even when no genuine technical dependency requires it.
- Sharing a single image or container across what are conceptually two different services, blurring the boundary that single service deployment is meant to establish.
- Failing to scope logs and metrics by service name and version, making it harder to isolate one service's behavior once several are aggregated into the same observability tooling.
- Treating "single service" as meaning "single container," and therefore avoiding the redundancy of multiple replicas even when the service's availability requirements call for it.
Single service deployment is fundamentally about independence: a service that can be built, configured, deployed, scaled, and rolled back entirely on its own terms, regardless of how many replicas it runs, is a single service deployment in the sense that matters for production operations.