What a Docker image is and why you build one

A Docker image is a blueprint — a frozen snapshot of everything your process needs to run. It contains your code, the programming language it uses, libraries, configuration files, and the exact operating system layer it expects. When you run that image, Docker creates a container from it, the same way every time.

You build an image so you can move your process between your laptop, a colleague's computer, and a production server without anyone saying "it works on my machine but not yours." The image guarantees that the container running on all three will behave identically because it carries its own environment with it.

Building an image is not something Docker does for you automatically. You write a recipe called a Dockerfile, and Docker reads that recipe and constructs the image layer by layer. This guide walks you through writing that recipe and running the command that builds it.

Key Takeaways

  • A Dockerfile is a text file with instructions that tell Docker how to build an image, starting from a base image and adding your code and dependencies on top.
  • The most common Dockerfile instructions are FROM (which base image to start with), COPY (which files to add), RUN (which commands to execute), and CMD (what to run when the container starts).
  • You build the image by running docker build -t imagename . in the directory where your Dockerfile lives, and Docker reads the Dockerfile and creates the image layer by layer.
  • After building, you can run docker run imagename to start a container from that image, and the container will behave the same way every time because it carries its own environment.
  • Most images start FROM a public base image like python:3.11 or node:18, so you do not have to build an operating system from scratch.

The Dockerfile: the recipe Docker reads

A Dockerfile is a plain text file with no file extension. You create it in the root directory of your project, name it exactly Dockerfile (capital D, no dot), and fill it with instructions. Each instruction is a command that Docker executes when building the image.

Here is a minimal Dockerfile for a Python process:

FROM python:3.11 WORKDIR /app COPY . . RUN pip install -r requirements.txt CMD ["python", "app.py"]

Read this top to bottom: start with the official Python 3.11 image, set the working directory inside the container to /app, copy everything from your computer into the container, run pip to install the packages listed in requirements.txt, and when someone runs the container, execute python app.py.

The Dockerfile does not run on your computer. It runs inside the container environment that Docker is building. So when you write RUN pip install, pip runs inside the container, not on your machine, and the packages land in the container's filesystem, not yours.

Understanding the four instructions you will use most

FROM is always the first instruction. It tells Docker which base image to start with. You are not building an operating system from scratch — you are starting with a pre-built image that already has an OS, a language runtime, and common tools. FROM python:3.11 means "start with the official Python 3.11 image from Docker Hub." FROM node:18 means "start with Node.js 18." FROM ubuntu:22.04 means "start with Ubuntu 22.04 with no language runtime pre-installed."

WORKDIR sets the directory inside the container where Docker will execute commands and where files will land when you copy them. WORKDIR /app means "create the /app directory if it does not exist, and make it the current directory." Every RUN, COPY, and CMD instruction that comes after it will run inside /app. If you do not set a WORKDIR, Docker uses /, which is messy.

COPY takes files from your computer and puts them into the container. COPY . . means "copy everything from the current directory on my computer into the current directory in the container" (which is /app because of the WORKDIR above). COPY requirements.txt . means "copy only requirements.txt." You can also copy specific directories: COPY src/ src/ copies the src folder from your computer into a src folder in the container.

CMD tells Docker what command to run when someone starts a container from this image. CMD ["python", "app.py"] means "run python app.py." This is the last instruction in most Dockerfiles. When you run docker run imagename, Docker starts the container and executes the CMD. If the command exits, the container stops.

Building the image on your computer

Once you have written your Dockerfile, open a terminal, navigate to the directory where the Dockerfile lives, and run this command:

docker build -t myapp:1.0 .

Break this down: docker build tells Docker to build an image. -t myapp:1.0 tags the image with a name and version — myapp is the name, 1.0 is the version. The dot at the end means "use the Dockerfile in the current directory." Docker reads the Dockerfile, executes each instruction in order, and creates the image.

The build process takes time because Docker is downloading the base image (if you do not have it already), copying your files, running pip or npm or whatever package manager you specified, and layering everything together. You will see output on your screen showing each step. If a step fails, Docker stops and tells you which instruction caused the problem.

After the build finishes, the image exists on your computer. You can list all your images by running docker images. You will see myapp listed with the tag 1.0 and a size in megabytes.

Running a container from your image

Now that the image exists, you can run a container from it:

docker run myapp:1.0

Docker creates a container from the myapp:1.0 image and executes the CMD instruction you wrote in the Dockerfile. If your CMD was CMD ["python", "app.py"], then your Python process starts running inside the container. You see its output in your terminal. When the process exits, the container stops.

If you want to run the container in the background and get your terminal prompt back, add the -d flag:

docker run -d myapp:1.0

Docker prints a container ID and returns your prompt. The container is still running in the background. You can list running containers with docker ps and stop one with docker stop containerId.

Common mistakes when writing a Dockerfile

The most common mistake is forgetting to copy your code into the container. If your Dockerfile has FROM and RUN but no COPY, the container will have the language runtime and dependencies but not your actual process. The container will start and then when ready exit because there is nothing to run.

Another mistake is putting COPY before RUN when you need to install dependencies. If your process depends on packages listed in requirements.txt, you must COPY requirements.txt first, then RUN pip install. If you reverse the order, pip will not find the file.

A third mistake is using the wrong base image. If you write a Node.js process and start with FROM python:3.11, the container will have Python but not Node.js, and your process will fail. Match the base image to your language and version.

Finally, do not put large files or sensitive data (like passwords or API keys) in your project directory if you are going to COPY everything with COPY . .. Those files will end up in the image and anyone who has access to the image can read them. Use a .dockerignore file (similar to .gitignore) to exclude files you do not want copied.

Moving your image to another computer or server

Once you have built an image, you can move it to another computer or push it to a registry so others can use it. The simplest way to move it is to save it as a tar file:

docker save myapp:1.0 > myapp.tar

This creates a file called myapp.tar on your computer. You can copy that file to another computer and load it:

docker load < myapp.tar

The image now exists on the second computer and you can run containers from it. For sharing with a team or deploying to production, most people push the image to a registry like Docker Hub. That requires creating an account, tagging the image with your registry username, and running docker push. The registry stores the image and anyone with permission can pull it and run it.

Frequently Asked Questions

Do I need to install anything on my computer besides Docker to create an image?

No. Docker includes everything you need. You do not need to install Python, Node.js, or any other language on your computer if you are only building Docker images. The base image you specify in the FROM instruction brings those tools into the container.

What is the difference between an image and a container?

An image is the blueprint — the file that sits on your computer. A container is a running instance of that image. You can build one image and run ten containers from it, and each container is isolated from the others. Stopping one container does not affect the others.

Can I edit a Dockerfile after I have built an image?

Yes. Edit the Dockerfile and run docker build again with the same tag. Docker rebuilds the image with your changes. Old versions of the image remain on your computer until you delete them with docker rmi imagename:oldversion.

What does the dot at the end of docker build mean?

The dot tells Docker where to find the Dockerfile and what directory to use as the build context. docker build -t myapp . means "build using the Dockerfile in the current directory, and when you see COPY instructions, copy from the current directory." If your Dockerfile is in a subfolder, use the path to that folder instead: docker build -t myapp ./docker.

Why is my image so large?

Base images are often hundreds of megabytes because they include an operating system, a language runtime, and common libraries. If you are copying large files or installing many packages, the image grows. You can reduce size by using a smaller base image (like alpine instead of ubuntu), removing unnecessary files after installation, and using multi-stage builds — but for most applications, a few hundred megabytes is normal and acceptable.