Zademy

Complete Guide to Docker and Docker Compose: Commands and Best Practices

Docker; DevOps; Containers; Guide; CLI
words words

Complete Guide to Docker and Docker Compose: Commands and Best Practices

Fundamental Docker concepts

Docker is an open-source system that handles application development, deployment, and execution through containerization. It solves compatibility problems by packaging an application and its dependencies into self-contained, portable units that run consistently across any environment.

Key components

  • Images are lightweight, self-contained, executable software packages that contain everything needed to run an application: code, runtime, libraries, and configurations. Think of them as the template for creating containers.
  • Containers are the runtime instance of a Docker image. They isolate software from its environment, so many can run simultaneously on a host without stepping on each other.
  • Docker Hub is Docker's service for finding and sharing container images.

Docker CLI commands (basic)

TaskCLI CommandDescription
Images
Build an Imagedocker build -t <image_name> .Builds an image from a Dockerfile in current directory.
Build without cachedocker build -t <image_name> . --no-cacheForces rebuilding without using cache.
List Imagesdocker imagesShows all local images.
Remove an Imagedocker rmi <image_name>Removes a local image.
Remove Unused Imagesdocker image pruneRemoves all unused images.
Publish to Docker Hubdocker push <user>/<image_name>Uploads an image to Docker Hub.
Containers
Run Container (with name)docker run --name <container_name> <image_name>Creates and runs a container from an image.
Run in Backgrounddocker run -d <image_name>Runs container in detached mode (background).
Run and Publish Portsdocker run -p <host_port>:<container_port> <image_name>Maps a container port to host.
List Containers (Running)docker psShows currently running containers.
List All (Running and Stopped)docker ps --allShows all containers, regardless of their state.
Start/Stop/Restartdocker start|stop|restart <container_name>Starts or stops an existing container. docker stop sends a SIGTERM signal for graceful shutdown.
Remove a Containerdocker rm <container_name>Removes a stopped container.
Enter Containerdocker exec -it <container_name> shOpens an interactive shell inside a running container.
View Logsdocker logs -f <container_name>Shows and follows container logs.
Inspect Containerdocker inspect <container_name>Shows container details, typically in JSON format.
Monitor Resourcesdocker statsShows runtime resource usage statistics.

Advanced Docker: best practices for images and security

Multi-stage builds

Multi-stage builds let you create small, secure production images that contain only the binaries or artifacts you actually need. No development tools, no build dependencies, no bloat.

  • Usage: Use multiple FROM instructions, each starting a new stage.
  • Selective Copying: Use COPY --from=<stage> to copy artifacts from a previous stage.
  • Stage Naming: Name stages with FROM <image> AS <NAME> so you can reference them easily and avoid breaking the copy if instructions are reordered: COPY --from=build /bin/hello /bin/hello.
  • Debugging: You can build only up to a specific stage using: docker build --target <stage> -t hello ..
  • BuildKit: This is the recommended builder, as it only processes the stages that the target depends on, unlike the legacy builder which processes all stages up to the target.

Image and container security

PracticeDetails
Base ImagesUse official or verified images from reliable sources. Start with a minimal base image and include only essential dependencies to minimize vulnerabilities.
ScanningRegularly scan images and containers for known vulnerabilities (e.g., using tools like Trivy or Docker Scout).
PrivilegesFollow the principle of least privilege. Run containers as non-root users.
File SystemUse read-only file systems whenever possible.
Content SigningEnable Docker Content Trust (DCT) to ensure you only use signed images.

Docker Compose (multi-container application management)

Docker Compose simplifies management of multi-container applications. You define and orchestrate multiple containers (services, networks, volumes) in a single YAML file, typically docker-compose.yml.

  • Key difference with Docker: Docker manages individual containers, while Docker Compose coordinates multiple containers that work together.
  • Ideal use: It's especially useful for development and testing environments where quick and fluid configuration of multiple services is required (e.g., web application, database, and frontend).
  • Version V2: Use the latest version. V1 (with hyphen: docker-compose) has stopped receiving updates; V2 uses docker compose (without hyphen).

Compose structure and basic commands

The docker-compose.yml file defines the structure:

# Note: In recent Docker Compose versions, version is no longer required
# version: '3.8'  # Optional in modern versions
services:
  service1: # Definition of containers/services
    # Service configuration
networks:
  network1: # Custom network configuration
    # Network configuration
volumes:
  volume1: # Named volume definition
    # Volume configuration
TaskCLI Command (V2)Description
Build and Deploydocker compose upBuilds and runs containers defined in the yml.
Deploy in Detacheddocker compose up -dDeploys and leaves the application running in the background.
Stop Applicationdocker compose stopStops the containers.
Stop and Removedocker compose downStops and removes services and networks. Does not remove named volumes by default.
Remove with Volumesdocker compose down --volumes or -vForces removal of services, networks, and named volumes.
Scale Servicedocker compose up --scale service=nIncreases the number of containers (n) for a specific service.
Service Statusdocker compose psShows the current status of containers.
Logsdocker compose logsShows logs of defined containers.

Persistent data management (volumes)

Volumes are how you persist data between containers and the host. Without them, data is lost the moment a container stops or restarts.

  • Named volumes have a user-defined name, making them easier to identify and manage. You define them in the volumes section of the yml and then mount them in the service.
  • Host mounts (bind mounts) share host directories with the container to facilitate data access and editing. The syntax is /path/on/host:/path/in/container.
TaskCLI Command (Docker, applies to Compose volumes)
List Volumesdocker volume ls
Inspect Volumedocker volume inspect <volume_name>
Remove Volumedocker volume rm <volume_name>
Clean Unused Volumesdocker volume prune

Advanced production best practices with Compose

Secrets and environment variables management

Keep key configurations (database credentials, API keys) out of your application code. It makes deployment more flexible and more secure.

  • Risk: Never hardcode secrets (passwords, tokens) in Dockerfiles or accidentally expose them in image layers.
  • Environment file (env_file): Store environment variables in a .env file and reference it in docker-compose.yml using the env_file: .env directive.
  • Security: This .env file must be excluded from the code repository (add it to .gitignore). Secrets load at runtime without being exposed in version control.

Networks and access security

  • Internal connectivity: By default, containers defined in Compose can talk to each other internally.
  • Database protection: Remove the port exposure of the database in the yml (don't bind ports to the host). The database process still claims the port, but it won't be bound to the host, so it stays protected from public exposure. To access it, tunnel a connection via SSH.

Resource limits and restarts

For shared environments, limit the resources an application can consume. Otherwise one app can starve everything else on the box.

  • Resource limitation (deploy: resources): Specify usage limits for memory, CPU, or GPU in the service.
    • Limits (limits): Total usage the application can have (e.g., cpus: 1, memory: 1GB).
    • Reservations (reservations): RAM and CPU that the container reserves exclusively for its operation.
  • Restart policy (restart_policy): Use restart: always to ensure the application starts automatically if the server restarts.
    • More detailed configurations allow defining conditions (e.g., on-failure), delays (delay), maximum number of attempts (max_attempts), and a time window (window) for restarts.

Health checks

A health check defines a continuous test that runs against the container to verify it's actually functioning, and restarts it if the test fails.

  • Configuration: You can define the interval (how often the test runs), retries (number of failures before considering it down), timeout (maximum wait time for the request), and start_period (margin of time at startup for the application to start).

Host security and general best practices

To improve the security of the Linux server where Docker Engine runs:

  • Limited root access: Limit Root access for login (often disabled by default on Ubuntu Server).
  • RSA keys: Use RSA (SSH keys) instead of passwords for login.
    • Create an SSH key with ssh-keygen.
    • Copy the public key to the server with ssh-copy-id <user>@<server>.
  • Brute force attack prevention: Install Fail2Ban (apt install fail2ban). It uses firewall rules (like IP Tables) to block IPs that make too many failed attempts against the SSH port.
  • Maintenance: Update Docker Engine and its dependencies frequently to mitigate vulnerabilities.
  • Monitoring: Implement a monitoring system to record application logs and automatically detect crashes or resource shortages on the server, in addition to using docker stats to monitor resources.

Wrapping up

Docker and Docker Compose are fundamental tools in modern software development. Mastering their commands and best practices improves development efficiency and ensures more secure, maintainable deployments in production. Proper implementation of these practices lets you build scalable, portable, and resilient applications.


To continue your learning journey in containerization, I recommend exploring Kubernetes orchestration strategies or diving deeper into image optimization techniques to further reduce the size and startup time of your applications.