What a Docker image is and why you build one
A Docker image is a packaged snapshot of your process, its code, the libraries it needs, and the operating system layer it runs on. When you create an image, you are building a template that Docker can turn into a running container — the same way a blueprint becomes a building. The image itself does not run; it sits on your computer or a server until you tell Docker to start it.
You build an image so that your process runs the same way on your laptop, your coworker's machine, a test server, and a production server. Without an image, you spend time installing dependencies, configuring settings, and troubleshooting why something works on one computer but not another. An image eliminates that friction by bundling everything your process needs into one file.
Creating an image requires a Dockerfile — a text file with instructions that tell Docker how to assemble the image layer by layer. You write the Dockerfile, run a build command, and Docker reads those instructions and produces the image file.
Key Takeaways
- A Dockerfile is a plain text file containing step-by-step instructions that Docker reads to build an image, starting with a base image and adding your code and dependencies.
- The most common Dockerfile commands are FROM (to choose a base image), COPY (to add your files), RUN (to install software), and CMD (to set what runs when the container starts).
- You build an image by running docker build -t imagename . in the directory where your Dockerfile lives, and Docker creates the image locally on your machine.
- After building, you can run the image with docker run imagename, push it to a registry like Docker Hub so others can use it, or keep it private on your own system.
- Each line in a Dockerfile creates a layer, and Docker caches layers so rebuilding is faster if you only change the last few steps.
Writing your first Dockerfile
A Dockerfile is a text file with no file extension. Create it in the root directory of your project and name it exactly Dockerfile (capital D, no extension). Open it in any text editor — Notepad, VS Code, or whatever you use for code.
Every Dockerfile starts with a FROM instruction that names a base image. The base image is a pre-built image that already has an operating system and often a runtime (like Python or Node.js) installed. For a Python process, you might use FROM python:3.11. For a Node.js process, FROM node:18. For a straightforward Linux system with nothing pre-installed, FROM ubuntu:22.04. Docker Hub hosts thousands of base images; you choose one that matches what your process needs.
After FROM, add a WORKDIR instruction to set the working directory inside the container — the folder where your code will live. For example, WORKDIR /app creates a folder called app and makes it the active directory for all commands that follow.
Next, use COPY to move your process files from your computer into the image. COPY . . copies everything from your current directory on your machine into the working directory in the image. If you only want specific files, you can be more precise: COPY app.py requirements.txt . copies only those two files.
Installing dependencies and setting the startup command
After copying your files, use RUN to execute commands inside the image — typically to install software your process needs. For Python, you might run RUN pip install -r requirements.txt to install packages listed in a requirements file. For Node.js, RUN npm install installs packages from package.json. You can chain multiple RUN commands, but each one creates a new layer, so combining commands with && is more efficient: RUN apt-get update && apt-get install -y curl.
At the end of the Dockerfile, use CMD to specify what command Docker runs when the container starts. For a Python script, CMD ["python", "app.py"]. For a Node.js server, CMD ["node", "server.js"]. The CMD instruction tells Docker what to execute by default — it is the entry point for your container.
Here is a complete example for a Python process:
FROM python:3.11 WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . CMD ["python", "app.py"]
This Dockerfile starts with Python 3.11, sets the working directory to /app, copies the requirements file, installs dependencies, copies the rest of your code, and runs app.py when the container starts.
Building the image on your computer
Once your Dockerfile is written and saved, open a terminal or command prompt in the directory where the Dockerfile lives. Run the build command: docker build -t myapp:1.0 .. The -t flag tags the image with a name and version; myapp:1.0 is the name and tag. The dot at the end tells Docker to look for the Dockerfile in the current directory.
Docker reads the Dockerfile line by line, executes each instruction, and creates layers. The first build takes longer because Docker downloads the base image and installs everything. Subsequent builds are faster because Docker caches layers — if you only change the last line, Docker reuses all the previous layers and only rebuilds from that point forward.
When the build finishes, Docker prints a message with the image ID. You can now see your image by running docker images in the terminal, which lists all images on your computer. Your image will appear with the name and tag you specified.
Running a container from your image
After building, start a container from your image by running docker run myapp:1.0. Docker creates a new container from the image and executes the CMD instruction you specified in the Dockerfile. If your process is a web server, add -p 8000:8000 to map port 8000 on your computer to port 8000 in the container: docker run -p 8000:8000 myapp:1.0. Then open your browser to localhost:8000 to see the process running.
If you want the container to run in the background, add the -d flag: docker run -d -p 8000:8000 myapp:1.0. To stop the container, run docker stop followed by the container ID (which you can find with docker ps).
Sharing your image with others
If you want others to use your image, push it to a registry. Docker Hub is the most common public registry. Create a free account at hub.docker.com, then tag your image with your username: docker tag myapp:1.0 yourusername/myapp:1.0. Log in to Docker Hub from your terminal with docker login, then push the image: docker push yourusername/myapp:1.0.
Once pushed, anyone can pull and run your image with docker run yourusername/myapp:1.0. If you want to keep your image private, Docker Hub offers private repositories, or you can run your own registry on a server you control. For most projects, keeping the image on your own computer is fine — you do not need to share it unless you are deploying to a server or collaborating with others.
Common mistakes and how to avoid them
One frequent mistake is copying files before installing dependencies. If you change your code and rebuild, Docker has to reinstall everything because the layer order changed. Instead, copy your dependency files first (requirements.txt or package.json), install them, then copy your code. That way, if only your code changes, Docker reuses the dependency layer.
Another mistake is making images too large. Every file you copy and every package you install adds size. Use a .dockerignore file (similar to .gitignore) to exclude files you do not need in the image — node_modules, .git, test files, and temporary files. A smaller image builds faster, pushes faster, and starts faster.
A third mistake is running your process as root inside the container. For security, create a non-root user in the Dockerfile with RUN useradd -m appuser and switch to that user with USER appuser before running your process. This limits the damage if your process is compromised.
Frequently Asked Questions
Do I need Docker installed to create a Dockerfile?
You need Docker installed to build and run the image, but you can write the Dockerfile in any text editor without Docker. However, you cannot test the image until you have Docker running on your computer.
What is the difference between a Dockerfile and a Docker image?
A Dockerfile is the recipe — the text file with instructions. A Docker image is the finished product — the packaged process that Docker creates after reading the Dockerfile. The image is what you run to create containers.
Can I edit a Docker image after I build it?
You do not edit an image directly. Instead, you edit the Dockerfile and rebuild the image. Docker creates a new image from your updated instructions. The old image remains on your computer until you delete it with docker rmi imagename.
Why does my image build take so long the first time?
The first build downloads the base image (which can be hundreds of megabytes) and installs all dependencies. Subsequent builds are faster because Docker caches layers. If you change only your code, Docker skips the base image and dependency installation and rebuilds only the layers that changed.
Can I use a Dockerfile for any programming language?
Yes. Docker works with Python, Node.js, Java, Go, Ruby, PHP, and any other language. You choose a base image that includes the runtime you need, then add your code and dependencies. The process is the same regardless of language.