Docker Fundamentals
itVirtualization, containers, and orchestration
Docker Fundamentals
Docker gives you a consistent way to package and run an application. You put the application and its runtime dependencies into an image. Docker starts an isolated process from that image as a container.
This model solves a common delivery problem. An application may work on one machine and fail on another because the operating system, libraries, files, or configuration differ. An image records the filesystem and default runtime configuration that the application expects. You can move that image through development, testing, and deployment without rebuilding the environment by hand.
Docker is more than the container process. The Docker client sends requests to Docker Engine. Docker Engine builds images, manages local objects, and starts containers. A registry stores images so other machines can pull them. Docker Compose describes a multi-container application in one YAML file.
The central workflow is short:
Write a Dockerfile → build an image → push or pull through a registry → run a container
Everything else supports that flow.
Why containers are useful
A container packages an application while still using the host operating system kernel. It does not boot a complete guest operating system for each workload. Docker uses operating-system features such as namespaces and control groups to isolate processes and account for resources.
That makes containers useful for repeatable application environments, local development, automated testing, service delivery, and short-lived jobs. You can replace a container from the same image instead of repairing its filesystem by hand.
Containers do not remove differences among processor architectures or operating-system kernels. An image must support the target platform. Linux and Windows containers also require compatible host capabilities. Treat an image as a repeatable application package, not as a universal machine snapshot.
The Docker architecture
The docker command is a client. It sends API requests to the Docker daemon, commonly called dockerd. The daemon manages images, containers, networks, and volumes. It can also communicate with registries during image pulls and pushes.
Docker Desktop packages Docker Engine, the Docker CLI, Docker Compose, and a graphical interface for local use. On macOS and Windows, Docker Desktop runs Linux containers through a Linux virtual machine. Docker Engine can also run directly on a supported Linux host.
This client-server boundary matters during troubleshooting. A command may fail because the client cannot reach the daemon, the daemon cannot reach a registry, or the containerized process exits. Those are different failures at different boundaries.
Images, layers, and Dockerfiles
An image is a read-only package of files, binaries, libraries, and configuration. Images are immutable. To change one, you build a new image.
A Dockerfile is a text file containing build instructions. A typical Dockerfile selects a base image with FROM, copies application files with COPY, runs build steps with RUN, selects a working directory with WORKDIR, and provides a default process with CMD or ENTRYPOINT.
Each build instruction can create an image layer. Layers let Docker reuse unchanged work through the build cache. When a layer changes, Docker rebuilds that layer and the layers after it. Put stable dependency steps before frequently changing application files when that ordering is correct for your build.
An image tag is a convenient name such as example:1.0. A digest identifies exact image content. Tags can move to new content; digests do not. Use deliberate tags for normal release workflows and digests when you need an exact immutable reference.
Containers are image instances
A container is a runnable instance of an image. The image supplies the initial filesystem and default configuration. Docker adds a writable container layer and starts the selected process.
The container lives only while its process and container object exist. Changes written into its writable layer are tied to that container. When you remove the container, those changes disappear. Store durable application data outside that layer.
The process inside a container is still a real host process with isolation around it. A container is not a security boundary you can ignore. The daemon, host kernel, image contents, runtime configuration, mounted files, capabilities, and published ports all affect risk.
Configuration belongs at run time
You can change a container's runtime behavior without rebuilding its image. Common inputs include environment variables, command arguments, mounts, network connections, resource constraints, and published ports.
Keep the image focused on the application and its stable dependencies. Supply environment-specific configuration when you create the container. Do not bake credentials into image layers. Image history and distribution can expose content that seemed temporary during a build.
Storage: writable layers, volumes, and bind mounts
The writable container layer is appropriate for temporary container state. It is a poor home for data that must survive container replacement.
A volume is persistent storage managed by Docker. Its lifecycle is separate from the lifecycle of one container. Use a volume for application data that Docker should manage, such as a local database data directory.
A bind mount connects a specific host path to a path inside the container. Use one when both the host and container need direct access to the same files, as in a local source-code workflow. A bind mount couples the container to the host path and can let the container modify host files.
A tmpfs mount keeps temporary data in host memory and does not persist it to disk. Choose storage by lifecycle and ownership, not by the shortest command syntax.
Networking and published ports
Containers have networking enabled by default. A container can make outgoing connections, and containers attached to the same user-defined network can communicate by container name.
A service listening inside a container is not automatically reachable from outside the Docker host. Port publishing creates a forwarding rule from a host port to a container port. Publishing host port 8080 to container port 80 sends traffic received on the host's port 8080 to port 80 in the container.
Published ports bind to all host interfaces by default unless you specify a host address. That can expose a service beyond your own machine. Publish only the ports that clients need, and choose an explicit host address when access should remain local.
EXPOSE in a Dockerfile documents an intended container port. It does not publish that port by itself.
Registries move images
A registry stores and distributes images. Docker Hub is the default public registry used by Docker, and organizations can use other public or private registries.
docker pull downloads an image. docker push uploads an image for which you have access and a suitable name. docker run pulls a missing image before creating the container.
Treat registry names as part of an image's identity. Verify the publisher, choose an appropriate tag or digest, and keep images updated. A convenient image is still software from a supply chain.
Compose describes an application
Docker Compose defines a multi-container application in a Compose file. The file declares services and can also declare networks, volumes, configuration, and secrets. The Compose CLI creates and manages the application from that definition.
Use Compose when several containers form one application or when a team needs a repeatable local environment. Compose coordinates Docker resources on the selected Docker platform. It is not a general cluster scheduler and does not give a single-host Docker Engine automatic multi-host orchestration.
Security boundaries and choices
The Docker daemon is a privileged control surface on a typical rootful Linux installation. Access to its API can grant extensive control over the host. Protect the daemon socket and remote API.
Reduce container privileges. Run the application as a non-root user when possible. Avoid privileged mode. Add only required capabilities. Use read-only filesystems and narrow mounts where the application allows them. Set resource limits for workloads that should not consume the whole host.
Rootless mode runs both the daemon and containers without root privileges inside a user namespace. It reduces risk from daemon and runtime vulnerabilities, though it has prerequisites and operational limitations. Security is a system property; no single flag makes an unsafe image or configuration safe.
When Docker fits
Docker fits when you need a repeatable application package, an isolated local environment, an image-based delivery workflow, or a practical way to run several services together on one Docker platform.
Docker alone is not the answer when you need cluster-wide scheduling, automatic recovery across machines, or declarative management of a large fleet. An orchestrator can consume container images and add those capabilities. Docker also adds little value when a native process already has a simple, controlled environment and packaging it would only add operational overhead.
A practical learning path
First, learn the image-to-container relationship. Then build a small image and inspect its layers. Next, run containers with explicit configuration, storage, networks, and ports. Add a registry workflow after the local lifecycle is clear. Use Compose when you can explain each underlying service, network, and volume. Finish with image provenance, least privilege, resource limits, observability, and orchestration.
Keep one question in mind: what belongs in the image, and what belongs to the container's environment? That decision shapes repeatability, security, and operations.
