Docker Containerization Docker Compose and Multi-Container Applications — Questions and Answers
Question 1: What is the primary purpose of Docker Compose?
- Define and run multi-container Docker applications using a single YAML file (Correct answer)
- Build Docker images faster than the standard Dockerfile
- Replace Kubernetes for production deployments
- Manage Docker registries and image versions
Correct answer: Define and run multi-container Docker applications using a single YAML file
Docker Compose allows you to define all services, networks, and volumes for a multi-container application in a docker-compose.yml file and start everything with a single command.
Docker Compose is designed for defining and sharing multi-container application definitions. The docker-compose.yml (or compose.yaml) file describes each service, its image or build context, environment variables, port mappings, volume mounts, and dependencies. Running 'docker compose up' starts all services in the correct order based on 'depends_on' declarations.
Question 2: What command starts all services defined in a docker-compose.yml file in detached mode?
- docker compose up -d (Correct answer)
- docker compose start --background
- docker compose run -d all
- docker compose launch
Correct answer: docker compose up -d
docker compose up -d starts all services defined in the compose file as background (detached) processes, returning control to the terminal.
'docker compose up' creates and starts all service containers. The '-d' flag runs them in detached mode so they run in the background. Without '-d', logs from all containers stream to the terminal. 'docker compose up --build' additionally rebuilds images before starting. You can start specific services with 'docker compose up -d service1 service2'.
Question 3: How do you stop and remove all containers, networks, and default volumes created by Docker Compose?
- docker compose down (Correct answer)
- docker compose stop
- docker compose rm
- docker compose kill
Correct answer: docker compose down
docker compose down stops all running containers and removes containers and networks created by 'docker compose up'. Use --volumes to also remove named volumes.
'docker compose stop' only stops containers but doesn't remove them. 'docker compose rm' removes stopped containers. 'docker compose down' does both, and also removes the networks. Add '-v' or '--volumes' to also remove named volumes defined in the compose file. Add '--rmi all' to also remove all images used by services.
Question 4: In a docker-compose.yml file, what does the 'depends_on' key control?
- The startup order of services, ensuring dependencies start before the dependent service (Correct answer)
- Which services share the same network
- Which services share environment variables
- Resource allocation between services
Correct answer: The startup order of services, ensuring dependencies start before the dependent service
depends_on tells Docker Compose to start listed services before the service that declares the dependency, controlling startup order.
By default, 'depends_on' only waits for the container to START, not for the application inside to be READY (e.g., a database accepting connections). For readiness waiting, use 'depends_on' with 'condition: service_healthy' combined with a healthcheck on the dependency. This is important for avoiding race conditions where your app starts before the database is ready.
Question 5: What Compose file keyword defines environment variables for a service?
- environment (Correct answer)
- env_vars
- variables
- env
Correct answer: environment
The 'environment' key in a service definition sets environment variables that are passed into the container at runtime.
Environment variables can be set in list format ('- KEY=value') or map format ('KEY: value'). Variables without values are passed through from the host shell ('- HOST_VAR'). You can also use 'env_file' to load variables from a .env file. The root-level '.env' file in the project directory automatically provides variable substitution in the compose file itself.
Question 6: What does the 'volumes' key in a service definition do in Docker Compose?
- Mounts host paths or named volumes into the container's filesystem (Correct answer)
- Creates Docker images from directories
- Defines shared memory between containers
- Specifies which containers can write to the same network
Correct answer: Mounts host paths or named volumes into the container's filesystem
The volumes key maps host directories or named Docker volumes into container paths, enabling data persistence and sharing between the host and container.
Short syntax: '- ./data:/app/data' mounts the local './data' directory to '/app/data' in the container. '- myvolume:/app/data' mounts a named volume. Long syntax allows specifying type (bind/volume/tmpfs), read-only mode, and volume options. Named volumes must also be declared in the top-level 'volumes' section of the compose file.
Question 7: How does Docker Compose name containers by default?
- projectname-servicename-number (e.g., myapp-web-1) (Correct answer)
- servicename_container_number
- random generated names like in docker run
- servicename only (no project prefix)
Correct answer: projectname-servicename-number (e.g., myapp-web-1)
Docker Compose prefixes container names with the project name (derived from the directory name or --project-name flag) followed by the service name and instance number.
The default project name is the current directory name in lowercase. So if your directory is 'myapp' and your service is 'web', the container is named 'myapp-web-1'. Multiple replicas get incrementing numbers. The project name can be overridden with the '-p' flag or COMPOSE_PROJECT_NAME environment variable. This naming helps identify containers belonging to a project.
Question 8: What is the purpose of the 'build' key in a Docker Compose service definition?
- Specifies the build context and Dockerfile location to build an image for the service (Correct answer)
- Defines the build order of services
- Triggers a production build process
- Specifies the base image to extend
Correct answer: Specifies the build context and Dockerfile location to build an image for the service
The 'build' key tells Compose to build an image from a local Dockerfile rather than pulling from a registry, specifying the context directory and optionally the Dockerfile path.
Simple form: 'build: .' uses the current directory as context with 'Dockerfile' as the filename. Extended form allows 'context:', 'dockerfile:', 'args:', and 'target:' keys. When both 'build' and 'image' are specified, the built image is tagged with the 'image' name. Run 'docker compose build' to pre-build images without starting services.
Question 9: What does 'docker compose logs -f' do?
- Follows (streams) log output from all running services (Correct answer)
- Shows the last 10 log lines from each service
- Writes logs to a file
- Shows only error-level logs
Correct answer: Follows (streams) log output from all running services
The -f (follow) flag streams live log output from all services, similar to 'tail -f', making it useful for monitoring application behavior in real time.
'docker compose logs -f' outputs logs from all services with service name prefixes. Add '--tail 50' to show only the last 50 lines before following. Specify a service name to filter: 'docker compose logs -f web'. Use '--no-color' to disable ANSI colors for log processing. Press Ctrl+C to stop following.
Question 10: What is the purpose of a .env file in a Docker Compose project?
- Provides default variable values for substitution in the compose file itself (Correct answer)
- Sets environment variables inside all containers
- Stores Docker Hub credentials
- Configures Docker daemon settings
Correct answer: Provides default variable values for substitution in the compose file itself
A .env file in the project directory provides variable values that are substituted into the docker-compose.yml file using ${VARIABLE} syntax, allowing environment-specific configuration.
The .env file is automatically loaded by Docker Compose for variable substitution in the compose file (e.g., 'image: myapp:${VERSION}'). This is different from 'env_file', which passes variables into containers. You can have multiple env files with '--env-file' flag. The .env file helps parameterize compose files for different environments without editing the YAML.
Question 11: Which Compose file directive sets resource limits for a service in Swarm-compatible format?
- deploy: resources: limits/reservations (Correct answer)
- resources: limits/reservations (top-level)
- limits: cpu/memory (under service)
- constraints: cpu/memory (under service)
Correct answer: deploy: resources: limits/reservations
In Compose file format v3+, resource limits are defined under the 'deploy' key as 'resources: limits:' and 'resources: reservations:', which is also used by Docker Swarm.
Example: 'deploy: resources: limits: cpus: "0.5" memory: 256M'. In Compose format v2, limits were directly under the service ('mem_limit', 'cpus'). The v3 deploy syntax is Swarm-compatible but also respected by Docker Compose with --compatibility flag. Docker Compose Desktop respects resource limits natively since Compose v2.
Question 12: How do multiple services communicate with each other in Docker Compose by default?
- They are automatically placed on a shared default network and can reach each other by service name (Correct answer)
- They communicate via localhost port mappings
- Manual network configuration is always required
- They use Docker's --link flag automatically
Correct answer: They are automatically placed on a shared default network and can reach each other by service name
Docker Compose creates a default bridge network for each project, connecting all services to it, enabling name-based service discovery without any network configuration.
The default network is named '{project}_default'. All services join this network and can reference each other by their service name as a DNS hostname. For example, a web service can connect to a database service using 'db:5432'. You can also define custom networks to segment services or connect to external networks.
Question 13: What is the difference between 'docker compose stop' and 'docker compose down'?
- stop halts containers but keeps them; down stops and removes containers and networks (Correct answer)
- stop removes containers; down only pauses them
- They are identical
- stop is for single services; down is for all services
Correct answer: stop halts containers but keeps them; down stops and removes containers and networks
docker compose stop gracefully stops running containers but leaves them and their networks intact. docker compose down stops and removes containers and networks.
After 'docker compose stop', you can restart with 'docker compose start' (not 'up') to resume from the same container state. After 'docker compose down', you must use 'docker compose up' which recreates containers. 'down' cleans up the environment completely, while 'stop' is used when you want to temporarily pause the application and resume it later.
Question 14: What does the 'healthcheck' key in a Compose service do?
- Defines a command Docker runs periodically to determine if the container is healthy (Correct answer)
- Monitors CPU and memory usage
- Sends HTTP pings to the service endpoint
- Checks if the Docker image is up to date
Correct answer: Defines a command Docker runs periodically to determine if the container is healthy
The healthcheck key configures a test command that Docker periodically runs inside the container, marking it as 'healthy' or 'unhealthy' based on the exit code.
Example: 'healthcheck: test: ["CMD", "curl", "-f", "http://localhost"] interval: 30s timeout: 10s retries: 3 start_period: 40s'. The container starts in 'starting' state, transitions to 'healthy' after passing the check, or 'unhealthy' after failing retries. Combined with 'depends_on: condition: service_healthy', this prevents dependent services from starting prematurely.
Question 15: How do you run a one-off command in a new service container using Docker Compose?
- docker compose run <service> <command> (Correct answer)
- docker compose exec <service> <command>
- docker compose start <service> --command <command>
- docker compose cmd <service> <command>
Correct answer: docker compose run <service> <command>
docker compose run starts a new container for the specified service and runs a one-off command, useful for tasks like database migrations or shell access.
'docker compose run web python manage.py migrate' creates a new container from the web service's image and runs the migration command. The container is removed after completion unless '--no-rm' is passed. Use 'docker compose exec' instead to run commands in an ALREADY RUNNING container. 'run' also starts linked services defined by 'depends_on'.
Question 16: What does the 'ports' key do in Docker Compose, and how does it differ from 'expose'?
- ports publishes to the host; expose makes ports available only to linked containers on the same network (Correct answer)
- They are identical
- expose publishes to the host; ports only documents
- ports only works in Swarm; expose works in Compose
Correct answer: ports publishes to the host; expose makes ports available only to linked containers on the same network
The 'ports' key maps container ports to the host (making them accessible from outside), while 'expose' only documents which ports a container listens on for inter-container communication.
ports syntax: '- "8080:80"' maps host port 8080 to container port 80. Without specifying host port ('- "80"'), Docker assigns a random host port. 'expose' is purely informational metadata — it doesn't actually do any port mapping. On the same Docker network, containers can already communicate on any port regardless of expose settings.
Question 17: What is the purpose of named networks in a Docker Compose file?
- To control which services can communicate with each other by assigning them to specific networks (Correct answer)
- To assign static IP addresses to services
- To prioritize network bandwidth for certain services
- Named networks are required for all Compose files
Correct answer: To control which services can communicate with each other by assigning them to specific networks
Named networks allow you to segment services so that only services on the same network can communicate, improving security and isolation within multi-service applications.
Example: define 'frontend' and 'backend' networks. The web service joins both; the database service joins only backend. This prevents the web service from directly reaching the database — traffic must go through the app service. You can also use 'external: true' to connect to a pre-existing Docker network created outside Compose.
Question 18: How do you override default Docker Compose configuration for a specific environment?
- Use a docker-compose.override.yml file or specify multiple -f files (Correct answer)
- Modify the docker-compose.yml directly
- Use --override flag with key=value pairs
- Set COMPOSE_OVERRIDE environment variable
Correct answer: Use a docker-compose.override.yml file or specify multiple -f files
docker-compose.override.yml is automatically merged with docker-compose.yml when present. Multiple files can also be explicitly merged with '-f file1.yml -f file2.yml'.
docker-compose.override.yml is designed for local development overrides (e.g., mounting source code, enabling debug ports) that shouldn't be in the base file. For different environments, you can have docker-compose.prod.yml, docker-compose.test.yml, etc., and combine them: 'docker compose -f docker-compose.yml -f docker-compose.prod.yml up'.
Question 19: What is the purpose of the 'restart' policy in Docker Compose?
- Defines when Docker should automatically restart a stopped container (Correct answer)
- Schedules periodic container restarts for maintenance
- Controls how many times a container can be restarted per hour
- Restarts all services when the compose file changes
Correct answer: Defines when Docker should automatically restart a stopped container
The restart policy tells Docker whether and when to automatically restart a container that exits, using values like 'always', 'unless-stopped', 'on-failure', or 'no'.
'restart: always' restarts the container regardless of exit code, including after Docker daemon restart. 'restart: unless-stopped' restarts unless you explicitly stopped it. 'restart: on-failure' only restarts if the container exits with a non-zero exit code (optionally with max retry count: 'on-failure:3'). 'restart: no' (default) never auto-restarts.
Question 20: What command rebuilds images and recreates containers for changed services in Docker Compose?
- docker compose up --build (Correct answer)
- docker compose rebuild
- docker compose build && docker compose start
- docker compose refresh
Correct answer: docker compose up --build
docker compose up --build forces Docker Compose to rebuild images from their Dockerfiles before starting containers, ensuring changes to source code or Dockerfile are included.
Without '--build', 'docker compose up' uses existing images if they exist, potentially using stale images. '--build' rebuilds only services that have a 'build' key in their definition. For even more control, 'docker compose build --no-cache' forces a full rebuild ignoring the build cache. Use '--force-recreate' to recreate containers even if their config hasn't changed.
Question 21: What is the 'anchor' feature (&, *) in Docker Compose YAML used for?
- YAML anchors reuse repeated blocks of configuration across multiple services (Correct answer)
- Define network anchors for service discovery
- Mark services that should always be kept running
- Specify the main/entry service for the application
Correct answer: YAML anchors reuse repeated blocks of configuration across multiple services
YAML anchors (&name) define reusable blocks that can be referenced with aliases (*name) elsewhere in the file, reducing duplication in compose file configuration.
Example: define '&common-env environment: - LOG_LEVEL=info' under an 'x-common' extension key, then reference it with '*common-env' in multiple services. This is YAML native syntax, not Docker-specific. Docker Compose also supports 'extends' key and compose fragments via extension fields (x-*) for service inheritance and config reuse.
Question 22: How do you scale a specific service to multiple instances using Docker Compose?
- docker compose up --scale service=3 (Correct answer)
- docker compose scale service 3
- docker compose replicate service 3
- Set replicas: 3 under the service key (non-Swarm)
Correct answer: docker compose up --scale service=3
docker compose up --scale <service>=<count> starts the specified number of container instances for the given service.
'docker compose up -d --scale web=3' starts 3 instances of the web service. Note that services with host port mappings cannot be scaled beyond 1 (port conflicts). Use port ranges ('- 8080-8082:80') or omit the host port ('- 80') to allow scaling. When scaling, Compose assigns container names with incrementing numbers: web-1, web-2, web-3.
Question 23: What is the 'profiles' feature in Docker Compose?
- Allows services to be conditionally started by assigning them to named profiles (Correct answer)
- Creates different resource allocation profiles
- Defines different Docker network configurations
- Sets environment-specific Dockerfile targets
Correct answer: Allows services to be conditionally started by assigning them to named profiles
Profiles allow you to mark services with profile names so they are only started when that profile is explicitly activated, enabling optional services like development tools or debugging utilities.
Example: assign 'profiles: ["debug"]' to a phpMyAdmin service. It won't start with normal 'docker compose up'. Start it with 'docker compose --profile debug up' or 'COMPOSE_PROFILES=debug docker compose up'. Services without profiles always start. This is useful for dev-only services (adminer, mailhog, mock servers) that shouldn't run in CI or production.
Question 24: What does 'docker compose exec' do differently from 'docker compose run'?
- exec runs a command in an already running container; run starts a new container (Correct answer)
- exec starts a new container; run uses existing containers
- They are identical in behavior
- exec only works for manager nodes in Swarm
Correct answer: exec runs a command in an already running container; run starts a new container
docker compose exec executes a command inside an already-running container, similar to 'docker exec'. docker compose run starts a brand new container to run the command.
'docker compose exec web bash' opens a bash shell in the running web container. 'docker compose run web bash' creates a fresh container from the web image and starts bash. Use exec for debugging live containers. Use run for one-off tasks that need a fresh environment (migrations, tests). exec requires the target service container to already be running.
Question 25: Which Docker Compose version supports Swarm deploy keys like replicas, update_config, and resources?
- Version 3 and above (Compose file format 3.x) (Correct answer)
- Version 2 only
- All versions
- Version 4 and above only
Correct answer: Version 3 and above (Compose file format 3.x)
Compose file format version 3 introduced the 'deploy' key with swarm-specific configuration like replicas, update_config, rollback_config, resources, and placement constraints.
The 'deploy' key is ignored by 'docker compose up' (non-Swarm) but is used by 'docker stack deploy'. In Compose file version 2, resource limits were direct service keys (mem_limit, cpus). Version 3 moved these under 'deploy: resources:' for Swarm compatibility. Use '--compatibility' flag with docker compose to apply v3 resource limits in non-Swarm mode.
Question 26: What is the purpose of 'x-' extension fields in Docker Compose files?
- Define reusable fragments that can be merged into services using YAML anchors (Correct answer)
- Mark experimental features
- Define external dependencies not managed by Compose
- Configure extended logging options
Correct answer: Define reusable fragments that can be merged into services using YAML anchors
Extension fields (any key starting with 'x-') are ignored by Docker Compose but can hold YAML anchors for reuse, providing a clean way to define shared configuration blocks.
Example: 'x-logging: &default-logging logging: driver: json-file options: max-size: 10m'. Then each service uses: 'logging: *default-logging'. Docker ignores x-* keys, so they won't cause validation errors. This pattern keeps compose files DRY (Don't Repeat Yourself) and is especially useful for logging, resource limits, and common environment variables.
Question 27: How does Docker Compose determine which containers need to be recreated when you run 'docker compose up' again?
- It compares the current configuration with the running container's configuration and recreates if changed (Correct answer)
- It always recreates all containers
- It checks the image modification time only
- It never recreates containers unless --recreate is specified
Correct answer: It compares the current configuration with the running container's configuration and recreates if changed
Docker Compose tracks the configuration used to create each container. If the service definition has changed (image, environment, ports, etc.), it recreates that container on the next 'docker compose up'.
Compose stores configuration hashes to detect changes. If a service's image, command, environment, ports, volumes, or networks have changed since the container was created, Compose recreates it. If nothing changed, the existing container is reused. Use '--force-recreate' to always recreate all containers, or '--no-recreate' to never recreate running containers.
Question 28: What is the 'init' key in a Docker Compose service definition used for?
- Runs an init process (tini) as PID 1 to handle signal forwarding and zombie process reaping (Correct answer)
- Runs initialization scripts before the main process
- Sets the initial state of the container
- Defines startup health checks
Correct answer: Runs an init process (tini) as PID 1 to handle signal forwarding and zombie process reaping
Setting 'init: true' injects a lightweight init process (tini) as PID 1, which properly forwards signals to child processes and reaps zombie processes.
By default, the process defined by CMD/ENTRYPOINT runs as PID 1, which is the init process. Most applications aren't designed to handle init responsibilities like SIGTERM propagation to child processes. With 'init: true', Docker injects tini as PID 1, which manages signal forwarding and zombie process cleanup, improving graceful shutdown behavior.
Question 29: What is the recommended way to pass secrets to services in a Docker Compose development environment?
- Use a .env file with docker compose env_file or environment variables (Correct answer)
- Hardcode values in docker-compose.yml
- Use Docker Swarm secrets (not available in standalone Compose)
- Store them in named volumes
Correct answer: Use a .env file with docker compose env_file or environment variables
In development, environment variables via .env files or env_file directive are the standard approach. Docker secrets are only available in Swarm mode.
Use 'env_file: .env.local' or 'environment: - DB_PASSWORD=${DB_PASSWORD}' with values from a .env file that is NOT committed to version control. Add .env to .gitignore. For production, use Docker secrets (Swarm), Kubernetes secrets, or a secrets manager like Vault or AWS Secrets Manager. Never hardcode credentials in docker-compose.yml.
Question 30: What does 'docker compose pull' do?
- Downloads the latest versions of all images specified in the compose file (Correct answer)
- Pulls configuration from a remote Compose registry
- Syncs the local project with a remote Docker host
- Downloads all service logs
Correct answer: Downloads the latest versions of all images specified in the compose file
docker compose pull fetches the latest image for each service from the container registry, updating locally cached images without starting containers.
'docker compose pull' is useful before deploying to ensure you have the latest images. After pulling, run 'docker compose up -d' to recreate containers with the new images. You can pull specific services: 'docker compose pull web db'. Images with 'build' keys are skipped unless '--include-deps' is used. This is commonly used in CI/CD pipelines.
Question 31: What is the difference between 'docker compose up' and 'docker compose start'?
- up creates and starts containers; start only starts already-existing stopped containers (Correct answer)
- They are identical
- start creates new containers; up only restarts existing ones
- up is for Swarm; start is for standalone
Correct answer: up creates and starts containers; start only starts already-existing stopped containers
docker compose up creates new containers if they don't exist and starts them. docker compose start only starts containers that already exist but are stopped.
Use 'docker compose up' when setting up for the first time or after changing configuration (it recreates as needed). Use 'docker compose start' to restart previously stopped containers without recreating them — this preserves container state. Similarly, 'docker compose stop' is the complement to 'start', while 'docker compose down' is the complement to 'up'.
Question 32: How can you view the currently running status of all services in a Docker Compose project?
- docker compose ps (Correct answer)
- docker compose status
- docker compose list
- docker ps --compose
Correct answer: docker compose ps
docker compose ps displays the status of each service container in the current Compose project, showing container names, services, ports, and running state.
'docker compose ps' shows only containers belonging to the current project (determined by working directory or -p flag). It displays each container's name, command, state (Up/Exit), and port mappings. Add '-a' to also show stopped containers. This is more focused than 'docker ps', which shows all containers across all projects.
Question 33: What is the purpose of the 'tmpfs' mount type in Docker Compose volumes?
- Creates an in-memory filesystem that is discarded when the container stops (Correct answer)
- Mounts a remote NFS share
- Creates a temporary named volume on disk
- Encrypts the mounted filesystem
Correct answer: Creates an in-memory filesystem that is discarded when the container stops
A tmpfs mount creates a temporary filesystem stored in memory (RAM), not on disk, which is discarded when the container stops — useful for sensitive data or improving I/O performance.
Use tmpfs for data that shouldn't persist (session state, caches, temporary computation) or for sensitive data you don't want written to disk (keys, tokens processed in memory). tmpfs mounts are extremely fast since they use RAM. Configure with 'tmpfs: /app/cache' (short syntax) or 'volumes: - type: tmpfs target: /app/cache size: 100m' (long syntax).
Question 34: What happens to named volumes when you run 'docker compose down'?
- Named volumes are preserved by default; add --volumes or -v to remove them (Correct answer)
- Named volumes are always deleted
- Named volumes are moved to the host's /tmp directory
- Named volumes are exported to a tar archive
Correct answer: Named volumes are preserved by default; add --volumes or -v to remove them
By default, docker compose down preserves named volumes to protect persistent data. You must explicitly add --volumes (-v) to delete them along with containers and networks.
This is an important safety feature preventing accidental data loss. A common mistake is running 'docker compose down -v' when you only want to restart services, accidentally deleting database volumes. For development resets, 'docker compose down -v' is useful to start completely fresh. Anonymous volumes (not declared in top-level volumes) are always removed.
Question 35: What is the 'cap_add' directive used for in Docker Compose service definitions?
- Grants additional Linux kernel capabilities to the container beyond the defaults (Correct answer)
- Sets the container's CPU capacity
- Defines the network capacity limits
- Increases the maximum number of open files
Correct answer: Grants additional Linux kernel capabilities to the container beyond the defaults
cap_add grants specific Linux capabilities to a container (e.g., NET_ADMIN for network manipulation, SYS_PTRACE for debugging) without running as fully privileged.
By default, containers run with a restricted set of Linux capabilities. 'cap_add: - NET_ADMIN - NET_RAW' grants these specific capabilities without the full root-equivalent 'privileged: true'. This follows the principle of least privilege — grant only the capabilities needed. Common use cases: network monitoring tools (NET_ADMIN), performance profiling (SYS_PTRACE), and time synchronization (SYS_TIME).
What is the primary purpose of Docker Compose?