So far you have run images that other people built. The real power of Docker appears when you package your own applications, and the recipe for that is the Dockerfile - a plain text file describing, step by step, how to assemble an image. In this lesson you will learn the essential instructions and build a working image for a small Python web app.
Create a folder containing a file named Dockerfile (no extension) with this content:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]Build and run it from that folder:
docker build -t my-python-app .
docker run -d -p 5000:5000 my-python-appThe trailing dot tells Docker to use the current directory as the build context - the set of files available to COPY instructions.
RUN cd.COPY . . means "everything here into the current WORKDIR".-p still does that at run time.These three confuse everyone at first:
docker run my-python-app bash replaces the CMD entirely.docker run are appended to it instead of replacing it. A common pattern pairs them:ENTRYPOINT ["python", "app.py"]
CMD ["--port", "5000"]Here the entrypoint is fixed and CMD supplies overridable default arguments.
Notice the Dockerfile copies requirements.txt and installs dependencies before copying the rest of the code. This is deliberate. Docker caches each layer, and a layer is rebuilt only when its inputs change. Application code changes constantly, but dependencies change rarely - so ordering the Dockerfile this way means day-to-day rebuilds skip the slow pip install step and finish in seconds. This is the single most valuable Dockerfile habit to learn.
Just as git has .gitignore, Docker has .dockerignore. It keeps junk out of the build context, making builds faster and images cleaner:
.git
__pycache__
*.pyc
.env
node_modules
Excluding secrets like .env files also prevents them from being accidentally baked into an image.
ENV APP_ENV=production # set an environment variable
ARG VERSION=1.0 # build-time variable, not in the final container
LABEL maintainer="you@example.com"
USER appuser # run as a non-root userENV values persist in running containers; ARG values exist only during the build.
docker build -t name . turns it into an image..dockerignore to keep secrets and clutter out of your images.Next up: Building and Tagging Images, where you will master build contexts, tagging strategies, and pushing images to a registry.