docker
docker-image
containerization
tutorial
devops

How to create new docker image based on existing image?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

The normal way to create a new Docker image from an existing one is to write a Dockerfile that starts with FROM. That approach is reproducible, reviewable, and easy to rebuild in CI. Docker also offers docker commit, but that is usually for temporary snapshots rather than a maintainable build workflow.

Start with a Base Image

Every child image begins by selecting a parent image:

dockerfile
FROM python:3.12-slim

After that, each Dockerfile instruction creates a new filesystem layer or image metadata change on top of the base. A simple application image might look like this:

dockerfile
1FROM python:3.12-slim
2
3WORKDIR /app
4COPY requirements.txt .
5RUN pip install --no-cache-dir -r requirements.txt
6
7COPY . .
8CMD ["python", "main.py"]

This is the standard pattern because anyone on the team can read it and rebuild the exact same image later.

Build and Test the Child Image

Once the Dockerfile exists, build it from the directory that contains the Dockerfile and your application files.

bash
docker build -t my-python-app:latest .
docker run --rm my-python-app:latest

The first command produces the new image. The second confirms that the inherited environment plus your new layers actually start the way you expect.

If the base image already defines a command or entrypoint, inspect it before assuming your child image will behave the way you think:

bash
docker image inspect python:3.12-slim \
  --format '{{json .Config.Entrypoint}} {{json .Config.Cmd}}'

That small check prevents a lot of startup confusion.

Build on Internal or Prebuilt Images

The parent does not have to be an official image from Docker Hub. Many organizations publish internal base images with security hardening, certificates, standard users, or runtime tools already installed.

dockerfile
1FROM registry.example.com/platform/java-runtime:2026.03
2
3COPY app.jar /app/app.jar
4CMD ["java", "-jar", "/app/app.jar"]

This is often the preferred approach in production because platform teams can patch the base image separately while application teams focus on only the top layer.

Keep the Build Context Small

When you create a child image, everything in the build context is potentially sent to the Docker daemon. That affects build speed and can accidentally leak files into the image. Use .dockerignore to exclude junk and local artifacts.

text
1.git
2node_modules
3__pycache__
4dist
5*.log

This matters for performance, but it also matters for security and repeatability.

Use docker commit Only for Exceptional Cases

You can snapshot a modified container into a new image:

bash
docker commit my-running-container debug-snapshot:latest

That can be useful when:

  • you are preserving a debugging environment
  • you need a quick emergency snapshot
  • you are exploring changes interactively

But it is a poor long-term workflow because the steps that created the image are not encoded anywhere. A committed image is hard to review and hard to rebuild from scratch.

Consider Multi-Stage Builds

If the application needs build tools but the final runtime should stay small, multi-stage builds are often better than piling everything into one image.

dockerfile
1FROM golang:1.24 AS build
2WORKDIR /src
3COPY . .
4RUN go build -o app .
5
6FROM debian:stable-slim
7WORKDIR /app
8COPY --from=build /src/app .
9CMD ["./app"]

This still creates a new image based on an existing image, but it avoids shipping compilers and build caches in the final runtime layer.

Tag and Publish Deliberately

If the new image will be deployed, tag it with something traceable instead of relying only on latest.

bash
docker tag my-python-app:latest registry.example.com/team/my-python-app:2026.03.07
docker push registry.example.com/team/my-python-app:2026.03.07

Clear tags make rollbacks and incident analysis much easier.

Common Pitfalls

  • Using docker commit as the primary build process instead of a Dockerfile.
  • Choosing a base image that is much larger than the runtime actually needs.
  • Copying the entire repository into the image without .dockerignore.
  • Forgetting to verify inherited CMD or ENTRYPOINT.
  • Publishing only latest and losing a clear link between source and artifact.

Summary

  • Use FROM in a Dockerfile to create a child image from an existing image.
  • Build and test the new image instead of assuming the inherited behavior is correct.
  • Internal base images are common and often preferable in production environments.
  • Use .dockerignore and multi-stage builds to keep the final image lean.
  • Reserve docker commit for temporary snapshots, not the normal delivery workflow.

Course illustration
Course illustration