Docker is an openโsource platform for packaging applications and their dependencies into lightweight, portable units called containers, enabling consistent behavior across development, testing, and production environments (Docker, Wikipedia). Its core component, the Docker Engine, powers container execution, while Docker Desktopโa userโfriendly application tailored for macOSโbundles the Docker Engine, Docker CLI, Docker Compose, Kubernetes integration, and a visual Dashboard into a seamless package (Docker Documentation).
On macOS, Docker Desktop simplifies container workflows by leveraging native virtualization (HyperKit on Intel Macs, Apple’s Hypervisor.framework on Apple Silicon), eliminating the need for cumbersome VMs like VirtualBox (The Mac Observer, Medium).
Installation is straightforward: simply download the appropriate .dmg installer (Intel or Apple Silicon), drag Docker into the Applications folder, and proceed through setupโgranting permissions and accepting licensing as needed (LogicCore Digital Blog). Once up and running, you can verify your setup via commands like:
docker --version
docker run hello-world
docker compose version
These commands confirm successful installation and provide instant access to Docker’s ecosystem on your Mac.
Commands Executed in Local System:
โ docker --version
zsh: command not found: docker
โ docker ps
# check the exact container name:
โ docker ps --format "table {{.Names}}\t{{.Image}}"
# rebuild the containers
โ docker-compose down
โ docker-compose up --build
# Error: target webpacker: failed to solve: error getting credentials - err: exec: "docker-credential-desktop": executable file not found in $PATH, out: ``
โ cat ~/.docker/config.json # remove "credsStore": "desktop"
# Remove all containers and images
โ docker container prune -f
โ docker image prune -f
โ docker ps -a # check containers
โ docker images # check images
โ docker-compose up --build -d # build again
# postgres
โ docker exec -it image-name psql -U username -d database_name
# rails console
โ docker exec -it image-name rails c
# get into the docker container shell
โ docker exec -it image-name bash
๐ณ 1. Difference between docker compose up --build and docker compose up
docker compose up
- Just starts the containers using the existing images.
- If the image for a service doesnโt exist locally, Docker will pull it from the registry (e.g., Docker Hub).
- It will not rebuild your image unless you explicitly tell it to.
docker compose up --build
- Forces Docker to rebuild the images from the
Dockerfilebefore starting the containers. - Useful when youโve changed:
- The
Dockerfile - Files copied into the image
- Dependencies
- The
- This ensures your running containers reflect your latest code and build instructions.
๐ Example:
docker compose up # Use existing images (fast startup)
docker compose up --build # Rebuild images before starting
If you changed your app code and your Docker setup uses bind mounts (volumes), you usually don’t need --build unless the image itself changed.
If you changed the Dockerfile, then you need --build.
๐ฅ 2. Why we use Docker Desktop & can we use Docker without it?
Docker Desktop is basically a GUI + background service that makes Docker easy to run on macOS and Windows.
It includes:
- Docker Engine (runs containers)
- Docker CLI
- Docker Compose
- Kubernetes (optional)
- Settings & resource controls (CPU, RAM)
- Networking setup
- A UI to view containers, images, logs, etc.
Why needed on macOS & Windows?
- Docker requires Linux kernel features like cgroups & namespaces.
- macOS and Windows don’t have these natively, so Docker Desktop runs a lightweight Linux VM behind the scenes (using HyperKit, WSL2, etc.).
- Without Docker Desktop, you’d need to set up that Linux VM manually, install Docker inside it, and configure networking โ which is more complex.
Can you use Docker without Docker Desktop?
Yes, but:
- On macOS/Windows โ you’d have to:
- Install a Linux VM manually (VirtualBox, VMware, UTM, etc.)
- SSH into it
- Install Docker Engine
- Expose ports and share files manually
- On Linux โ you don’t need Docker Desktop at all, you can install Docker Engine directly via:
sudo apt install docker.io - For Windows, Microsoft has Docker on WSL2 which can run without the Docker Desktop GUI, but requires WSL2 setup.
๐ก In short:
- Use
--buildwhen you change something in the image definition. - Docker Desktop = easiest way to run Docker on macOS/Windows.
- You can skip Docker Desktop, but then you must manually set up a Linux VM with Docker.
๐งฉ 1. Core Docker Concepts
| Term | What it is | Key analogy |
|---|---|---|
| Image | A read-only blueprint (template) that defines what your app needs to run (OS base, packages, configs, your code). Built from a Dockerfile. | Like a recipe for a dish |
| Container | A running instance of an image. Containers are isolated processes, not full OSes. | Like a meal prepared from the recipe |
| Volume | Persistent storage for containers. Survives container restarts or deletions. | Like a pantry/fridge where food stays even after cooking is done |
| Docker Compose | A YAML-based tool to define & run multi-container apps. Lets you describe services, networks, and volumes in one file and start them all at once. | Like a restaurant order sheet for multiple dishes at once |
| Network | Virtual network that containers use to talk to each other or the outside world. | Like a kitchen intercom system |
โธ 2. Kubernetes in simple words
Kubernetes (K8s) is a container orchestration system. Itโs what you use when you have many containers across many machines and you need to manage them automatically.
What it does:
- Deploy containers on a cluster of machines
- Restart them if they crash
- Scale up/down automatically
- Load balance traffic between them
- Handle configuration and secrets
- Do rolling updates with zero downtime
๐ Analogy
If Docker Compose is like cooking multiple dishes at home, Kubernetes is like running a huge automated kitchen in a restaurant chain โ you don’t manually turn on each stove; the system manages resources and staff.
๐ 3. How Docker Works on macOS
Your assumption is right โ Docker needs Linux kernel features (cgroups, namespaces, etc.), and macOS doesnโt have them.
So on macOS:
- Docker Desktop runs a lightweight Linux virtual machine under the hood using Appleโs HyperKit (before) or Apple Virtualization Framework (newer versions).
- That VM runs the Docker Engine.
- Your
dockerCLI in macOS talks to that VM over a socket. - All containers run inside that Linux VM, not directly on macOS.
Workflow:
Mac Terminal โ Docker CLI โ Linux VM in background โ Container runs inside VM
โ 4. Hardware Needs for Docker on macOS
Yes, VMs can be heavy, but Docker’s VM for macOS is minimal โ not like a full Windows or Ubuntu desktop VM.
Typical Docker Desktop VM:
- Base OS: Tiny Linux distro (Alpine or LinuxKit)
- Memory: Usually 2โ4 GB (configurable)
- CPU: 2โ4 virtual cores (configurable)
- Disk: ~1โ2 GB base, plus images & volumes you pull
Recommended host machine for smooth Docker use on macOS:
- RAM: At least 8 GB (16 GB is comfy)
- CPU: Modern dual-core or quad-core
- Disk: SSD (fast read/write for images & volumes)
๐ก Reason it’s lighter than “normal” VMs:
Docker doesn’t need a full OS with GUI in its VM โ just the kernel & minimal services to run containers.
โ Quick Recap Table:
| Term | Purpose | Persistent? |
|---|---|---|
| Image | App blueprint | Yes (stored on disk) |
| Container | Running app from image | No (dies when stopped unless data in volume) |
| Volume | Data storage for containers | Yes |
| Compose | Multi-container management | Yes (config file) |
| Kubernetes | Cluster-level orchestration | N/A |
Quickest way to see per-request Rails logs in Docker
- Run app logs:
docker compose logs -f --tail=200 main-app
- Run Sidekiq logs:
docker compose logs -f --tail=200 sidekiq
- Filter for a single request by its request ID (see below):
docker compose logs -f main-app | rg 'request_id=YOUR_ID'
Ensure logs are emitted to STDOUT (so Docker can collect them)
Your images already set RAILS_LOG_TO_STDOUT=true and the app routes logs to STDOUT:
if ENV["RAILS_LOG_TO_STDOUT"].present?
logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = config.log_formatter
config.log_tags = [:subdomain, :uuid]
config.logger = ActiveSupport::TaggedLogging.new(logger)
end
So the docker compose logs commands above are the right way. Tailing log files inside the container usually isnโt needed, but if you want to:
docker compose exec main-app bash -lc 'tail -f log/development.log'
Trace a single request end-to-end
- Get the request ID from the response (Rails sets
X-Request-Id):
REQ=$(curl -s -D - http://localhost:3001/your/path -o /dev/null | awk '/X-Request-Id/ {print $2}' | tr -d '\r')
docker compose logs -f main-app | rg "$REQ"
- Your app tags logs with a UUID per request; switching to the canonical tag makes grepping easier. Optionally change tags to:
# in `website-v1/config/application.rb`
config.log_tags = [:request_id]
Make logs easier to read (optional, but highly recommended)
- Add concise, per-request logging (1 line per request) with JSON output for easy grep/parse:
# Gemfile
gem 'lograge'
# config/initializers/lograge.rb
Rails.application.configure do
config.lograge.enabled = true
config.lograge.formatter = Lograge::Formatters::Json.new
config.lograge.custom_options = lambda do |event|
{
request_id: event.payload[:request_id],
params: event.payload[:params].except('controller','action'),
user_id: event.payload[:user_id],
time: Time.now.utc
}
end
end
Then:
bundle install
docker compose restart main-app
docker compose logs -f main-app
Now you can grep easily:
docker compose logs -f main-app | jq -r 'select(.request_id=="'"$REQ"'")'
Tuning
- In development, you already have
config.log_level = :debug. For production, consider:infoinstead of:warnto get request lines:
# config/environments/production.rb
config.log_level = :info
- Sidekiq logs are a separate stream (service
sidekiq); use its logs for background job tracing. - Noise reduction: you already have
config.assets.quiet = truein development.
If you want, I can switch to :request_id tagging and add lograge with JSON in the repo now.
- Made no code edits; provided commands to stream logs from
main-appandsidekiq. - Confirmed logs are routed to STDOUT via
RAILS_LOG_TO_STDOUTandTaggedLogginginapplication.rb. - Offered optional improvements (switch to
:request_id, addlogrageJSON) and how to grep a single request by ID.




