List Docker Swarm Services Without Losing Detail
docker service ls is the first command to run on any Swarm host: one line shows what is running and whether it is at full strength. The examples use Docker CLI 29.8.1 from the installed docker-ce-cli package, version 5:29.8.1-1~ubuntu.24.04~noble.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about ten minutes. You need the Docker CLI and access to a Swarm manager. This command only lists services, so nothing here creates, updates or removes one. Do not reach for sudo just to make a listing work: a worker node or an unreachable daemon is a topology or connectivity problem, not usually a file-permission one.
1. Confirm the installed command
Start with the local help output. This is an ordinary, read-only command and does not contact the Swarm manager:
$ docker version --format '{{.Client.Version}}'
29.8.1
$ docker service ls --help
Usage: docker service ls [OPTIONS]
List services
The command has the alias docker service list, but stick to ls in scripts so it matches the installed manual and every example here. The default output is a table with headers, and the available options are --filter, --format and --quiet.
Checkpoint
If docker service ls --help is not available, stop and check the Docker CLI package is installed before you go anywhere near the Swarm.
2. List every service from a manager
Run the plain listing from a Swarm manager:
$ docker service ls
ID NAME MODE REPLICAS IMAGE
abc123def456 web replicated 3/3 nginx:alpine
fed654cba321 log-agent global 3/3 fluent/fluent-bit:latest
The exact IDs, names, images and counts are host-specific. In the table, REPLICAS shows actual tasks against the desired count. A value such as 2/3 is a useful warning that the service is not meeting its desired state, but it will not tell you why on its own: run docker service ps SERVICE_NAME separately for task placement and error detail.
This is a Swarm cluster-management command, and Docker's own client documentation says it must run on a manager node. A worker cannot answer a service-list request just because it can run ordinary local containers.
If Docker reports that the node is not a Swarm manager, move the command to a manager or switch to the context that points there. If it reports that the daemon cannot be reached, check the selected context and daemon connectivity first:
$ docker context show
$ docker info
$ docker service ls
docker info is read-only, but it can expose environment details in its output. Do not paste credentials, registry tokens or private hostnames into a public ticket.
3. Narrow the list with a supported filter
Filters use the form key=value. The supported service-list keys are:
idmatches an ID or ID prefix.labelmatches a label's presence, or a particular value.modematchesreplicatedorglobal.namematches a name or its prefix.
Quote the complete filter so shell metacharacters or whitespace cannot alter it. To find services whose names start with web:
$ docker service ls --filter 'name=web'
ID NAME MODE REPLICAS IMAGE
abc123def456 web replicated 3/3 nginx:alpine
789abc012def web-cache replicated 3/3 redis:7.4-alpine
The ID filter works the same way, on an ID or ID prefix:
$ docker service ls --filter 'id=abc123'
ID NAME MODE REPLICAS IMAGE
abc123def456 web replicated 3/3 nginx:alpine
For deployment checks, filter by mode:
$ docker service ls --filter 'mode=global'
A label filter can match presence or a specific value:
$ docker service ls --filter 'label=team'
$ docker service ls --filter 'label=team=platform'
Do not assume an unsupported filter silently does what you intended. Keep filters to these four documented keys, and check how your installed Docker version combines multiple --filter flags before you rely on it.
4. Produce a stable machine-readable view
Use --format when a human-oriented table is inconvenient. The installed manual supports a Go template, a table template, and the json directive, against these documented fields: .ID, .Name, .Mode, .Replicas, .Image and .Ports.
For a compact report with no headers:
$ docker service ls --format '{{.Name}}: {{.Mode}} {{.Replicas}}'
web: replicated 3/3
log-agent: global 3/3
Use the table directive when you want headers while still choosing the columns:
$ docker service ls --format 'table {{.Name}}\t{{.Mode}}\t{{.Replicas}}'
NAME MODE REPLICAS
web replicated 3/3
log-agent global 3/3
For one JSON object per service:
$ docker service ls --format json
{"ID":"abc123def456","Image":"nginx:alpine","Mode":"replicated","Name":"web","Ports":"","Replicas":"3/3"}
These examples show representative values, not promises about your cluster. Check the command's exit status before treating the output as records: a script should fail clearly when Docker cannot contact a manager, rather than reading an empty variable as an empty cluster.
5. Use quiet mode only for IDs
--quiet or -q prints only service IDs:
$ docker service ls --quiet
abc123def456
fed654cba321
Handy when another command accepts service IDs, but it deliberately drops names and status. If you need to identify a service in an alert or log, prefer a template containing both .ID and .Name.
Warning
Do not pipe an unreviewed ID list straight into a command that changes services. Listing is non-destructive, but scaling, updating and removing services change cluster state and need their own review, maintenance window and recovery plan.
6. Recover from misleading results
An empty result can mean no services match the filter, not that the Swarm has none at all. Rerun the plain command, then add the filter back one piece at a time:
$ docker service ls
$ docker service ls --filter 'name=THE_PREFIX_YOU_EXPECT'
$ docker service ls --filter 'label=THE_LABEL_YOU_EXPECT'
If the plain command fails, do not keep changing filters. Confirm the context with docker context show, check docker info, and verify the selected endpoint is a manager. If the listing shows a partial replica count, use the service name with docker service ps and inspect the task error before changing the service.
Recovery
There is no undo for docker service ls, because it never alters the cluster. The safe path is diagnostic: restore the intended context, repeat the unfiltered listing, and compare it with the manager you expected to be talking to.
Done means
- Confirmed the CLI. You checked the local Docker version and help syntax.
- Ran it against the right manager. Context and manager both matched what you intended.
- Told empty from broken. You can tell a filtered empty result from a failed manager connection.
- Used real filters. Only the supported
id,label,modeornamekeys. - Picked the right output. A template or JSON when a script needed stable fields.
- Kept it read-only. No scaling, updating or removing crept into the same session.