Use the Docker CLI Safely: Contexts, Containers and Cleanup
You will finish with a small, repeatable Docker CLI workflow: confirm which daemon you are addressing, run a disposable container, inspect its output, enter a running container when needed, and remove what you created. The examples match Docker 29.8.1 and the docker-ce-cli package installed here as 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 fifteen minutes. You need a shell, the Docker CLI, access to a Docker daemon, and an image that you are permitted to run. Most commands below are ordinary user commands. Access to the daemon socket can itself grant broad control over the host, so treat membership of the Docker group and access to a remote Docker endpoint as administrative privileges.
1. Confirm the CLI and its endpoint
Start with read-only checks. The top-level docker command is a client for a daemon, and its global options apply before the subcommand. Check the installed version and the active context:
$ docker --version
Docker version 29.8.1, build 4a63305
$ docker context ls
NAME DESCRIPTION DOCKER ENDPOINT
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock
The asterisk marks the selected context. Do not assume that docker is talking to the local machine: a context, DOCKER_HOST, or an explicit -H can select another endpoint. The CLI configuration directory defaults to ~/.docker; use --config DIRECTORY when a separate client configuration is required.
Checkpoint: ask the daemon for a compact health and version report:
$ docker info --format 'Server {{.ServerVersion}} / Containers {{.Containers}} / Images {{.Images}}'
Server 29.8.1 / Containers 49 / Images 30
Your counts will differ. If this fails with a socket or connection error, stop here. Changing the context or starting a service is a separate administrative task, and adding sudo blindly can hide the real endpoint and permission problem.
2. Check the image before creating anything
List local images and choose one you recognise. This is read-only:
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine 3 9234e837854f ... ...
Use an exact image reference in examples and scripts, such as alpine:3, rather than relying on whatever happens to be tagged latest. If the image is absent, docker run may pull it from a registry. That is a network and supply-chain decision: check the registry, image name, tag and trust policy before allowing a pull. Do not run an image from an untrusted source merely because its name looks familiar.
To discover the syntax of a command on this installed CLI, ask for its help:
$ docker run --help
Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
Create and run a new container from an image
3. Run a disposable container
Run a short command with --rm. It prints the container's output and removes the container after it exits:
$ docker run --rm --name cli-smoke-test alpine:3 sh -c 'printf "container-ok\n"'
container-ok
This creates a container, but the removal is automatic when the command finishes. The name is useful while the container exists and makes errors easier to read. The command inside the container is separate from the Docker CLI command: sh -c and everything after it are arguments for the image's process.
Do not add host networking, host filesystem mounts, extra capabilities or privileged mode to make a test convenient. Those options cross security boundaries. Start with the smallest container and permissions that answer the question.
Checkpoint: confirm that the disposable container did not remain:
$ docker ps -a --filter name=cli-smoke-test
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4. Keep a container for inspection
For a longer-lived test, detach a harmless process and give it a specific name:
$ docker run -d --name cli-inspection alpine:3 sh -c 'printf "started\n"; sleep 300'
7d2b...
The returned identifier is abbreviated here and is different on every run. Check its state and logs:
$ docker ps --filter name=cli-inspection
CONTAINER ID IMAGE COMMAND STATUS NAMES
7d2b... alpine:3 "sh -c 'printf ...'" Up ... cli-inspection
$ docker logs cli-inspection
started
docker ps shows running containers. Add -a to include stopped containers. Logs are the process output captured by the container's logging setup, not a shell history or a full application audit trail.
5. Execute a command without confusing it with a new container
Use docker exec only against a running container. It starts an additional process in that container; it does not create a second container:
$ docker exec cli-inspection sh -c 'printf "exec-ok\n"'
exec-ok
For an interactive shell, allocate a terminal and keep standard input open:
$ docker exec -it cli-inspection sh
/ # id
uid=0(root) gid=0(root) groups=0(root)
/ # exit
The root user inside a container is not automatically harmless. It may have access to mounted data or capabilities granted at creation. Treat an interactive shell as a debugging tool, not as a reason to edit production state manually. Prefer a reproducible image or deployment change when the fix must survive recreation.
6. Stop and remove what you created
Stopping is the reversible first action. It asks the container's main process to exit:
$ docker stop cli-inspection
cli-inspection
$ docker ps --filter name=cli-inspection
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
The stopped container still exists and can be inspected with docker ps -a. When you are certain that its filesystem changes, logs and metadata are no longer needed, remove it:
$ docker rm cli-inspection
cli-inspection
$ docker ps -a --filter name=cli-inspection
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Removal is destructive for the container's writable layer. It does not remove the image. Do not use docker rm -f casually: the -f option force-removes a running container and uses SIGKILL. If you attached anonymous volumes, review the command's volume options before adding -v, because that can remove data in those volumes. Named volumes and host bind mounts have their own lifecycle and need a separate review.
7. Diagnose the common failure paths
A missing image, a stopped container, a wrong context and a failed process are different problems. Use the object-specific checks rather than repeating the same command with more privilege:
Cannot connect to the Docker daemon: checkdocker context ls, the endpoint, and whether the daemon is available.pull access deniedor an unexpected pull: verify the image reference and registry, then check credentials with the approved authentication process.No such container: list all containers withdocker ps -a; names and context are local to the daemon you selected.- A non-zero application result: inspect
docker logs CONTAINERanddocker inspect CONTAINER; do not infer success from the container having been created.
For remote endpoints, TLS settings matter. The top-level CLI supports --tls, --tlscacert, --tlscert, --tlskey and --tlsverify. Use the certificates and endpoint supplied by the administrator. Never disable verification to get a connection working.
Done means
- You confirmed the Docker CLI version and selected context.
- You verified the daemon before creating a container.
- You used a known image and a disposable
--rmsmoke test. - You can distinguish
run,exec,ps,logs,stopandrm. - You stopped before destructive cleanup and understand what removal can delete.
- You would investigate the endpoint, image, container state or application output before reaching for elevated privileges.