CrackedRuby CrackedRuby

Overview

Docker provides operating system-level virtualization through containerization, packaging applications with their dependencies into isolated, portable units. Containers share the host operating system kernel while maintaining isolated process spaces, file systems, and network interfaces. This architecture delivers consistent runtime environments across development, testing, and production without the overhead of full virtual machines.

The Docker platform emerged from Linux container technologies (LXC, cgroups, namespaces) to standardize container creation, distribution, and execution. A Docker container runs as a process on the host system, isolated through kernel features rather than hardware virtualization. This process-level isolation allows containers to start in milliseconds and consume minimal resources compared to virtual machines.

Docker addresses the "works on my machine" problem by encapsulating an application's complete runtime environment: code, system libraries, dependencies, configuration files, and environment variables. The same container image produces identical behavior whether running on a developer's laptop, CI/CD server, or production cluster.

For Ruby applications, Docker eliminates dependency conflicts between system Ruby versions, gem dependencies, and native extensions. A containerized Ruby application includes the exact Ruby version, bundled gems, and compiled native extensions, guaranteeing consistent execution across environments.

# Without Docker: System-dependent execution
require 'nokogiri'  # May fail if libxml2 version incompatible
require 'pg'        # Requires PostgreSQL client libraries

# With Docker: Self-contained execution
# All dependencies packaged in container image
# Same behavior on macOS dev machine and Linux production

Key Principles

Docker operates through three fundamental components: images, containers, and registries. An image serves as a read-only template containing the application code, runtime, libraries, and configuration. A container represents a running instance of an image, executing as an isolated process. Registries store and distribute images, enabling sharing across teams and deployment targets.

Images compose from layers, each representing a filesystem change. When building an image, Docker creates a new layer for each instruction in the Dockerfile. Layers stack using a union filesystem, presenting multiple read-only layers plus one writable container layer as a single filesystem. This layering enables efficient storage through layer reuse—multiple images sharing common layers consume disk space only once.

Container isolation relies on Linux kernel features: namespaces and cgroups. Namespaces provide process, network, mount, and user isolation, giving each container its own view of system resources. Control groups (cgroups) limit resource consumption, preventing containers from exhausting host CPU, memory, or I/O.

The Docker daemon manages container lifecycle: pulling images, creating containers, starting/stopping processes, and cleaning up resources. The Docker client communicates with the daemon through a REST API, accepting commands and returning results. This client-server architecture allows remote container management.

Copy-on-write filesystem semantics optimize storage and performance. When a container modifies a file from an image layer, Docker copies the file to the container's writable layer before making changes. The original image layer remains unchanged, allowing multiple containers to share the same base layers while maintaining independent writable state.

Docker networking creates virtual networks connecting containers. The default bridge network assigns each container a private IP address, enabling inter-container communication. Custom networks provide DNS-based service discovery—containers reference each other by name rather than IP address. Host networking removes isolation, allowing containers direct access to host network interfaces.

Volume management persists data beyond container lifecycle. Named volumes store data in Docker-managed locations, surviving container deletion. Bind mounts map host filesystem paths into containers, useful for development workflows where code changes should immediately affect running containers. Volumes and bind mounts bypass the copy-on-write filesystem, improving I/O performance for data-intensive operations.

# Ruby application with database dependency
# Container isolation means each service runs independently

# config/database.yml in containerized Rails app
production:
  adapter: postgresql
  host: postgres  # DNS name from Docker network
  database: app_production
  username: <%= ENV['DB_USER'] %>
  password: <%= ENV['DB_PASSWORD'] %>

Ruby Implementation

Ruby applications integrate with Docker through multiple approaches: containerizing Ruby applications in Docker images, using Ruby Docker SDKs for programmatic container management, and building development environments with Docker Compose.

The docker-api gem provides Ruby bindings for the Docker Remote API, enabling container lifecycle management from Ruby code. This gem wraps HTTP endpoints, presenting an object-oriented interface for images, containers, volumes, and networks.

require 'docker-api'

# Connect to Docker daemon
Docker.url = 'unix:///var/run/docker.sock'
Docker.options = { read_timeout: 300 }

# Pull image
image = Docker::Image.create('fromImage' => 'ruby:3.2-alpine')

# Create and start container
container = Docker::Container.create(
  'Image' => 'ruby:3.2-alpine',
  'Cmd' => ['ruby', '-e', 'puts RUBY_VERSION'],
  'HostConfig' => {
    'Memory' => 536870912,  # 512MB
    'CpuShares' => 512
  }
)

container.start
output = container.logs(stdout: true)
puts output  # => 3.2.x

container.stop
container.delete

Ruby Dockerfiles follow conventions balancing image size, build performance, and security. Alpine Linux base images minimize size, though they require additional packages for gems with native extensions. Debian-based images provide broader compatibility at the cost of larger image size.

# Multi-stage Dockerfile for Rails application
FROM ruby:3.2-alpine AS builder

# Install build dependencies
RUN apk add --no-cache \
  build-base \
  postgresql-dev \
  nodejs \
  yarn

WORKDIR /app

# Install gems (cached layer)
COPY Gemfile Gemfile.lock ./
RUN bundle config set --local without 'development test' && \
    bundle install --jobs=4

# Install JavaScript dependencies
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile

# Copy application code
COPY . .

# Precompile assets
RUN RAILS_ENV=production \
    SECRET_KEY_BASE=dummy \
    bundle exec rails assets:precompile

# Production stage
FROM ruby:3.2-alpine

RUN apk add --no-cache \
  postgresql-client \
  tzdata \
  nodejs

WORKDIR /app

# Copy installed gems from builder
COPY --from=builder /usr/local/bundle /usr/local/bundle

# Copy application and assets
COPY --from=builder /app /app

# Create non-root user
RUN addgroup -g 1000 rails && \
    adduser -D -u 1000 -G rails rails && \
    chown -R rails:rails /app

USER rails

EXPOSE 3000

CMD ["bundle", "exec", "puma", "-C", "config/puma.rb"]

The Docker Ruby SDK supports streaming operations for container logs and execution:

require 'docker-api'

container = Docker::Container.get('rails-app')

# Stream logs in real-time
container.streaming_logs(stdout: true, follow: true) do |stream, chunk|
  puts chunk
end

# Execute commands inside running container
stdout, stderr, status = container.exec(['bundle', 'exec', 'rails', 'console']) do |stream, chunk|
  puts "#{stream}: #{chunk}"
end

Managing Docker from Ruby enables dynamic test environments, creating and destroying containers for each test suite:

require 'docker-api'
require 'minitest/autorun'

class DockerIntegrationTest < Minitest::Test
  def setup
    # Create PostgreSQL container for testing
    @db_container = Docker::Container.create(
      'Image' => 'postgres:15-alpine',
      'Env' => [
        'POSTGRES_PASSWORD=test',
        'POSTGRES_DB=test_db'
      ],
      'HostConfig' => {
        'PortBindings' => {
          '5432/tcp' => [{ 'HostPort' => '5433' }]
        }
      }
    )
    @db_container.start
    
    # Wait for PostgreSQL to accept connections
    sleep 2
  end
  
  def teardown
    @db_container.stop
    @db_container.delete(force: true)
  end
  
  def test_database_operations
    # Test code using database on port 5433
  end
end

Dockerized Ruby applications configure through environment variables rather than configuration files, following twelve-factor methodology:

# config/initializers/redis.rb
REDIS_URL = ENV.fetch('REDIS_URL', 'redis://localhost:6379/0')
$redis = Redis.new(url: REDIS_URL)

# Dockerfile
ENV REDIS_URL=redis://redis:6379/0

# docker-compose.yml sets this automatically through service linking

Practical Examples

Containerizing a Sinatra application demonstrates basic Docker workflow from development through deployment. The application requires Ruby runtime, gems, and configuration:

# app.rb
require 'sinatra'
require 'json'

set :bind, '0.0.0.0'
set :port, ENV.fetch('PORT', 4567)

get '/health' do
  content_type :json
  { status: 'ok', timestamp: Time.now.to_i }.to_json
end

get '/env' do
  content_type :json
  { environment: ENV['RACK_ENV'] || 'development' }.to_json
end
FROM ruby:3.2-slim

WORKDIR /app

COPY Gemfile Gemfile.lock ./
RUN bundle install --without development test

COPY . .

EXPOSE 4567

CMD ["ruby", "app.rb"]

Building and running this container:

docker build -t sinatra-app:1.0 .
docker run -d -p 8080:4567 --name web sinatra-app:1.0
curl http://localhost:8080/health
# => {"status":"ok","timestamp":1234567890}

Multi-container applications use Docker Compose to orchestrate services. A Rails application with PostgreSQL and Redis requires coordinated startup, networking, and volume management:

# docker-compose.yml
version: '3.8'

services:
  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: app_production
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data
    command: redis-server --appendonly yes

  web:
    build:
      context: .
      dockerfile: Dockerfile
    command: bundle exec puma -C config/puma.rb
    environment:
      RAILS_ENV: production
      DATABASE_URL: postgresql://app:secret@postgres/app_production
      REDIS_URL: redis://redis:6379/0
      SECRET_KEY_BASE: ${SECRET_KEY_BASE}
    ports:
      - "3000:3000"
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    volumes:
      - ./log:/app/log
      - ./tmp:/app/tmp

  worker:
    build:
      context: .
      dockerfile: Dockerfile
    command: bundle exec sidekiq -C config/sidekiq.yml
    environment:
      RAILS_ENV: production
      DATABASE_URL: postgresql://app:secret@postgres/app_production
      REDIS_URL: redis://redis:6379/0
    depends_on:
      - postgres
      - redis

volumes:
  postgres_data:
  redis_data:

Development environments benefit from hot-reloading, mounting source code as volumes:

# docker-compose.dev.yml
version: '3.8'

services:
  web:
    build:
      context: .
      dockerfile: Dockerfile.dev
    command: bundle exec rails server -b 0.0.0.0
    environment:
      RAILS_ENV: development
    volumes:
      - .:/app
      - bundle_cache:/usr/local/bundle
    ports:
      - "3000:3000"
    stdin_open: true
    tty: true

volumes:
  bundle_cache:
# Dockerfile.dev
FROM ruby:3.2

WORKDIR /app

# Install dependencies once
COPY Gemfile Gemfile.lock ./
RUN bundle install

# Source code mounted as volume at runtime
CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0"]

Running tests in containers isolates test dependencies from the host system:

# test/test_helper.rb
require 'minitest/autorun'
require 'docker-api'

class DockerTestHelper
  def self.setup_test_database
    @container = Docker::Container.create(
      'Image' => 'postgres:15-alpine',
      'Env' => ['POSTGRES_PASSWORD=test'],
      'HostConfig' => {
        'AutoRemove' => true,
        'PortBindings' => { '5432/tcp' => [{ 'HostPort' => '0' }] }
      }
    )
    @container.start
    
    # Get dynamically assigned port
    port_info = @container.json['NetworkSettings']['Ports']['5432/tcp']
    port = port_info.first['HostPort']
    
    ENV['TEST_DATABASE_URL'] = "postgresql://postgres:test@localhost:#{port}/postgres"
    
    # Wait for PostgreSQL startup
    30.times do
      break if system("pg_isready -h localhost -p #{port} -q")
      sleep 0.5
    end
  end
  
  def self.teardown_test_database
    @container.stop if @container
  end
end

Minitest.after_run { DockerTestHelper.teardown_test_database }

Container health checks enable reliable service dependencies. A Rails application waits for database availability before starting:

FROM ruby:3.2

WORKDIR /app

COPY Gemfile Gemfile.lock ./
RUN bundle install

COPY . .

# Health check pings Rails app
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s \
  CMD curl -f http://localhost:3000/health || exit 1

CMD ["bundle", "exec", "puma"]
# config/routes.rb
Rails.application.routes.draw do
  get '/health', to: proc { 
    status = ActiveRecord::Base.connection.active? ? 200 : 503
    [status, { 'Content-Type' => 'application/json' }, 
     [{ database: status == 200 }.to_json]]
  }
end

Implementation Approaches

Containerization strategies vary based on application architecture, deployment target, and operational requirements. Monolithic applications typically deploy in single containers, while microservices architectures distribute across multiple containers with service-specific optimization.

Single-stage builds create images in one Dockerfile, installing all dependencies and copying code sequentially. This approach suits simple applications but produces larger images containing build tools and intermediate artifacts:

FROM ruby:3.2

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y \
  build-essential \
  libpq-dev \
  nodejs

# Install application dependencies
COPY Gemfile Gemfile.lock ./
RUN bundle install

COPY . .

CMD ["bundle", "exec", "puma"]

Multi-stage builds separate build-time dependencies from runtime requirements. The builder stage compiles code and installs dependencies, then copies only necessary artifacts to the final stage:

FROM ruby:3.2 AS builder

RUN apt-get update && apt-get install -y build-essential libpq-dev
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install --jobs=4

FROM ruby:3.2-slim

RUN apt-get update && apt-get install -y libpq5
WORKDIR /app
COPY --from=builder /usr/local/bundle /usr/local/bundle
COPY . .

CMD ["bundle", "exec", "puma"]

Base image selection impacts image size, security surface, and dependency availability. Alpine Linux produces minimal images but requires manual package installation for gems with native extensions. Debian provides comprehensive package repositories with larger base image size. Distroless images eliminate package managers and shells, reducing attack surface for production deployments:

# Alpine: smallest, requires explicit dependencies
FROM ruby:3.2-alpine
RUN apk add --no-cache postgresql-client

# Debian slim: balanced size and compatibility  
FROM ruby:3.2-slim
RUN apt-get update && apt-get install -y libpq5

# Full Debian: largest, complete tooling
FROM ruby:3.2

Layer caching optimization arranges Dockerfile instructions to maximize cache hits. Dependencies change infrequently compared to application code, so copying dependency files before source code allows Docker to reuse cached layers when only code changes:

# Inefficient: code changes invalidate all subsequent layers
COPY . .
RUN bundle install

# Efficient: dependency layer cached unless Gemfile changes
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .

Container orchestration platforms manage multi-container deployments across clusters. Docker Swarm provides native clustering, while Kubernetes offers advanced scheduling, service discovery, and self-healing. Orchestration abstracts infrastructure, allowing applications to scale horizontally through container replication.

Development workflows balance between running services locally versus in containers. Docker Compose enables consistent local environments matching production, eliminating "works on my machine" discrepancies. Volume mounting supports rapid iteration, reflecting code changes without rebuilding images:

services:
  app:
    build: .
    volumes:
      - .:/app        # Hot reload application code
      - gems:/bundle  # Cache installed gems
    environment:
      BUNDLE_PATH: /bundle

Continuous integration builds container images as build artifacts, versioning through tags. Each commit produces a tagged image pushed to a registry. Deployment stages pull specific image tags rather than rebuilding, ensuring tested artifacts reach production unchanged:

# .gitlab-ci.yml
build:
  stage: build
  script:
    - docker build -t registry.example.com/app:$CI_COMMIT_SHA .
    - docker push registry.example.com/app:$CI_COMMIT_SHA
    
deploy_staging:
  stage: deploy
  script:
    - docker pull registry.example.com/app:$CI_COMMIT_SHA
    - docker tag registry.example.com/app:$CI_COMMIT_SHA registry.example.com/app:staging
    - docker service update --image registry.example.com/app:staging app_staging

Tools & Ecosystem

Docker Compose orchestrates multi-container applications through declarative YAML configuration. Service definitions specify image, build context, environment variables, ports, volumes, and dependencies. Compose creates isolated networks for service communication and manages container lifecycle collectively:

services:
  app:
    build: .
    ports:
      - "3000:3000"
    depends_on:
      - db
    environment:
      DATABASE_URL: postgresql://db/app
  
  db:
    image: postgres:15
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:

Docker Hub serves as the default public registry for image distribution. Organizations host private registries for internal images, using authentication to control access. Registry mirrors cache frequently pulled images, reducing bandwidth and improving pull performance in distributed teams:

# Push to Docker Hub
docker tag myapp:latest username/myapp:1.0
docker push username/myapp:1.0

# Push to private registry
docker tag myapp:latest registry.company.com/myapp:1.0
docker push registry.company.com/myapp:1.0

BuildKit modernizes Docker image building with improved performance, build caching, and security. Enabled through environment variables or daemon configuration, BuildKit parallelizes independent build stages, mounts secrets without including them in image layers, and provides better cache invalidation:

# syntax=docker/dockerfile:1.4

FROM ruby:3.2

# Mount secret during build without storing in image
RUN --mount=type=secret,id=bundle_config \
  bundle config --local gems.example.com $(cat /run/secrets/bundle_config)

# Cache bundle install across builds
RUN --mount=type=cache,target=/usr/local/bundle \
  bundle install

Docker Desktop provides GUI management on macOS and Windows, packaging the Docker daemon with Kubernetes support. The CLI remains primary for automation, while the desktop application simplifies resource allocation, volume browsing, and container inspection.

Watchtower automates container updates by monitoring registries for new image tags. When detecting updated images, Watchtower pulls the new version, stops the existing container, and starts a replacement with identical configuration:

services:
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    command: --interval 300  # Check every 5 minutes

Dive analyzes Docker images layer-by-layer, identifying inefficiencies and wasted space. The tool visualizes layer composition, showing which Dockerfile instructions contributed most to image size:

dive myapp:latest
# Shows layer breakdown, highlighting large files added to each layer

Hadolint lints Dockerfiles against best practices, catching common mistakes before building images:

hadolint Dockerfile
# DL3008: Pin versions in apt-get install
# DL3009: Delete apt-get lists after installing
# DL3015: Avoid additional packages in yum install

Container registries beyond Docker Hub include GitHub Container Registry, GitLab Container Registry, Amazon ECR, and Google Container Registry. These integrate with respective platforms' authentication and CI/CD systems:

# Authenticate to GitHub Container Registry
require 'docker-api'

Docker.authenticate!(
  'username' => ENV['GITHUB_USERNAME'],
  'password' => ENV['GITHUB_TOKEN'],
  'serveraddress' => 'ghcr.io'
)

image = Docker::Image.create('fromImage' => 'ghcr.io/owner/image:tag')

Common Pitfalls

Layer caching gotchas occur when developers assume Docker detects file content changes. Docker caches based on file metadata (modification time, inode), not content. Touching a file without changing its content invalidates the cache for that layer and all subsequent layers:

# Cache invalidated even if Gemfile unchanged
RUN touch Gemfile
COPY Gemfile Gemfile.lock ./
RUN bundle install  # Runs every build despite unchanged dependencies

Image tag mutability causes deployment inconsistencies. Tags like latest or stable point to different images over time. Pulling ruby:latest today yields a different image than pulling it next month. Production deployments should reference immutable tags or digest hashes:

# Mutable tag - different image tomorrow
docker pull ruby:latest

# Immutable digest - always same image
docker pull ruby@sha256:abc123...

# Versioned tag - more stable but still mutable
docker pull ruby:3.2.2

Volume permission issues arise from user ID mismatches between container and host. A container running as user 1000 cannot write to host directories owned by user 1001. Alpine-based images compound this by lacking user synchronization tools:

# Create matching user ID
RUN addgroup -g 1000 app && \
    adduser -D -u 1000 -G app app

USER app

# Now writes to volumes succeed if host directories owned by UID 1000

Container networking confusion stems from port publishing versus exposure. EXPOSE documents ports without making them accessible from the host. Publishing (-p flag) actually forwards traffic:

EXPOSE 3000  # Documentation only
# Port inaccessible from host
docker run myapp

# Port accessible on host:3000
docker run -p 3000:3000 myapp

Build context size impacts build performance. Dockerfile COPY . . sends entire directory to Docker daemon, including node_modules, .git, and other unnecessary files. .dockerignore excludes files from build context:

# .dockerignore
.git
node_modules
tmp
log
*.log
.env

Environment variable injection through ENV bakes values into images, exposing secrets in image layers. Runtime variable injection through docker run -e or Compose keeps secrets out of images:

# Bad: Secret in image layer, visible in docker history
ENV DATABASE_PASSWORD=secret123

# Good: Document variable without value
ENV DATABASE_PASSWORD=
# Inject at runtime
docker run -e DATABASE_PASSWORD=secret123 myapp

Resource limits prevent container resource exhaustion affecting host stability. Without limits, containers consume unlimited CPU and memory, potentially crashing the host:

services:
  app:
    image: myapp
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G
        reservations:
          cpus: '0.5'
          memory: 512M

Timezone discrepancies occur because containers default to UTC regardless of host timezone. Applications generating timestamps or scheduling tasks require explicit timezone configuration:

ENV TZ=America/New_York
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

Signal handling failures prevent graceful shutdowns. Docker sends SIGTERM to container PID 1, but shell script wrappers don't forward signals by default. Applications must handle SIGTERM for clean shutdown:

# Bad: Shell doesn't forward signals
CMD bundle exec puma

# Good: exec replaces shell with application
CMD exec bundle exec puma

# Better: Use JSON array syntax (no shell)
CMD ["bundle", "exec", "puma"]

Container filesystem persistence confusion leads to data loss. Container filesystems are ephemeral—data written outside volumes disappears when containers stop. Critical data requires volume mounting:

# config/initializers/uploads.rb
# Bad: Writes to ephemeral container filesystem
CarrierWave.configure do |config|
  config.root = Rails.root.join('public/uploads')
end

# Good: Writes to persistent volume
CarrierWave.configure do |config|
  config.root = '/mnt/uploads'  # Mounted volume
end

Dependency version pinning prevents broken builds from upstream changes. Unpinned base images or system packages introduce breaking changes:

# Unpinned: Breaks when ruby:3.2 points to incompatible version
FROM ruby:3.2

# Pinned: Reproducible builds
FROM ruby:3.2.2-alpine3.18

# System packages need pinning too
RUN apk add --no-cache postgresql-client=15.3-r0

Reference

Core Components

Component Description Example
Image Read-only template with application code and dependencies ruby:3.2-alpine
Container Running instance of an image docker run ruby:3.2-alpine
Dockerfile Build instructions for creating images FROM, RUN, COPY, CMD
Registry Storage and distribution system for images Docker Hub, GitHub Container Registry
Volume Persistent data storage outside container filesystem Named volumes, bind mounts
Network Virtual network connecting containers Bridge, host, overlay networks

Dockerfile Instructions

Instruction Purpose Usage
FROM Set base image FROM ruby:3.2-slim
WORKDIR Set working directory for subsequent instructions WORKDIR /app
COPY Copy files from build context to image COPY Gemfile Gemfile.lock ./
ADD Copy files with URL support and archive extraction ADD archive.tar.gz /app
RUN Execute command during build RUN bundle install
ENV Set environment variable in image ENV RAILS_ENV=production
EXPOSE Document port application listens on EXPOSE 3000
CMD Default command when container starts CMD ["bundle", "exec", "puma"]
ENTRYPOINT Configure container as executable ENTRYPOINT ["ruby"]
USER Set user for RUN, CMD, ENTRYPOINT USER rails
VOLUME Create mount point for volumes VOLUME /var/log
ARG Define build-time variables ARG RUBY_VERSION=3.2
HEALTHCHECK Configure container health check HEALTHCHECK CMD curl localhost:3000

Docker CLI Commands

Command Operation Example
docker build Build image from Dockerfile docker build -t myapp:1.0 .
docker run Create and start container docker run -d -p 3000:3000 myapp:1.0
docker ps List running containers docker ps -a
docker images List images docker images
docker pull Download image from registry docker pull ruby:3.2
docker push Upload image to registry docker push username/myapp:1.0
docker exec Execute command in running container docker exec -it container_id bash
docker logs View container output docker logs -f container_id
docker stop Stop running container docker stop container_id
docker rm Remove container docker rm container_id
docker rmi Remove image docker rmi image_id
docker volume Manage volumes docker volume create data_vol
docker network Manage networks docker network create app_net

Docker Compose Commands

Command Operation Example
docker-compose up Start services docker-compose up -d
docker-compose down Stop and remove services docker-compose down -v
docker-compose build Build service images docker-compose build web
docker-compose logs View service logs docker-compose logs -f web
docker-compose exec Execute command in service container docker-compose exec web rails console
docker-compose ps List service containers docker-compose ps
docker-compose restart Restart services docker-compose restart web
docker-compose scale Scale service replicas docker-compose scale web=3

Volume Types

Type Description Use Case
Named Volume Docker-managed storage location Database data persistence
Bind Mount Host directory mounted into container Development code hot-reloading
tmpfs Mount Memory-backed temporary storage Temporary cache, sensitive data

Network Types

Type Description Use Case
Bridge Default isolated network Multi-container applications
Host Remove network isolation Maximum performance, host port access
Overlay Multi-host networking Swarm services, cross-host communication
None Disable networking Security isolation, batch processing

Health Check Parameters

Parameter Description Default
interval Time between checks 30s
timeout Maximum check duration 30s
start-period Initialization grace period 0s
retries Consecutive failures before unhealthy 3

Resource Limits

Resource Docker Run Flag Compose Syntax
Memory --memory=512m memory: 512M
CPU --cpus=2 cpus: '2'
Memory Reservation --memory-reservation=256m memory: 256M (reservations)
CPU Shares --cpu-shares=512 cpu_shares: 512

Image Tag Conventions

Pattern Example Purpose
Version myapp:1.2.3 Semantic versioning
Git SHA myapp:abc1234 Commit traceability
Environment myapp:staging Environment-specific images
Latest myapp:latest Current development
Digest myapp@sha256:abc... Immutable reference