How to Create, Start, Stop, and Remove Docker Containers: Essential Container Lifecycle Commands

How to Create, Start, Stop, and Remove Docker Containers

How to Create, Start, Stop, and Remove Docker Containers

Somewhere in my first month of using Docker, I realized I was typing docker run for everything, even in situations where I actually wanted to just start a container that already existed. That habit worked, but it hid an important truth: containers have a full lifecycle with distinct states, and each state has its own commands. Once I learned to move deliberately between “create,” “start,” “stop,” “pause,” and “remove,” debugging got a lot easier because I finally understood what state a misbehaving container was actually in.

The Container Lifecycle at a Glance

A Docker container moves through these states:

Created → Running → Paused → Stopped → Removed

Creating a Container Without Starting It

docker create --name my-nginx -p 8080:80 nginx:latest

Expected output:

a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890

That long string is the container ID. At this point, nothing is running yet — I can confirm with:

docker ps -a
CONTAINER ID   IMAGE          COMMAND                  STATUS    NAMES
a1b2c3d4e5f6   nginx:latest   "/docker-entrypoint.…"   Created   my-nginx

Starting a Container

docker start my-nginx
my-nginx

Checking status again:

docker ps
CONTAINER ID   IMAGE          STATUS         PORTS                  NAMES
a1b2c3d4e5f6   nginx:latest   Up 3 seconds   0.0.0.0:8080->80/tcp   my-nginx

docker run: Create and Start in One Step

In practice, I almost always use docker run, which combines create and start:

docker run -d --name web1 -p 8081:80 nginx:latest
b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3

The -d flag runs it detached (in the background); I’ll cover this in more depth in a dedicated guide on detached mode.

Viewing Logs

docker logs web1
/docker-entrypoint.sh: Configuration complete; ready for start up
2026/07/29 10:15:22 [notice] 1#1: nginx/1.27.0
2026/07/29 10:15:22 [notice] 1#1: start worker processes

Follow logs live with -f:

docker logs -f web1

Stopping a Container

docker stop web1
web1

Internally, docker stop sends SIGTERM to the container’s main process (PID 1 inside the container), waits a grace period (10 seconds by default), and if the process hasn’t exited, sends SIGKILL. I can adjust the grace period:

docker stop -t 30 web1

Killing a Container Immediately

If I don’t care about a graceful shutdown — say, during quick local testing — docker kill sends SIGKILL right away:

docker kill web1

Restarting a Container

docker restart web1

This is functionally a stop followed by a start, useful when an app needs to reload configuration or recover from a hung state.

Pausing and Unpausing

docker pause web1
docker unpause web1

Pausing uses the Linux cgroups freezer subsystem to suspend all processes in the container without terminating them — useful for temporarily reclaiming CPU without losing in-memory state.

Removing a Container

Once a container is stopped, its filesystem and metadata still exist on disk until removed:

docker rm web1
web1

Trying to remove a running container fails safely:

docker rm web2
Error response from daemon: cannot remove container "/web2": container is running: stop the container before removing or force remove

Force-remove (stops and removes in one step) when I’m sure:

docker rm -f web2

Combining Stop and Remove for Cleanup

A pattern I use constantly during development:

docker rm -f $(docker ps -aq)

This stops (implicitly, via -f) and removes every container on the host — I only ever run this on a dev machine, never on anything with production containers.

Removing Containers Automatically After They Exit

For throwaway test containers, --rm removes the container the moment it stops, so I don’t have to clean up manually:

docker run --rm alpine echo "this container will clean itself up"
this container will clean itself up

Checking afterward:

docker ps -a

No trace of the container remains.

Internal Working: What Happens at Each Stage

When I run docker create, the Docker daemon (dockerd), through containerd and runc, prepares a container’s root filesystem by stacking the image’s read-only layers with a new writable layer (via overlay2 on most Linux hosts), sets up its network namespace, and writes container metadata to /var/lib/docker/containers/<id>/config.v2.json. Nothing is executed yet.

docker start hands the prepared bundle to runc, which uses Linux namespaces (PID, network, mount, UTS, IPC) and cgroups to actually launch the process in isolation. From that point, the container’s PID 1 is a real Linux process on the host, just heavily namespaced.

docker stop and docker kill operate by sending POSIX signals directly to that PID 1 process. docker rm deletes the writable layer and metadata but never touches the underlying image layers, which is why removing containers never deletes images.

Networking and Storage Notes

Each container gets its own network namespace by default, connected to a bridge network (docker0 unless otherwise configured) via a virtual ethernet pair. Stopping a container tears down that network namespace; removing it releases the container’s IP back to Docker’s internal address pool. Data written to the container’s writable layer is lost on docker rm unless it lives in a bind mount or named volume — something worth checking before cleanup:

docker inspect -f '{{ range .Mounts }}{{ .Source }} -> {{ .Destination }}{{ "\n" }}{{ end }}' web1

Security Considerations

Troubleshooting

Container immediately shows “Exited (0)” after docker run This typically means the main process finished right away — common with containers whose default command is something like bash with no interactive terminal attached. Check with:

docker inspect -f '{{ .State.ExitCode }}' web1

“No such container” errors Usually a typo in the container name/ID, or the container was already removed. docker ps -a shows everything, running or not.

Container won’t stop, even with docker stop The main process may be ignoring SIGTERM. After the grace period, Docker sends SIGKILL, which cannot be ignored, so this should eventually succeed. If it truly hangs, check docker events for anomalies.

Monitoring

docker stats web1
CONTAINER ID   NAME   CPU %     MEM USAGE / LIMIT     MEM %     NET I/O
b2c3d4e5f6a7   web1   0.05%     3.2MiB / 1.944GiB     0.16%     1.2kB / 0B

Best Practices

Summary

The container lifecycle — create, start, stop, pause, remove — maps directly onto real Linux process and namespace mechanics, not just Docker-specific abstractions. Understanding which command touches which layer (metadata, writable filesystem, running process) makes debugging far more precise than treating docker run as a magic on/off switch.

References

Exit mobile version