Skip to main content
Docker Basics Tutorial
CHAPTER 05 Beginner

Creating Custom Docker Images

Updated: May 15, 2026
25 min read

# CHAPTER 5

Creating Custom Docker Images

1. Introduction

Using pre-built images from Docker Hub is only half of the Docker equation. If you are a developer writing a custom Python API or a PHP web application, you need to package *your* code into an image so you can send it to the production server. This is achieved by writing a Dockerfile. In this chapter, we will learn how to author a Dockerfile, understanding the step-by-step instructions required to build a custom, production-ready blueprint.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Define what a Dockerfile is and its purpose.
  • Understand core Dockerfile instructions: FROM, WORKDIR, COPY, RUN, CMD.
  • Execute the docker build command to compile an image.
  • Understand the concept of Docker Image Layers and caching.
  • Build a custom image containing a simple web application.

3. Beginner-Friendly Explanation

Imagine baking a cake using a highly strict recipe. A Dockerfile is the recipe card. It contains exact, sequential instructions.
  1. 1. FROM: Go to the store and buy a pre-made vanilla cake base. (Start with an official base image, like Python or PHP).
  1. 2. WORKDIR: Put the cake base on the kitchen counter. (Set the working directory).
  1. 3. COPY: Take the chocolate frosting from your fridge and put it on the cake. (Copy your custom code from your laptop into the container).
  1. 4. RUN: Put the cake in the oven at 350 degrees. (Run an installation command, like npm install).
  1. 5. CMD: Serve the cake to the guests. (The final command that keeps the container alive).

When you run docker build, the Docker Engine reads the recipe card top-to-bottom and bakes your custom Image.

4. Core Dockerfile Instructions

A Dockerfile is a simple text file named exactly Dockerfile (no extension).
  • FROM <image>: This MUST be the first line. It defines your base operating system. Example: FROM php:8.2-apache.
  • WORKDIR /path: Creates a folder inside the container and makes it the active directory. All subsequent commands happen here. Example: WORKDIR /var/www/html.
  • COPY <source> <destination>: Copies files from your laptop into the container. Example: COPY . . (Copies everything from the current laptop folder into the current container folder).
  • RUN <command>: Executes a terminal command *during the build process*. Used to install software. Example: RUN apt-get update && apt-get install git.
  • EXPOSE <port>: Documentation only. Tells the user which port the app runs on. Example: EXPOSE 80.
  • CMD ["executable", "param"]: The default command that runs *when the container starts*. Example: CMD ["php", "-S", "0.0.0.0:80"].

5. Image Layers and Caching

Every single line in a Dockerfile creates a new Layer. Docker is incredibly smart. If you build an image, and then change one line of your HTML code and build it again, Docker does not rebuild the entire operating system from scratch. It utilizes Cache. It skips the FROM and RUN layers because they haven't changed, and only rebuilds the COPY layer where the HTML was modified. This makes rebuilding images take seconds instead of minutes.

6. Mini Project: Dockerize a PHP Application

Let's package a custom PHP script into a container.

Step-by-Step Tutorial:

  1. 1. On your laptop, create a new folder called my-php-app. Open your terminal and cd into it.
  1. 2. Inside the folder, create a file named index.php and add this code:

php
123
<?php
echo "<h1>Hello from my Custom Docker Container!</h1>";
?>
  1. 3. Inside the same folder, create a file named exactly Dockerfile (no .txt extension) and add this code:
dockerfile
1234567891011
# Step 1: Use the official PHP image with an Apache web server included
FROM php:8.2-apache

# Step 2: Set the working directory to Apache's default web folder
WORKDIR /var/www/html

# Step 3: Copy our index.php file into the container
COPY index.php .

# Step 4: Expose port 80
EXPOSE 80
  1. 4. Now, let's "bake" the image! Run the build command (don't forget the . at the end, which means "look in this current directory for the Dockerfile"):
bash
1
docker build -t my-custom-php-app:v1 .
  • -t: Tags (names) the image.
  1. 5. Once built, run your brand new custom image!
bash
1
docker run -p 8080:80 my-custom-php-app:v1
  1. 6. Open your browser to http://localhost:8080. You will see your custom PHP code running!

7. Real-World Scenarios

A Node.js developer writes an app. Instead of emailing a zip file of their code to the operations team and writing a 5-page manual on how to install Node, run npm install, and start the server, they simply write a 10-line Dockerfile. The operations team types docker build and the application is guaranteed to compile and run flawlessly, entirely independent of the developer's machine.

8. Best Practices

  • Order Matters for Caching: Because Docker caches layers top-to-bottom, you should place instructions that rarely change (like RUN npm install or RUN apt-get install) at the TOP of the Dockerfile, and instructions that change constantly (like COPY . . for your source code) at the BOTTOM. If you copy your code *before* installing dependencies, Docker will reinstall the dependencies every single time you change a typo in your HTML!

9. Common Mistakes

  • RUN vs. CMD Confusion: This is the #1 beginner mistake.
  • RUN executes *while the image is being built* (e.g., installing a library).
  • CMD executes *when the container is finally launched* (e.g., starting the web server). If you try to start the web server using RUN, the server will start during the build process, hang indefinitely, and the build will fail.

10. Exercises

  1. 1. What is the purpose of the . at the end of the docker build -t my-app . command?
  1. 2. Explain the functional difference between the RUN instruction and the CMD instruction in a Dockerfile.

11. FAQs

Q: Can a Dockerfile have multiple FROM statements? A: Yes! This is an advanced concept called a "Multi-Stage Build." It is used to compile code in Stage 1 (which requires heavy compiler tools), and then copy only the finished, compiled code into Stage 2 (a tiny, lightweight image) to keep the final production image as small as possible.

12. Interview Questions

  • Q: Explain the concept of Docker Image Layers and the Build Cache. How would you structure a Dockerfile to optimize cache usage for a Node.js application?
  • Q: Describe the step-by-step process of converting a legacy, non-containerized application into a Dockerized application using a Dockerfile.

13. Summary

In Chapter 5, we became Image authors. We introduced the Dockerfile as the declarative recipe for packaging custom software. We dissected the essential instructions—FROM, WORKDIR, COPY, RUN, and CMD—understanding how each instruction creates an immutable layer within the image. Finally, we executed the docker build command to compile our custom PHP application, proving that we can package and distribute our own code flawlessly without relying entirely on pre-built Hub images.

14. Next Chapter Recommendation

Our custom container works perfectly, but if we delete the container, any data generated inside it is destroyed. How do we save files permanently? Proceed to Chapter 6: Docker Volumes and Persistent Storage.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·