Running and Managing Containers

beginner
12 min

Running and Managing Containers

You can start and stop a container - now it is time to truly manage them. This lesson covers the complete container lifecycle, interactive containers, restart policies, resource limits, and the inspection tools you will reach for when something goes wrong.

The Container Lifecycle

A container moves through a small set of states: created, running, paused, stopped (exited), and finally removed. The commands map directly onto these transitions:

bash
docker create --name app nginx # created, but not started docker start app # running docker pause app # paused (processes frozen) docker unpause app # running again docker stop app # graceful stop (SIGTERM, then SIGKILL) docker restart app # stop + start in one step docker rm app # gone

docker run is simply create plus start in one command. docker stop sends SIGTERM and waits ten seconds before forcing SIGKILL; use docker kill only when a container refuses to die.

Interactive Containers

For experimentation, run a container with an interactive terminal:

bash
docker run -it --rm ubuntu bash
  • -i keeps STDIN open, -t allocates a terminal - together they give you a usable shell.
  • --rm deletes the container automatically when you exit, keeping your system clean.

This pattern is perfect for testing commands in a throwaway Linux environment. Need Python for five minutes? docker run -it --rm python:3.12 python drops you straight into a REPL.

Executing Commands in Running Containers

docker exec runs an additional process inside a container that is already running:

bash
docker exec -it app sh # open a shell docker exec app ls /usr/share/nginx/html # run a one-off command

This is the standard way to debug: open a shell, check config files, test network reachability from inside the container.

Logs, Stats, and Inspect

Three commands answer most "what is happening?" questions:

bash
docker logs -f --tail 100 app # follow the last 100 log lines docker stats # live CPU, memory, and network usage docker inspect app # full JSON: config, network, mounts

docker logs shows everything the main process wrote to stdout and stderr - which is why containerized apps log to the console instead of files. docker inspect combined with a format string extracts specific fields:

bash
docker inspect -f "{{.NetworkSettings.IPAddress}}" app

Restart Policies

By default a crashed container stays down. Restart policies make containers self-healing:

bash
docker run -d --restart unless-stopped nginx
  • no - never restart (default)
  • on-failure - restart only when the app exits with an error code
  • always - restart on any exit, and on daemon startup
  • unless-stopped - like always, but respects a manual docker stop

For anything meant to run long-term, unless-stopped is the sensible choice.

Limiting Resources

A runaway container can starve the whole host. Cap its resources at run time:

bash
docker run -d --memory 512m --cpus 1.5 nginx

This container may use at most 512 MB of RAM and one and a half CPU cores. Setting limits is essential on shared servers.

Bulk Cleanup

Over time, stopped containers and unused images accumulate. Clean house with:

bash
docker container prune # remove all stopped containers docker system prune # also remove dangling images and networks docker system df # see what is using disk space

Key Takeaways

  • Containers move through created, running, paused, and exited states with matching commands.
  • -it --rm gives you disposable interactive environments for quick experiments.
  • docker logs, docker stats, and docker inspect are your primary debugging tools.
  • Use --restart unless-stopped for long-running services.
  • Apply memory and CPU limits so one container cannot starve the host.

Next up: Writing a Dockerfile, where you stop consuming other people's images and start building your own.

Running and Managing Containers - Docker | CodeYourCraft | CodeYourCraft