Fun with Learning Technology
LearnCoursesQuestionsTracksToolsNewsExplorePractice
Fun with Learning Technology

A new problem, explained clearly, every day.

Subscribe
Learn
  • Lessons
  • Topics
  • News
  • Tools
  • Courses
  • Career tracks
  • Everything
Site
  • About
  • Contact
  • Support
  • Privacy
  • Terms
Get the daily one

One email per new problem. No spam.

Request a tutorial

Requests shape what gets made next.

© 2026 Fun with Learning TechnologyRSS
Home›Courses›Docker & Kubernetes›docker build, run, exec, logs

Docker Basics

docker build, run, exec, logs

This lesson covers the essential lifecycle commands for managing containerized applications through image creation and execution. Mastering these commands is vital for ensuring consistent deployments across various environments by managing the transition from static code to running service instances. You will reach for these tools whenever you need to package software, troubleshoot runtime behavior, or inspect the health of your deployed applications.

Building Images with docker build

The docker build command is the process of transforming a set of instructions into an immutable image. Think of this as the 'compilation' phase of your application lifecycle, where you define the environment, dependencies, and configuration required for your service. By reading instructions from a Dockerfile, the engine creates layers, which are essentially cached snapshots of your filesystem at specific points in the build process. This design is why Docker is efficient; if you only change the last line of your source code, the system reuses the cached layers from the previous steps, drastically reducing build times. Understanding this layer mechanism is critical because placing frequently changing files, like source code, at the bottom of your Dockerfile ensures that you do not invalidate the cache for expensive operations like installing system libraries. This command effectively packages everything your application needs into a portable unit.

# Build an image named 'web-server' from the current directory
# The '.' context tells Docker where to look for the Dockerfile
docker build -t web-server:v1 .

Executing Containers with docker run

Once you have an image, you must instantiate it into a container using docker run. This command bridges the gap between a static artifact and a live process. When you run a container, you are creating an isolated environment with its own process ID namespace, network stack, and filesystem view. The -d flag runs the container in detached mode, meaning it continues in the background, allowing you to use your terminal for other tasks. The -p flag maps the host's port to the container's internal port, effectively punching a hole through the network isolation. It is crucial to understand that a container is just a process on the host machine with restrictions; it is not a virtual machine. When the main process defined in your image's entrypoint terminates, the container exits. Proper use of this command ensures that your application remains isolated from the host while still being reachable by traffic from the outside world.

# Start a detached container mapping host port 8080 to container port 80
docker run -d -p 8080:80 --name my-app web-server:v1

Inspecting Output with docker logs

When a containerized process is running in the background, you cannot see its standard output or error streams directly. The docker logs command serves as your window into the container's internal activity, capturing everything sent to stdout and stderr. Because Docker captures these streams from the root process, it provides a unified way to observe logs regardless of whether the application is a web server, a database, or a worker. Using the -f flag allows you to follow the log stream in real-time, which is essential for observing application behavior during initialization or while handling incoming requests. If you are debugging an issue, these logs are often the first place to look because they reflect the internal logic and error handling of your software. If logs are not appearing, ensure that your application is configured to write to standard output rather than a local file, as Docker specifically captures the stream buffers.

# Follow the output of the running 'my-app' container in real-time
docker logs -f my-app

Interacting with Containers with docker exec

Sometimes you need to inspect the state of a running container without stopping it, and this is where docker exec becomes indispensable. It allows you to run a new command inside an existing container's environment, essentially jumping into the isolated process space. By providing the -it flags (interactive and tty), you can spawn a shell, such as sh or bash, directly inside the container. This is extremely useful for verifying configuration files, checking environment variables, or inspecting the filesystem state while the application is active. Remember that this does not start a new container; it starts a new process within the existing namespace. This command should be used primarily for diagnostic purposes, as making manual changes inside a running container violates the principle of immutability. If you find yourself manually patching code inside a container, you should instead update your image definition and rebuild, ensuring that all deployments remain reproducible.

# Open an interactive shell session inside the 'my-app' container
docker exec -it my-app /bin/sh

Managing Lifecycle States

Understanding the lifecycle requires knowing how to stop and remove containers after their utility has passed. Docker keeps containers in a stopped state unless they are explicitly removed, allowing you to inspect their filesystem post-mortem. Using 'docker stop' sends a termination signal to the root process, giving the application a grace period to shut down cleanly, while 'docker rm' purges the container filesystem entirely. This pattern of 'create-run-stop-remove' is the foundation of ephemeral infrastructure. By treating containers as disposable, you force your application to be stateless, ensuring that no important data is trapped inside a container that might vanish. Always use labels or names to track your containers, as leaving orphan containers behind will eventually exhaust system resources. When combined with the build process, these lifecycle commands enable a robust pipeline where every deployment starts from a clean, predictable state, minimizing configuration drift and unexpected runtime errors across your infrastructure.

# Gracefully stop the running container, then remove it from the system
docker stop my-app
docker rm my-app

Key points

  • The docker build process generates immutable image layers to ensure consistency across environments.
  • Caching in Docker is triggered by layer ordering, so place less frequently changing steps early in your Dockerfile.
  • A container is a process isolation unit, not a virtual machine, and it shares the host kernel.
  • The docker run command manages port mappings and detaches processes from the interactive terminal session.
  • Standard output and error streams from the container's primary process are accessible via the docker logs command.
  • The docker exec command allows for real-time diagnostic interaction with a running container without stopping the main process.
  • Use interactive flags -it to maintain a pseudo-terminal connection when executing shell commands inside containers.
  • Adopting an ephemeral container lifecycle promotes stateless application architecture and prevents configuration drift.

Common mistakes

  • Mistake: Using 'docker run' to interact with a container that is already running. Why it's wrong: 'docker run' creates a brand new container instance from an image. Fix: Use 'docker exec' to enter a container that is already active.
  • Mistake: Forgetting to use the '-d' flag for background tasks. Why it's wrong: The process stays attached to the terminal; closing the terminal sends a SIGTERM and kills the container. Fix: Always use '-d' for detached mode if the container should persist.
  • Mistake: Assuming 'docker logs' shows live traffic without follow. Why it's wrong: 'docker logs' prints cached output and exits immediately. Fix: Use 'docker logs -f' to stream logs in real-time.
  • Mistake: Confusing 'docker build' context with the destination. Why it's wrong: Sending too many files in the build context slows down the process. Fix: Use a .dockerignore file to exclude unnecessary files from the build context.
  • Mistake: Running 'docker exec' without specifying an interactive TTY. Why it's wrong: You won't get a command prompt or proper input handling. Fix: Use 'docker exec -it <container> <command>' for shell access.

Interview questions

What is the primary difference between docker run and docker build?

The 'docker build' command is the initial stage where you transform a set of instructions from a Dockerfile into a static, immutable image. It creates the layers of the filesystem and prepares the environment. Conversely, 'docker run' is the execution phase where you take that image and instantiate a live, isolated container from it. While build focuses on preparation and packaging, run focuses on lifecycle and runtime execution.

How do you effectively use the docker logs command to troubleshoot a container?

To troubleshoot a container, you use 'docker logs [container_id]'. This command retrieves the standard output and standard error streams that the containerized process generates. For real-time debugging, the '--follow' or '-f' flag is essential as it streams logs as they happen. You can also use '--tail' to limit output. This is vital because containers are ephemeral, and without logs, you would have no visibility into internal process crashes or runtime application errors.

When should you use docker exec versus starting a container with a different command?

You use 'docker exec' to enter a container that is already running, which is perfect for administrative tasks like checking environment variables, inspecting filesystem states, or triggering manual scripts without stopping the container. You should not use it to start the primary application process. Using exec allows you to keep the container running while performing live diagnostics, preserving the uptime of your service while you inspect the internal process state or configuration files.

How does docker run differ from docker exec when dealing with containerized processes?

The 'docker run' command is responsible for creating a new container instance from an image, which implies starting a fresh process defined by the ENTRYPOINT or CMD instructions. In contrast, 'docker exec' is specifically designed to spawn a new process inside an existing container that is already running. You use 'run' to deploy your services, and you use 'exec' to perform maintenance or diagnostic tasks inside an existing, active environment without affecting the primary process.

Compare using docker logs versus configuring log drivers for long-term storage.

While 'docker logs' is incredibly convenient for immediate, local debugging of containerized applications, it is not a production-grade solution. The local logs are stored as JSON files on the host disk and can consume all available storage if not rotated correctly. In contrast, configuring log drivers—like sending logs to Fluentd or Splunk—externalizes the data. External storage is mandatory in a Kubernetes environment to ensure logs persist even when pods are rescheduled, deleted, or when the underlying node encounters a failure.

Explain the architectural implications of building images with many layers versus minimizing them.

When you run 'docker build', every instruction that modifies the filesystem creates a new layer. Minimizing these layers by chaining commands with '&&' significantly reduces the image size and improves cache efficiency. Architecturally, smaller images result in faster pulls across a Kubernetes cluster during scaling events. Efficient layering ensures that changes in high-level code do not invalidate the entire cache, meaning that 'docker build' processes run faster and Kubernetes deployment times are drastically reduced for your team.

All Docker & Kubernetes interview questions →

Check yourself

1. A developer wants to inspect the output of a background container that keeps crashing immediately. Which command is most appropriate?

  • A.docker run -it my-container
  • B.docker logs my-container
  • C.docker exec my-container tail -f /var/log/app.log
  • D.docker build --no-cache .
Show answer

B. docker logs my-container
docker logs captures the standard output and error of the container process. Option 0 starts a new container, option 2 assumes a log file exists inside the container (which might not be the case), and option 3 builds an image, which is unrelated to existing container state.

2. What is the primary difference between 'docker run' and 'docker exec'?

  • A.run creates a new container; exec runs a command in an existing container.
  • B.run executes a command in the background; exec runs it in the foreground.
  • C.run requires an image; exec requires a container ID.
  • D.run is for building images; exec is for running them.
Show answer

A. run creates a new container; exec runs a command in an existing container.
docker run initializes a container from an image. docker exec operates on an already running container instance. The other options misstate the fundamental purposes of the lifecycle commands.

3. During a build, your image is unnecessarily large. What is the most effective way to optimize the 'docker build' output?

  • A.Use docker exec to delete files after the container starts.
  • B.Use a .dockerignore file to exclude local files from the build context.
  • C.Always use the --no-cache flag.
  • D.Use docker logs to check for file bloat.
Show answer

B. Use a .dockerignore file to exclude local files from the build context.
.dockerignore prevents unnecessary files from being sent to the Docker daemon. Deleting files after the container starts (option 0) doesn't reduce the image size (layers), and the other options do not address the build context size.

4. You have a running web server in a container. You need to verify the internal network configuration. Which command is correct?

  • A.docker run -it <container_id> /bin/bash
  • B.docker build -t net-debug .
  • C.docker exec -it <container_id> ip addr show
  • D.docker logs -f <container_id>
Show answer

C. docker exec -it <container_id> ip addr show
docker exec allows you to run a diagnostic command inside an existing, running container. Option 0 would start a duplicate server, option 1 builds an image, and option 3 displays logs, not network configuration.

5. What happens if you run 'docker run -d my-app' and the container process exits immediately after starting?

  • A.Docker automatically restarts the container indefinitely.
  • B.The container stays in a 'running' state with no active processes.
  • C.The container enters an 'exited' state, and you must check the logs to debug the exit code.
  • D.The host machine will crash.
Show answer

C. The container enters an 'exited' state, and you must check the logs to debug the exit code.
Containers exit when the primary process (PID 1) exits. To diagnose why, you look at the logs. Option 0 only happens if restart policies are configured; option 1 is impossible as a container requires a PID 1; option 3 is incorrect as Docker isolates processes.

Take the full Docker & Kubernetes quiz →

← PreviousDockerfile — Writing and Best PracticesNext →Docker Volumes — Bind Mounts vs Named Volumes

Docker & Kubernetes

24 lessons, free to read.

All lessons →

Track your progress

Sign in to mark lessons done, score quizzes and keep notes.

Open in the app