An image that builds is not an image that runs. When a built container exits at once, its log names the problem, and the cause is usually one Dockerfile line.
From error to line
| Log or build output | Dockerfile cause |
|---|---|
can't open file '/app/server.py' | CMD names a file that is not in the image |
ModuleNotFoundError: No module named 'flask' | No RUN pip install -r requirements.txt |
"/server.py": not found during the build | COPY names a file that is not in the build context |
Error: Cannot find module 'express' (Node) | No RUN npm install |
Look inside the image
The image is the evidence. Override the command to list it:
docker run --rm signup-web ls /appapp.py
requirements.txtdocker image history signup-web lists every instruction the image was built from, newest first. A step that is not in the list never ran.
Rebuild, then recreate
edit Dockerfile
│
▼
docker compose build web new image signup-web:latest
│
▼
docker compose up -d web is recreated from the new image ID
│
▼
docker compose logs web read the next error, or the startup linesdocker compose up -d --build does the first two steps in one command. docker compose build alone changes nothing that is running.
Keep the cache useful
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
CMD ["python", "app.py"]Dependencies change rarely and code changes often, so dependencies go first. A rebuild after editing app.py reports CACHED for the install step.