---
title: "10 — The Docker CLI: Containers and Networks in Day-to-Day Use"
uid: docker-cli
tags: ["operations", "networks", "roadmap:docker", "docker", "containers", "cli", "commands"]
excerpt: "The Docker CLI is noun-verb — `docker <noun> <verb>` — and almost everything daily is `docker container <verb>` or `docker network <verb>`."
date: 2026-08-13T03:28:13+0000
source: https://www.aveshina.my.id/en/blog/docker-cli
---

The Docker command surface felt like a wall of unrelated verbs until I noticed its grammar. The structure that surfaced: **the Docker CLI is noun-verb — docker <noun> <verb> — and almost everything I do is docker container <verb> or docker network <verb>, with images and volumes following the same pattern.** [1][3]

The framing worth holding onto is that the older single-word commands (docker run, docker ps, docker stop) and the newer grouped commands (docker container run, docker container ls, docker container stop) are the *same operations* [2]. Docker reorganized the CLI into management groups so that every object — container, image, volume, network — has a consistent verb set. Once I learned the noun-verb shape, the surface stopped feeling sprawling and started feeling small.

## The grammar

```figure
<svg viewBox="0 0 720 240" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-2xl" role="img" aria-label="The Docker CLI as noun-verb. A central box reads docker <noun> <verb>. Four labeled noun boxes branch from it: container, image, volume, network. Under each, a small stack of verbs: container has run/ls/exec/logs/stop/rm; image has build/ls/pull/push/rm; volume has create/ls/rm; network has create/ls/connect/inspect.">
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">

    <rect x="240" y="20" width="240" height="44" rx="8" fill="#1e1b4b" stroke="#6366f1" stroke-width="1.5"/>
    <text x="360" y="46" font-family="ui-monospace, monospace" font-size="14" font-weight="700" fill="#e0e7ff" text-anchor="middle">docker &lt;noun&gt; &lt;verb&gt;</text>

    <!-- four nouns -->
    <g font-size="11" font-weight="700" text-anchor="middle">
      <rect x="40"  y="100" width="140" height="28" rx="6" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.4"/>
      <text x="110" y="119" fill="#1e1b4b">container</text>
      <rect x="210" y="100" width="140" height="28" rx="6" fill="#fef9c3" stroke="#ca8a04" stroke-width="1.4"/>
      <text x="280" y="119" fill="#422006">image</text>
      <rect x="380" y="100" width="140" height="28" rx="6" fill="#fce7f3" stroke="#db2777" stroke-width="1.4"/>
      <text x="450" y="119" fill="#500724">volume</text>
      <rect x="550" y="100" width="140" height="28" rx="6" fill="#dcfce7" stroke="#16a34a" stroke-width="1.4"/>
      <text x="620" y="119" fill="#052e16">network</text>
    </g>

    <!-- connector lines -->
    <g stroke="#94a3b8" stroke-width="1.2" fill="none">
      <path d="M360,64 L110,100"/>
      <path d="M360,64 L280,100"/>
      <path d="M360,64 L450,100"/>
      <path d="M360,64 L620,100"/>
    </g>

    <!-- verbs -->
    <g font-family="ui-monospace, monospace" font-size="9.5" text-anchor="middle">
      <g fill="#1e1b4b">
        <text x="110" y="150">run · ls · exec</text>
        <text x="110" y="166">logs · stop · rm</text>
      </g>
      <g fill="#422006">
        <text x="280" y="150">build · ls · pull</text>
        <text x="280" y="166">push · rm</text>
      </g>
      <g fill="#500724">
        <text x="450" y="150">create · ls</text>
        <text x="450" y="166">rm · inspect</text>
      </g>
      <g fill="#052e16">
        <text x="620" y="150">create · ls</text>
        <text x="620" y="166">connect · inspect</text>
      </g>
    </g>

    <text x="360" y="210" font-size="10" font-style="italic" fill="#64748b" text-anchor="middle">same verb set per object; same operations as the legacy short forms</text>
  </g>
</svg>
```

That grammar is the whole shape of the surface. The same four verbs — ls, inspect, rm, and a domain-specific one (run for containers, build for images, create for volumes/networks) — appear for every object, so learning one noun teaches the pattern for the rest [1].

## Container commands

Containers are the noun I touch most. The day-to-day set, in management-group form [2]:

```
docker container run -d --name api -p 8080:3000 my-app:1.0  # start one
docker container ls                                          # running containers
docker container ls -a                                       # include stopped
docker container logs -f api                                 # tail logs (follow)
docker container exec -it api sh                             # shell inside
docker container stop api                                    # graceful stop (SIGTERM)
docker container rm api                                      # remove stopped container
docker container inspect api                                 # full config as JSON
```

These all have short aliases — docker run, docker ps, docker exec — and in practice I type the short forms. But the grouped form is what makes the CLI teachable: every object behaves the same way, and docker container ls -a parallels docker volume ls and docker network ls exactly [1][2].

Two commands deserve special mention because they're where I spend most debugging time. docker logs -f <name> follows a container's stdout in real time — the single most useful debug tool, given a well-logging app. docker exec -it <name> sh drops me into a shell in the live container, where I can env, ls, curl localhost, and otherwise poke the running process without restarting it [1].

## Network commands

Networks are the second noun I touch whenever more than one container is involved. By default, Docker gives every container a network — but the default **bridge** network isolates containers from each other's names, which is almost never what I want. The pattern I use is to create a named network and attach my services to it, so they can reach each other by container name [4][5]:

```
docker network create appnet
docker run -d --name db --network appnet postgres:16
docker run -d --name api --network appnet -e DATABASE_URL=postgres://db:5432/app my-app:1.0
```

On appnet, the api container can resolve the hostname db to the database container's IP — Docker runs an embedded DNS server for each user-defined network [4]. That's the whole magic behind the postgres://db:5432/... connection string in a Compose file: the service name resolves because they're on the same network.

Docker ships three network drivers worth knowing [4]:

- **bridge** — the default, a virtual network on the host. The user-defined bridge (what I create above) adds DNS resolution between containers; the default bridge does not.
- **host** — the container shares the host's network stack directly. No isolation, but maximum performance. Mainly useful on Linux.
- **overlay** — spans multiple Docker hosts (used with Swarm), so containers on different machines can talk as if on the same LAN.

The diagnostic verbs are the same as for containers: docker network ls lists them, docker network inspect appnet shows which containers are attached and what IPs they got, docker network connect appnet api attaches a running container to an additional network, and docker network rm appnet removes one [5].

## The other two nouns

Images and volumes round out the surface, and they obey the same grammar. docker image ls, docker image rm, docker image pull; docker volume create, docker volume ls, docker volume rm. I won't expand on them — they're covered in the registries and persistence posts — but I mention them here because they're what completes the picture. Four nouns, same verbs, that's the CLI.

## System-wide inspection

A few commands sit above the noun-verb structure and are worth knowing exist:

```
docker system df            # disk used by images, containers, volumes
docker system prune         # remove stopped containers, dangling images, unused networks
docker stats                # live CPU/mem/net per running container
docker info                 # daemon config, storage driver, counts
```

docker system prune is the one I run periodically on dev machines, where images and stopped containers accumulate into gigabytes of cruft. In production I'm more careful — prune removes anything not currently in use, which is rarely what I want a server to do to itself.

## How I use this

The grammar is the habit. When I can't remember a command, I reconstruct it from docker <noun> <verb> — "list volumes? docker volume ls", "inspect this network? docker network inspect appnet" — and I'm right almost every time without looking it up. When debugging, my loop is docker container ls to find the container, docker logs -f <name> to read what it's complaining about, and docker exec -it <name> sh to poke it if the logs aren't enough. And when I'm wiring up a multi-container app, I reach for a named bridge network and service-name DNS — that single pattern replaces every fragile -p port-forward chain I used to build. The CLI's grammar is small; leaning on it is what keeps it small.

## References

[1] Docker, Inc., "Use the Docker command line," Docker Docs, 2024. [Online]. Available: [https://docs.docker.com/engine/reference/commandline/cli/](https://docs.docker.com/engine/reference/commandline/cli/)

[2] Docker, Inc., "docker (base command) reference," Docker Docs, 2024. [Online]. Available: [https://docs.docker.com/reference/cli/docker/](https://docs.docker.com/reference/cli/docker/)

[3] Docker, Inc., "Docker CLI cheat sheet (PDF)," Docker Docs, 2024. [Online]. Available: [https://docs.docker.com/get-started/docker_cheatsheet.pdf](https://docs.docker.com/get-started/docker_cheatsheet.pdf)

[4] Docker, Inc., "Docker networking overview," Docker Docs, 2024. [Online]. Available: [https://docs.docker.com/network/](https://docs.docker.com/network/)

[5] Docker, Inc., "docker network subcommands," Docker Docs, 2024. [Online]. Available: [https://docs.docker.com/engine/reference/commandline/network/](https://docs.docker.com/engine/reference/commandline/network/)

```quiz
Q: The Docker CLI is organized as…
- a flat list of unrelated verbs
- noun-verb: docker <noun> <verb>, with a consistent verb set per object
correct: 1
explain: Every object (container, image, volume, network) has the same management verbs — ls, inspect, rm, plus a domain-specific one. The legacy short forms are aliases for the grouped commands.

Q: Two containers are attached to the default bridge network. Can the api container resolve the hostname db?
- Yes, the default bridge has built-in DNS for all containers
- No — only user-defined bridge networks provide automatic name resolution between containers
correct: 1
explain: The default (legacy) bridge does not provide DNS between containers. Create a named network with docker network create and attach both containers to it; then service names resolve.

Q: Which command drops you into an interactive shell in a running container?
- docker logs -it api
- docker exec -it api sh
correct: 1
explain: docker exec runs a new process inside the running container; -it gives it an interactive tty. sh is the typical shell in minimal images (bash may not be present).

Q: Why is `docker system prune` run cautiously on a production host?
- It restarts all running containers
- It removes anything not currently in use — stopped containers, dangling images, unused networks, volumes — which may include things you wanted
correct: 1
explain: prune aggressively reclaims disk by deleting unused objects. On a dev machine that's fine; on a host where unused images are intentionally cached for quick rollback, it's destructive.

Q: The `overlay` network driver is used to…
- share the host's network stack with a container for maximum performance
- span containers across multiple Docker hosts so they communicate as if on one LAN (used with Swarm)
correct: 1
explain: bridge is single-host, host shares the host stack, and overlay creates a virtual network across multiple hosts so containers on different machines can reach each other by name.
```
