3.5Compose troubleshooting: restarts and orphan volumes
The essentials in 30 seconds
- "Restarting": read before recreating: compose ps spots the sick one, service logs accuse it — fix the FILE, then up -d only recreates what changed.
- Busy port: move the left one: 8080 already in use = squatter on the host — change the host port (left), never the internal one; global docker ps unmasks it.
- Old builds, orphan volumes: target: up -d --build after code changes, volume ls for orphans — down -v only touches THIS project, with care.
Running mini-case — Idir and the ghost port
Idir, junior DevOps in Algiers, launches his stack one Monday: the api loops in Restarting, "port already allocated". Instead of razing everything, he diagnoses: compose ps spots the api, compose logs accuses the port, global docker ps unmasks an old forgotten manual run on 8080. He changes the HOST port to 8082 in the compose, up -d — the stack starts, data intact. The manual ghost is cleaned up afterwards, surgically. Since then, Idir reads before recreating.
This same case returns in the lesson, the diagram, the script and the 48h challenge.
1. Restarting and busy port: ps spots, logs accuse
Service in "Restarting": READ before recreating. docker compose ps spots the sick one, logs service-name accuses it — missing variable, volume at the wrong path, busy port. Fix the FILE, then up -d: Compose only recreates what changed, the rest keeps running. Declarative is surgical by nature: treat the description, not the containers.
The already used port (8080 already in use): another service — or an old run outside Compose — occupies the HOST port. Fix: change the host port (the left one, "8082:80"), never the container port; global docker ps unmasks the squatter. Two stacks getting mixed is often the same project name (folder) or the same host ports: isolate with -p and distinct ports.
2. Old builds and orphan volumes: target, don't raze
Code not updating after an up? The image was not rebuilt: up -d --build, not a furious rm. Renaming a service or project creates orphan volumes (dormant old data): docker volume ls shows them, and compose down -v only touches THIS project — with care, as it wipes its volumes. Cleaning means identifying first.
The three reflexes of the stack doctor: name projects (-p) when duplicated, read the service logs (not the whole stack), fix the file then relaunch. And the absolute ban: panicked down -v — never raze to diagnose. Idir stuck the sequence on the wall: ps → logs → fix → up -d.
🔎 Concrete example — Port taken by a ghost: full diagnosis
Idir runs the ps → logs → docker ps → file-fix sequence.
docker compose ps # api : Restarting ?
docker compose logs api # Error: port déjà utilisé ?
docker ps # un vieux run manuel sur 8080 ?
# Corriger le port HÔTE dans compose.yml : "8082:80"
docker compose up -d # ne recrée que ce qui change
Reading: the squatter was a forgotten manual run — unmasked by the global ps.
Lesson: change the host port (left), never the internal one; clean the ghost afterwards.
Section vocabulary
- Orphan
- Volume or project abandoned after a rename: dormant old data to identify before any cleanup.
Simple example: Idir's old pgdata after renaming the service.
What it is not: an active volume of the current project.
Reflex: volume ls first, delete knowingly.
- Squatter
- Process already occupying the target host port: old manual run or second stack on the same port.
Simple example: The forgotten manual run on 8080.
What it is not: a problem inside the service image.
Reflex: global docker ps to unmask.
- --build
- Force image rebuild at up: the changed code is really taken into account.
Simple example: Idir's up -d --build after each api change.
What it is not: a furious rm of containers to "force".
Reflex: changed code = --build, systematically.
- Project name
- Prefix isolating a stack's resources (-p, folder by default): two projects, two worlds.
Simple example: Idir isolates mock-up and sandbox with -p.
What it is not: two stacks mixing on the same ports.
Reflex: name when duplicated on one machine.
- Recreate (targeted)
- up -d only recreates modified services: declarative surgery, the rest runs.
Simple example: Only the api recreated after the port change.
What it is not: razing the whole stack "to be safe".
Reflex: fix the file, relaunch, verify.
In practice — Break then fix, with a scalpel
- Cause a busy port: manual run + compose on the same host port.
- Diagnose: compose ps, compose logs of the service, global docker ps.
- Fix the host port in the file and relaunch (up -d): only the service changes.
- Clean the manual ghost (rm -f) and check: green stack, data intact.
Ready-to-say script — announcing the failure and the fix (30 s)
"The api was looping: host port squatted by a forgotten old manual run. I moved the left port to 8082 in the compose, relaunched — only the service was recreated, data intact, ghost cleaned afterwards. No down -v, no loss."
Say in a team stand-up; show the ps → logs → fix sequence.
Copy-paste template — compose after port fix
# Après diagnostic : port hôte déplacé (gauche), interne inchangé.
services:
web:
image: nginx:1.27
ports:
- "8082:80"
networks:
- front
bdd:
image: postgres:16.4
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- front
volumes:
pgdata:
networks:
front:
# Diagnostique : compose ps, logs du service, docker ps global.
Freelancer
The ps → logs → fix → up -d sequence and your Monday mornings become calm again.
SME in Algiers
Idir puts the sequence on the wall: the team diagnoses before razing.
Project team
Ban down -v outside throwaway stacks; require the service log in every failure ticket.
Beginner
This week: cause a busy port on throwaway and fix it with a scalpel.
✓ Best practices
- Read the logs of the precise service, not the whole stack in bulk.
- Fix the file, relaunch: Compose only recreates what changed.
- Name projects (-p) as soon as two stacks share a machine.
✗ Common pitfalls
- Panicked down -v: the project's data is wiped.
- Changing the container (right) port instead of the host (left) port.
- Forgetting --build after a code change: the old image is still running.
Key takeaways
- PS spots, LOGS accuse, the FILE fixes: read before recreating.
- Busy PORT → move the HOST (left) port or kill the squatter.
- DOWN -v = project reset, with care — never a diagnosis.
- --BUILD after each image change; -p to isolate duplicates.
48h challenge — apply tomorrow
Cause 1 failure on throwaway (busy port) and fix it without -v, noting each diagnosis step.
- I diagnose ps → logs before any action.
- I move the host port, never the internal one.
- I never raze: -v only on decided reset.
Frequently asked questions
Why do two stacks get mixed?
Same PROJECT NAME (the folder by default) or same HOST PORTS: resources overlap. Isolate with -p project-name and distinct host ports. compose ps per project then shows two separate worlds — and global docker ps stays the referee when in doubt.
Must everything be recreated when one service changes?
NO: up -d only recreates modified services — that is the whole value of declarative. Fix the file, relaunch, verify: the rest keeps running, volumes stay. Razing everything "to be safe" destroys what declarative preserves.
Compose shows "port already allocated". What do you change?