Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

Short answer: A Dockerfile is the recipe used at build time, a Docker image is the layered artifact produced by that recipe, and a container is a running instance of the image with its own writable layer. Docker Compose is a separate, runtime-oriented description of one or more services, their images, networks, ports, environment variables, mounts and dependencies.

That distinction explains most everyday Docker behavior. Rebuilding an image does not automatically migrate data written inside an old container, changing a Compose file is not the same as changing a Dockerfile, and deleting a container removes files stored only in its writable layer. Volumes, rather than the container filesystem, are the usual persistence mechanism.

The four concepts, in the order Docker uses them

1. Dockerfile: build instructions

A Dockerfile is a text file containing instructions for constructing an image. It describes what should happen while the image is being built, not how a complete application stack should run in production.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Instruction What it does during a build Typical purpose
FROM Selects the base image. Starts from an operating-system or language-runtime image.
RUN Executes a command and records the result in a new layer. Installs packages, compiles code or creates directories.
WORKDIR Sets the working directory for subsequent instructions. Keeps later RUN, COPY and command paths predictable.
COPY Adds files from the build context to the image. Places application source, manifests or configuration in the artifact.
CMD Defines the default program and arguments when a container starts. Supplies the normal process for the image, while still allowing an override at run time.

Each build instruction contributes to the image’s layers. A small change can therefore invalidate the layer at that point and the layers after it, while unchanged earlier layers may be reused. The Dockerfile is the repeatable description; the image is the result you can tag, distribute and start.

2. Image: the built, layered artifact

An image is made from read-only layers. Those layers contain the filesystem and metadata needed to start an application, such as the runtime, installed dependencies and files copied from the project. Images are not running processes and do not have a lifecycle of their own in the way containers do.

You can build an image from a Dockerfile with a command such as:

docker build -t demo-web:dev .

The final argument is the build context, here the current directory. The resulting tag identifies a particular image version for local use. A Compose service can either refer to such an image with image: or describe how to build one with a build: section.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

3. Container: a runtime instance

When Docker starts an image, it creates a container. The container has the image’s read-only layers plus a thin writable layer associated with that particular instance. Processes, network identity and runtime settings belong to the container, not to the image.

Writing a file in that writable layer does not change the image. If the container is removed, those writes disappear. Starting a new container from the same image gives you a fresh writable layer, which is why a container should not be treated as a database or document archive.

4. Compose: a runtime application model

Compose uses a YAML file, commonly named compose.yaml, and the Compose CLI to declare services and their runtime configuration. A service is an application component that can be started as one or more containers from the same image and configuration. Compose also creates the network relationships that let services reach one another by service name.

“A Dockerfile provides instructions to build a container image while a Compose file defines your running containers.” — Docker Docs, Compose overview

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A Compose file can combine a locally built application with a dependency pulled from an existing image. That is the practical boundary: the Dockerfile defines how one image is made; Compose defines how the resulting services cooperate.

How a Dockerfile becomes a running process

  1. Write the build recipe. Choose a base with FROM, set a WORKDIR, copy dependency manifests and source files, run installation or compilation commands, then specify a default CMD.
  2. Build the image. Docker executes the instructions in order and stores the resulting read-only layers.
  3. Create a container. Docker adds a writable layer and assigns runtime settings such as environment variables, mounts, ports and a network.
  4. Start the container’s main process. The process specified by CMD runs unless a command is supplied at startup.
  5. Replace rather than edit the artifact. If the application code or dependencies change, rebuild the image and recreate the container instead of assuming edits to one container update every future instance.

A minimal single-service workflow might look like this:

docker build -t demo-web:dev .
docker run --rm -p 8080:8080 demo-web:dev

The --rm option removes the container after it stops. That is convenient for a disposable test, but it also emphasizes that files written only inside the container are not a persistence strategy.

What Compose adds for multi-service applications

Most real applications need more than one process: for example, a web application and a Redis service. Compose puts the relationship in one declarative file instead of requiring a long sequence of individual docker run commands.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
services:
  web:
    build: .
    ports:
      - "8080:8080"
    environment:
      REDIS_URL: redis://redis:6379
    depends_on:
      - redis
  redis:
    image: redis:7

In this example, web is built from the Dockerfile in the current directory. redis uses an existing image directly. Compose places the services on a network where the web service can address Redis by the hostname redis; the application should not use localhost for that cross-service connection because, inside the web container, localhost refers to the web container itself.

The service definition is the place for runtime concerns such as:

  • Which image to run, or which directory to build.
  • Published host ports and container ports.
  • Environment variables supplied at startup.
  • Bind mounts or named volumes.
  • Dependencies and service startup relationships.
  • Additional network and lifecycle settings.

Compose can start one service or the whole model, inspect status, stream logs, stop services and rebuild images. It is useful in development and can also describe repeatable environments in CI, staging and production when its operational limits and environment-specific settings are handled deliberately.

docker compose up versus docker compose run

Command Purpose What Compose starts Typical use
docker compose up Creates and starts the services in the Compose model. The application stack described by the file, including required service relationships. Run the web application and its dependencies for normal development or an environment deployment.
docker compose up --build Builds service images before starting the model. The rebuilt services plus their dependencies. Use after changing a Dockerfile, copied dependency files or other content that belongs in the image.
docker compose run <service> <command> Runs a one-off command for a selected service and its dependencies. A temporary container for that task rather than the entire application stack. Run tests, a migration or an interactive maintenance command.

For example, with a service named web, docker compose run web pytest is conceptually different from docker compose up: the first asks for a task-specific container, while the second brings up the declared application services. If the task needs a newly built image, build first or use the appropriate build option before running it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Where application data lives

Docker offers three practical storage choices. Select one by asking who needs to see the files, how long they must survive and who should manage the storage.

Storage type Lifecycle Management and host visibility Good fit
Container writable layer Exists only for that container; removed with the container. Managed as part of the container filesystem; not a durable host data location. Temporary runtime output, caches or disposable experiments.
Volume Independent of an individual container and can survive container replacement. Docker-managed; normally accessed by containers rather than edited directly on the host. Database files and other data generated and consumed by containers.
Bind mount Follows the host path’s lifecycle. The host and container see the same files. Local source-code development when edits on the host should appear immediately in the container.
tmpfs mount Exists only during the current container session. Stored in memory rather than persisted on disk. Ephemeral data that should disappear when the container stops.

Development pattern: source bind mount, state volume

A common development arrangement is to bind-mount the project source so the container sees host edits, while placing database state in a named volume. The two mounts solve different problems: one optimizes the edit-and-run loop, and the other protects state when the database container is recreated.

services:
  web:
    build: .
    volumes:
      - .:/workspace
  db:
    image: postgres:16
    volumes:
      - db-data:/var/lib/postgresql/data
volumes:
  db-data:

The exact paths and database image depend on the application. The principle is to choose a bind mount when host access is required, a volume when Docker-managed persistence is required, and tmpfs when persistence is specifically unwanted.

Build-time configuration versus runtime configuration

Put facts needed to create the artifact in the Dockerfile: the base runtime, operating-system packages, dependency installation, compiled assets and files copied into the image. Put deployment-specific values in Compose or another runtime system: port mappings, environment variables, mounts, service dependencies and restart behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

This separation keeps one image reusable across environments. A development Compose file might mount source code and expose a host port; a production variant can omit the source mount, set production environment values, use a different restart policy and add or remove services. The image itself need not be rebuilt merely because a port mapping or environment value changes, although a code or dependency change normally requires rebuilding.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

A practical Compose development workflow

  1. Place the Dockerfile and Compose file in the project. Keep the build context narrow enough that irrelevant files are not copied into the image.
  2. Declare the application service. Use build: . when the service comes from local source, and list the port, environment and development mounts it needs.
  3. Add dependencies as services. Use image: for a dependency that already has a suitable image, and attach a named volume when its data must survive replacement.
  4. Start the model. Run docker compose up --build when an image rebuild is needed; otherwise docker compose up can reuse existing images.
  5. Inspect behavior. Use Compose status and log commands to identify whether a failure is in image creation, container startup, networking or the application process.
  6. Run one-off tasks separately. Use docker compose run <service> <command> for tests, migrations and shells that should not become the permanent service process.
  7. Recreate after relevant changes. Changes to a Dockerfile, image contents or service configuration may require rebuilding and recreating the affected service so the running container receives them.
  8. Stop the environment deliberately. Stopping services leaves the declared data resources available according to their storage type; removing a container still does not remove an external volume automatically.

Using Compose beyond a laptop

Compose is not limited to local development. Docker documents using Compose in CI, staging and production, with environment-specific files or overrides for differences such as source-code mounts, published host ports, environment settings, restart policies and additional services.

A production-oriented file should be explicit about which development conveniences are removed. Source bind mounts are often replaced by the immutable image; host ports may be narrowed or omitted behind a proxy; production environment values should be supplied through the deployment mechanism; and restart behavior should match the host’s operational expectations. After changing application code, rebuild the service image and recreate the service so the running deployment is based on the new artifact.

Compose can describe this setup, but the choice of orchestration and operations model remains a system-design decision. The documentation establishes that Compose can be used in production scenarios; it does not make Compose the universal answer for every scale, availability or scheduling requirement.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Common mistakes and how to correct them

“I changed a file in the container, so the image is updated.”

The writable layer belongs to one container and cannot modify the image’s read-only layers. Change the source or Dockerfile, rebuild the image and recreate the container. If the file is application data that must persist, move it to a volume or an intentionally chosen bind mount.

“Deleting and recreating the database container deleted my data.”

That is expected when the data lived only in the writable layer. Attach a named volume at the database’s data directory and verify the mount before deleting the old container.

“Compose and Dockerfile are interchangeable.”

They operate at different stages. The Dockerfile builds one image; Compose declares running services and their relationships. A Compose service may invoke a Dockerfile through build:, but the YAML does not replace the build instructions.

“The application cannot reach its dependency at localhost.”

Inside a container, localhost points back to that same container. Use the dependency’s Compose service name and its container port on the shared network.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

“I edited the Dockerfile, but the old behavior is still running.”

The running container was created from the previous image. Use docker compose up --build or an explicit rebuild, then recreate the service. Confirm the image and container status if the old process remains.

A compact decision guide

  • Need to define how software is assembled? Write or modify the Dockerfile.
  • Need a portable, layered artifact? Build an image.
  • Need to start that artifact with a process and runtime settings? Create a container.
  • Need several services, networks, ports, mounts and dependencies in one model? Use Compose.
  • Need files to survive container replacement? Use a volume or a deliberately selected bind mount, not the writable layer.
  • Need a one-off test or migration? Use docker compose run; need the declared stack? Use docker compose up.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.