Docker packages an application with its runtime dependencies so that it can run consistently across development, testing and production environments. These Docker fundamentals are essential for beginners working with DevOps tools, cloud platforms and container-based deployment workflows.
If you want to practise Docker as part of a broader automation workflow, the AWS DevOps course covers related skills such as source control, CI/CD, cloud services and infrastructure operations.
What are the core Docker fundamentals?
The three core Docker objects are images, containers and volumes. An image is a reusable application package, a container is a running or stopped instance of that image, and a volume stores data outside the container's writable layer.
| Docker object | Purpose | Example |
|---|---|---|
| Image | Packages an application and its dependencies | nginx:alpine |
| Container | Runs an isolated process from an image | An Nginx web server |
| Volume | Preserves application data | Website files or database data |
| Registry | Stores and distributes images | Docker Hub or Amazon ECR |
| Dockerfile | Defines how to build an image | Instructions using FROM, COPY and RUN |
A useful diagram-in-words is:
Dockerfile -> docker build -> Image -> docker run -> Container
|
+-> Volume for persistent dataThe image provides the starting filesystem and configuration. Docker adds a writable container layer when the image is started, but that layer is normally removed when the container is deleted.
How does Docker work?
Docker uses a client-and-engine architecture. The docker command sends requests to the Docker Engine, which manages images, containers, networks and volumes on the host.
User
|
v
Docker CLI -> Docker Engine -> Images
-> Containers
-> Networks
-> VolumesOn Linux, containers share the host kernel while using kernel features such as namespaces and control groups for isolation and resource management. Docker Desktop runs Linux containers through a managed Linux virtual machine on Windows and macOS.
Containers are not complete virtual machines. They usually start faster and use fewer resources because each container does not require a separate guest operating system.
| Feature | Container | Virtual machine |
|---|---|---|
| Isolation | Process and filesystem isolation | Hardware-level virtualisation |
| Operating system | Shares the host kernel | Includes a guest OS |
| Typical startup | Starts as a process | Boots an operating system |
| Packaging unit | Container image | VM disk image |
| Common use | Services, jobs and development environments | Full OS isolation and legacy workloads |
How can you verify a Docker installation?
Docker is ready when the client can communicate with the Docker Engine and run a test container. Install Docker Engine or Docker Desktop using the official instructions for your operating system, then verify both the client and server.
docker version
docker info
docker run --rm hello-worlddocker version displays client and server information. If it shows only client details or reports that it cannot connect to the daemon, the Docker Engine may not be running or the current user may not have access to its socket.
The --rm option automatically deletes the test container after it exits. Docker may first download the hello-world image if it is not available locally.
What is a Docker image?
A Docker image is a read-only template containing application files, libraries, runtime components and default configuration. Images are built in layers, which allows Docker to reuse unchanged layers across builds and reduce unnecessary transfers.
For example, nginx:alpine contains the Nginx web server on an Alpine Linux base. The part before the colon is the repository name, while alpine is the tag.
docker pull nginx:alpine
docker image ls nginxExample output:
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx alpine <image-id> <time> <size>Tags are convenient labels, but a tag can be moved to a newer image. Production workflows can use an image digest when an exact immutable image version is required.
Build a simple image with a Dockerfile
Create a new directory and add an HTML page:
mkdir docker-web-lab
cd docker-web-lab
cat > index.html <<'EOF'
<!doctype html>
<html>
<body>
<h1>Docker fundamentals lab</h1>
<p>This page is served from a custom image.</p>
</body>
</html>
EOFCreate a file named Dockerfile:
FROM nginx:alpine
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80Build the image from the current directory:
docker build -t beginner-web:1.0 .The final dot is the build context. It tells Docker which directory contains the Dockerfile and files available to COPY instructions.
The instructions perform the following actions:
| Instruction | Action |
|---|---|
FROM nginx:alpine | Selects the base image |
COPY | Adds the local HTML file to the image |
EXPOSE 80 | Documents the container's listening port |
EXPOSE does not publish a port on the host. Port publishing happens when the container is started with -p or --publish.
Inspect the new image:
docker image ls beginner-web
docker history beginner-web:1.0docker history shows the image layers and the instructions that created them. Docker can reuse cached layers when the Dockerfile and relevant files have not changed.
What is a Docker container?
A container is an isolated process created from an image. It receives a writable layer for runtime changes, but important data should not depend on that layer because deleting the container removes it.
Run the image built in the previous lab:
docker run -d --name demo-web -p 8080:80 beginner-web:1.0The options mean:
| Option | Meaning |
|---|---|
-d | Runs the container in detached mode |
--name demo-web | Assigns a readable container name |
-p 8080:80 | Maps host port 8080 to container port 80 |
beginner-web:1.0 | Specifies the image and tag |
Test the service:
curl http://localhost:8080The request reaches port 8080 on the host. Docker forwards it to port 80 inside the container, where Nginx is listening.
Manage the container lifecycle
docker ps
docker ps -a
docker logs demo-web
docker stop demo-web
docker start demo-web
docker restart demo-web
docker rm -f demo-webdocker ps shows running containers, while docker ps -a also includes stopped containers. docker rm -f stops and removes a container, but it does not remove the source image or named volumes.
To run a command inside a running container, use docker exec:
docker exec -it demo-web shThe Nginx Alpine image provides sh, but it may not include Bash. Minimal images often omit diagnostic tools, so do not assume every image contains bash, curl or a package manager you normally use.
Why are Docker volumes required?
Docker volumes preserve data independently of a container's lifecycle. A container can be replaced or deleted while its named volume remains available for another container.
Consider a database container. If its database files exist only in the writable container layer, removing that container also removes the files. Attaching a volume places the files in storage managed separately by Docker.
Container writable layer -> Deleted with container
Named volume -> Remains after container deletionDocker supports several storage approaches:
| Storage type | Managed by | Suitable for |
|---|---|---|
| Named volume | Docker | Databases and persistent application data |
| Anonymous volume | Docker | Temporary data without a fixed volume name |
| Bind mount | User and host filesystem | Source code and host configuration files |
tmpfs mount | Host memory on Linux | Sensitive or temporary non-persistent data |
Create and use a named volume
Create a volume and write an HTML file into it:
docker volume create webdata
docker run --rm \
--mount source=webdata,target=/data \
alpine sh -c 'echo "<h1>Persistent Docker volume</h1>" > /data/index.html'Start Nginx with the volume mounted read-only:
docker run -d \
--name volume-web \
-p 8081:80 \
--mount source=webdata,target=/usr/share/nginx/html,readonly \
nginx:alpine
curl http://localhost:8081Remove the container and create a replacement:
docker rm -f volume-web
docker run -d \
--name replacement-web \
-p 8081:80 \
--mount source=webdata,target=/usr/share/nginx/html,readonly \
nginx:alpine
curl http://localhost:8081The page still exists because webdata survived the deletion of the first container.
Inspect and remove volumes with:
docker volume ls
docker volume inspect webdata
docker volume rm webdataDocker will reject the removal if a container still references the volume. Remove the relevant container before deleting the volume.
When should you use a bind mount?
Use a bind mount when a container needs direct access to a specific host directory, such as application source code during local development. Changes on either side are immediately visible because the container is accessing the host path.
On Linux or macOS, the current directory can be mounted as follows:
docker run --rm \
--mount type=bind,source="$(pwd)",target=/workspace \
alpine ls -la /workspaceBind mounts depend on host paths and permissions, making them less portable than named volumes. Docker Desktop users may also need to permit file sharing for the selected host directory.
How do you troubleshoot common Docker errors?
Start troubleshooting by checking container status, logs, port mappings and mounts. Avoid repeatedly rebuilding an image until you know whether the failure is occurring during the build, container startup or application runtime.
Cannot connect to the Docker daemon
Typical error:
Cannot connect to the Docker daemonCheck whether Docker Engine or Docker Desktop is running:
docker version
docker infoOn Linux, socket permissions may also be responsible. Use the Docker installation guidance for your distribution before changing group membership, and understand that access to the Docker socket provides powerful host-level control.
A container exits immediately
Containers run only while their main process is active. Check all containers and inspect the logs and exit code:
docker ps -a
docker logs demo-web
docker inspect --format '{{.State.Status}} exit={{.State.ExitCode}}' demo-webAn exit code of zero usually indicates normal completion. A non-zero code suggests an application, command, configuration or permission failure.
The host port is already in use
Typical error:
Bind for 0.0.0.0:8080 failed: port is already allocatedFind the existing published ports:
docker ps --format 'table {{.Names}}\t{{.Ports}}'Stop the conflicting service or choose another host port:
docker run -d --name demo-web-2 -p 8082:80 beginner-web:1.0Only the host-side port changed. Nginx still listens on port 80 inside the container.
Mounted files are missing
A mount placed over a non-empty container directory hides the original files at that path. Inspect the mounts before concluding that the image build failed:
docker inspect --format '{{json .Mounts}}' replacement-webCheck whether the source volume contains the expected data:
docker run --rm --mount source=webdata,target=/data alpine ls -la /dataThe container receives permission denied errors
The process inside the container may run as a non-root user whose UID and GID cannot access the mounted files. Check the image's runtime user, file ownership and host security controls rather than automatically running the application as root.
docker exec replacement-web id
docker exec replacement-web ls -ld /usr/share/nginx/htmlFor production images, set appropriate ownership during the build and use the least-privileged user that can run the application.
What Docker practices should beginners follow?
Use explicit image tags, keep images small, store persistent data in volumes and remove unused lab resources carefully. Treat images as replaceable build artefacts rather than servers that are manually modified after deployment.
Practical habits include:
- Write application changes in the Dockerfile instead of editing running containers.
- Use
.dockerignoreto exclude Git data, credentials, logs and unnecessary build files. - Never place passwords, access keys or private keys inside an image.
- Run applications as a non-root user where the image supports it.
- Publish only the ports required by the application.
- Use read-only mounts when a container does not need to change mounted files.
- Review base images and rebuild when security updates are available.
- Remove unused test containers with
docker container pruneonly after reviewing what will be deleted.
Cloud learners can connect these concepts to image storage in Amazon Elastic Container Registry and container execution services such as Amazon ECS. The AWS Solutions Architect course provides broader context for selecting compute, networking and storage services, while these AWS DevOps interview questions can help you review operational scenarios after completing the labs.
What should you remember about Docker fundamentals?
An image is the reusable package, a container is an instance of that package, and a volume provides persistent storage outside the container layer. Build images with Dockerfiles, publish ports deliberately, inspect logs before troubleshooting blindly, and keep important state in suitable external storage.
The best way to learn these concepts is to repeat the image build, container replacement and volume persistence labs until the object lifecycle is clear.
Reviewed by Network Rhinos DevOps trainers.
To practise Docker with cloud services, CI/CD tools and deployment workflows, enquire about batch details for the AWS DevOps course.
Related reading: AWS IAM Explained: Users, Roles, Policies and Access
