The email that arrived from Legal one day
"Please confirm whether our company is in scope for Docker Desktop’s paid license."
It’s one of the emails engineering leads in Korea dread most. Under Docker’s subscription terms, Docker Desktop is free for small businesses with fewer than 250 employees and less than $10 million in annual revenue, and for personal use, education, and non-commercial open source; other organizations need a paid Pro, Team, or Business subscription for professional use (checked October 2026). Docker Desktop license agreement Questions that need interpretation, such as whether affiliates are counted together, should be settled against the agreement text with Legal. Amounts in this article use public prices as of October 2026 to illustrate the method; exchange rates, taxes, and discounts are not included.
The problem is that “then let’s just use a free alternative” is not as simple as it sounds. Integration tests that use Testcontainers start failing, internal scripts that hardcode /var/run/docker.sock stop working, and bind-mount performance for node_modules on macOS feels noticeably different. Save a few million KRW on licenses only to burn a full day of 20 developers, and the economics flip.
This article answers five questions:
- Which tool should our team pick given our constraints? (30-second decision tree)
- How much money do we actually save? (TCO formulas by team size)
- How much performance and compatibility should we accept as trade-offs? (9-point comparison)
- Which commands do we use to migrate? (migration runbook)
- When should we actually keep Docker Desktop?
30-second decision tree: start with the conclusion
Follow the tree from the top.
Q1. Is our organization in scope for Docker Desktop’s paid license?
(In scope if 250+ employees or $10M+ annual revenue — check the agreement text)
├─ NO → Keep using it for free. Treat the rest of this article as performance-tuning reference only.
└─ YES → Go to Q2
Q2. What is the team’s primary OS?
├─ macOS (Apple Silicon) → Go to Q3 (OrbStack is the frontrunner)
├─ macOS (Intel) → Go to Q3 (OrbStack’s edge shrinks; Rancher becomes more competitive)
└─ Windows + WSL2 → Go to Q3 (OrbStack is out; Rancher vs. Podman)
Q3. Do we need a local Kubernetes cluster running at all times?
├─ YES → Conclusion B (Rancher Desktop)
└─ NO → Go to Q4
Q4. Can the company pay for a commercial SaaS subscription billed overseas?
├─ YES → Conclusion A (OrbStack)
└─ NO → Conclusion C (Podman Desktop)One-line rationale for each conclusion
| Conclusion | Tool | One-line rationale |
|---|---|---|
| A | OrbStack | Native virtualization on macOS only: fastest perceived boot and file I/O, and docker CLI compatibility is effectively lossless. Paid for team use, and no support outside macOS |
| B | Rancher Desktop | Local K8s based on k3s turns on with a single toggle; covers Windows, macOS, and Linux. Open source, so license cost is 0 |
| C | Podman Desktop | Rootless, daemonless architecture is easier to get through security review, and fully free. docker compatibility is handled via socket emulation, but edge cases exist |
Backup option: colima if you don’t need a GUI
If your team only uses the CLI and has no need for a GUI dashboard, colima is the lightest answer. Install via Homebrew, run colima start, and you’re done—it attaches to the docker CLI as-is.
brew install colima docker docker-compose
colima start --cpu 4 --memory 8 --vm-type vz --mount-type virtiofs
docker context use colima
docker run --rm hello-worldExpected result: the Hello from Docker! message is printed. If it fails, first check that the VM is Running with colima status. --vm-type vz uses Apple’s Virtualization.framework on macOS 13 or later. By default colima mounts only your home directory (/Users/$USER) into the VM, so bind-mounting any other path shows an empty directory with no error. Add the path under mounts in ~/.colima/default/colima.yaml and run colima restart. colima FAQ The downsides: no GUI, you have to dig through logs yourself when something breaks, and support load grows if any teammates are not CLI-native.
Prices and terms checked October 2026. Prices, versions, and license terms change—recheck the official docs before applying.
Running the numbers: TCO for 5-, 20-, and 50-person teams
The real cost of free tools is labor hours. The calculations below use these formulas.
Commercial tool annual cost = monthly price per seat × number of developers × 12 + switching hours × number of developers × hourly rate
Open-source annual cost = (initial setup hours + annual troubleshooting hours) × number of developers × hourly rateAssumptions (all examples):
- Developer hourly rate: 60,000 KRW (a rough assumption based on converting annual salary)
- Exchange rate: $1 = 1,400 KRW
- Docker Desktop: for several people under a company account, Team ($15 per user per month billed annually, up to 100 users) or Business ($24 per user per month) is the realistic plan; Pro ($9) is a single-user subscription. The tables use Team at $15 ≈ 21,000 KRW. Docker pricing
- OrbStack: commercial use needs Pro at $8 per user per month ($96 a year) ≈ 11,000 KRW OrbStack pricing. A commercial tool still takes time to install and verify, so we add 1 switching hour per person. Annual troubleshooting is assumed similar to the current Docker Desktop and set to 0.
- Open-source initial setup: 3 hours per person; annual troubleshooting: 6 hours per person → 9 hours total
5-person team
| Tool | Formula | Annual cost |
|---|---|---|
| Docker Desktop (Team) | 21,000 × 5 × 12 | 1,260,000 KRW |
| OrbStack Pro | 11,000 × 5 × 12 + 1h × 5 × 60,000 | 960,000 KRW |
| Rancher Desktop | 9h × 5 × 60,000 | 2,700,000 KRW |
| Podman Desktop | 9h × 5 × 60,000 | 2,700,000 KRW |
20-person team
| Tool | Formula | Annual cost |
|---|---|---|
| Docker Desktop (Team) | 21,000 × 20 × 12 | 5,040,000 KRW |
| OrbStack Pro | 11,000 × 20 × 12 + 1h × 20 × 60,000 | 3,840,000 KRW |
| Rancher Desktop | 9h × 20 × 60,000 | 10,800,000 KRW |
| Podman Desktop | 9h × 20 × 60,000 | 10,800,000 KRW |
50-person team
| Tool | Formula | Annual cost |
|---|---|---|
| Docker Desktop (Team) | 21,000 × 50 × 12 | 12,600,000 KRW |
| OrbStack Pro | 11,000 × 50 × 12 + 1h × 50 × 60,000 | 9,600,000 KRW |
| Rancher Desktop | 9h × 50 × 60,000 | 27,000,000 KRW |
| Podman Desktop | 9h × 50 × 60,000 | 27,000,000 KRW |
With Docker Business ($24), a 50-person team comes to 20,160,000 KRW a year. Prices are public list prices as of October 2026; labor hours are assumptions.
How to read this table
Looking at the numbers alone, you get the paradox that “free tools cost more.” But several important caveats apply.
- Labor hours are largely one-time. The initial 3 hours happen only in year one. If you write an internal standard install script and roll it out, that drops to 20 minutes per person. Then a 50-person team’s year-2 cost is not
(0.33h + 6h) × 50 × 60,000 ≈ 19,000,000 KRW; if you also cut troubleshooting time in half, it comes down to around3h × 50 × 60,000 = 9,000,000 KRW. - License fees, by contrast, recur every year. The break-even from year two can be computed directly:
break-even annual troubleshooting hours per person = monthly price per seat × 12 ÷ hourly rateWith Team,21,000 × 12 ÷ 60,000 = 4.2 hours. If open-source troubleshooting after the switch stays under 4.2 hours per person per year, open source is cheaper from year two; above that it stays more expensive. With Business it is33,600 × 12 ÷ 60,000 ≈ 6.7 hours. - If actual labor hours differ from these assumptions, the conclusion flips. If the team has container experts, troubleshooting can drop to 1–2 hours; if you use Testcontainers and a complex Compose stack, it can exceed 20 hours.
The key takeaway: free is not always cheaper. Don’t copy this table as-is—plug your team’s actual hourly rate and expected labor hours into the formula above and recalculate. The cost-comparison methodology itself is the same approach covered in GitHub Actions vs GitLab CI Pricing: Hands-on Calculations Across 3 Scenarios.
Performance and usability: 9-point comparison
Measurement environment disclaimer
The table below summarizes commonly reported tendencies and each tool’s architectural characteristics. Read it as relative trends, not absolute numbers. You must measure the actual values on your own machines and workloads.
- Assumed baseline: macOS Apple Silicon (M-series), 16GB RAM, VM allocated 4 vCPU / 8GB
- Assumed workload: Node.js project (tens of thousands of files in
node_modules) bind-mounted; image build based onnode:20-alpine - Numbers vary widely depending on machine specs, disk health, and whether the image cache is warm
| Item | Docker Desktop | OrbStack | Rancher Desktop | Podman Desktop |
|---|---|---|---|---|
| Cold boot | Average (tens of seconds) | Very fast (a few seconds) | Average to slow | Average |
| Volume I/O (many files) | Improved, but VM-boundary overhead remains | Most favorable (native virtualization optimizations) | Average | Average; mount-option tuning required |
| Image build | buildx built in by default, fast | Fast (buildx compatible) | nerdctl/buildkit based, decent | buildah based; option differences exist |
| Idle memory | Relatively high | Low (dynamic allocation) | Medium | Medium |
| Local K8s | Built-in K8s toggle | Built-in K8s support | k3s provided by default | Separate setup (kind, etc.) |
| docker CLI compatibility | Baseline (100%) | Effectively lossless | High (nerdctl in parallel) | Socket emulation required |
| Compose compatibility | Complete | Complete | Alternatives such as nerdctl compose | podman compose (some syntax differences) |
| rootless | Partial support | VM isolation | Supported | Daemonless and rootless by default |
| Korean UI / Korea support | English UI; global support contracts available | English UI; no confirmed Korean distributor | English UI; SUSE-family partners exist | English UI; Red Hat partner channels |
If you want to measure this yourself, run a minimal reproduction script like the following.
# 1) Runtime start-up time: quit the tool completely, keep only the start command of the tool you are measuring
start=$(date +%s)
docker desktop start # or: open -a OrbStack / colima start / podman machine start / rdctl start
until docker info >/dev/null 2>&1; do sleep 1; done
echo "ready in $(( $(date +%s) - start ))s"
# 2) Bind-mount file I/O: run under your home directory (colima's default mount scope)
mkdir -p ~/iotest && cd ~/iotest
time docker run --rm -v "$PWD":/w -w /w alpine \
sh -c 'for i in $(seq 1 5000); do echo x > f_$i; done'
cd ~ && rm -rf ~/iotest
# 3) Build time (no cache, same Dockerfile for each tool)
time docker build --no-cache -t bench:local .How to read it: time runs in the host shell, so container start-up is included. Compare the median of three runs per tool on the same machine rather than absolute values. If step 1 keeps waiting, use docker context ls to confirm the current context points to the tool you just started. docker desktop start works only on Docker Desktop versions that include the Docker Desktop CLI. Docker Desktop CLI The previous version used time docker info, which only measures an already-running daemon’s response, and time ( ... ) inside the container, which does not work in alpine’s default shell.
For how volume-mount strategy affects performance, we covered the concepts in Docker Volumes vs Bind Mounts — A Complete Guide to Data Persistence.
Migration runbook
Step 1: Back up the current state
# save the image list
docker images --format '{{.Repository}}:{{.Tag}}' > images.txt
# archive important images
docker save -o backup-images.tar $(cat images.txt | grep -v '<none>' | tr '\n' ' ')
# volume backup (example volume name: my_data)
docker run --rm -v my_data:/src -v "$PWD":/dst alpine \
tar czf /dst/my_data.tgz -C /src .Expected result: backup-images.tar and my_data.tgz files are created. If you get tar: /src: Cannot open, the volume name is wrong—check the exact name with docker volume ls.
Step 2: Connect the new runtime
# --- OrbStack / colima stack ---
docker context ls
docker context use orbstack # or colima
docker version # success if the Server section is shown
# --- Rancher Desktop ---
docker context use rancher-desktop
nerdctl ps # when using the containerd backend
# --- Podman ---
podman machine init --cpus 4 --memory 8192
podman machine start
podman system connection list
# to keep using the docker CLI: set the socket path as an env var
export DOCKER_HOST="unix://$(podman machine inspect --format '{{.ConnectionInfo.PodmanSocket.Path}}')"
docker ps # answers via the podman backendYou can put DOCKER_HOST in ~/.zshrc and roll it out to the whole team. However, using a context and an environment variable at the same time will conflict, so pick only one approach.
Step 3: Restore images and volumes
docker load -i backup-images.tar
docker volume create my_data
docker run --rm -v my_data:/dst -v "$PWD":/src alpine \
tar xzf /src/my_data.tgz -C /dstStep 4: Verify Compose
# Podman
podman compose up -d
# Rancher Desktop (containerd backend)
nerdctl compose up -d
# OrbStack / colima
docker compose up -dFive things that commonly break, and the workarounds
① Compose file syntax differences
podman compose internally calls an external Compose implementation, and behavioral differences have been reported for depends_on condition, extends, and some x- extension fields.
- Symptom:
unsupported key, or service startup order gets scrambled - Workaround: use the
docker-composebinary +DOCKER_HOSTinstead ofpodman-compose, or replacedepends_onwith application-level retry logic
② Hardcoded /var/run/docker.sock and Testcontainers
This is the most common tripwire. CI scripts, Testcontainers, and some IDE plugins hardcode the socket path.
On macOS, a /var/run/docker.sock link made by hand with ln -sf breaks on reboot or machine re-creation. The official Podman installer also installs podman-mac-helper, which manages this link. If you installed another way (for example Homebrew) and the link is missing, run it once (needs admin rights; the official package path is /opt/podman/bin).
sudo podman-mac-helper install
podman machine stop && podman machine start
ls -l /var/run/docker.sock # should point to podman.sockFor Testcontainers, set the Podman configuration from the official docs as environment variables.
# macOS
export DOCKER_HOST="unix://$(podman machine inspect --format '{{.ConnectionInfo.PodmanSocket.Path}}')"
export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock
# Linux rootless Podman
export DOCKER_HOST="unix://${XDG_RUNTIME_DIR}/podman/podman.sock"
export TESTCONTAINERS_RYUK_DISABLED=trueWith rootless Podman the official docs say to disable Ryuk (the cleanup container). Finished test containers are then not removed automatically, so add a cleanup step in CI (for example, removing containers labeled org.testcontainers=true). The old ryuk.container.privileged=true is no longer needed from Testcontainers for Java 1.19.0. Testcontainers: supported runtimes
③ File permissions and UID mapping
In a rootless environment, UIDs inside the container are not mapped 1:1 to host UIDs.
- Symptom:
Permission deniedon a bind-mounted directory - Workaround: use the
--userns=keep-idoption, or alignUSERin the Dockerfile with the host UID
podman run --rm --userns=keep-id -v "$PWD":/w:Z -w /w alpine touch test.txtOn environments with SELinux enabled (mostly Linux), the :Z label is required. On macOS it is ignored.
④ DNS and port-forwarding differences
Name resolution between containers and the behavior of host.docker.internal differ by tool.
- Podman: uses
host.containers.internal; you can add an alias with--add-host=host.docker.internal:host-gateway - Rancher Desktop: some settings do not auto-expose ports, so check the network settings in the GUI
podman run --rm --add-host=host.docker.internal:host-gateway alpine \
ping -c1 host.docker.internal⑤ Missing buildx builder
Teams that were using multi-arch builds (--platform linux/amd64,linux/arm64) need an alternative path.
# Podman: manifest method
podman build --platform linux/amd64 -t app:amd64 .
podman build --platform linux/arm64 -t app:arm64 .
podman manifest create app:multi
podman manifest add app:multi app:amd64
podman manifest add app:multi app:arm64
podman manifest push app:multi docker://registry.example.com/app:multi
# Rancher Desktop: use buildkit directly
nerdctl build --platform=amd64,arm64 -t app:multi .The safest alternative is not doing multi-arch builds locally at all—move them to CI. That makes it independent of which local runtime you pick, so the migration risk disappears.
Five cases where “just keep Docker Desktop” is the right call
To be honest, if any of the following apply, you’re better off not switching.
- Testcontainers-based integration tests are a core pipeline — when Ryuk, socket-path, and permission issues stack up, debugging cost quickly exceeds the license fee.
- You already use enterprise security scanning and policy-management features — management capabilities like image vulnerability scanning and registry access control have to be reassembled with separate tools on the free alternatives.
- Non-engineering roles also use Docker — if PMs and QA start and stop containers via a GUI, a CLI-heavy alternative leads to a surge in support requests.
- A vendor support contract is an audit requirement — on finance and public-sector projects, if “official vendor support” is on the checklist, switching to open source actually increases audit risk.
- A small team inside an organization that needs licenses — for a 5-person team in a large group, saving 1,260,000 KRW a year (Team) costs 45 hours (2,700,000 KRW at 60,000 KRW/hour). A standalone small company may be free in the first place, so check the license criteria first.
30-day migration checklist
| Period | Work | Done when |
|---|---|---|
| D+1–3 | Officially confirm whether the paid license applies; survey current usage | Document developer count, OS distribution, and whether Testcontainers is in use |
| D+4–7 | Pick one candidate via the decision tree; designate 2–3 pilot users | Candidate tool confirmed and approved |
| D+8–14 | Pilot: fully bring up one primary project on the new runtime | compose up → full test suite passes |
| D+15–18 | Catalog breakage points + document workarounds internally | Record whether each of the five items above has a response |
| D+19–25 | Roll out a standard install script; expand to half the team | Per-person install time under 30 minutes |
| D+26–30 | Full rollout or rollback decision | Full switch only if none of the rollback criteria below are met |
Rollback criteria (keep Docker Desktop if any one applies):
- Per-person troubleshooting time exceeds 8 hours during the pilot
- CI/CD pipeline fails due to local-runtime differences
- Primary project’s development cycle (build + test) time increases by 30% or more
FAQ
Q1. What exactly are the criteria for Docker Desktop’s paid license? A. As of October 2026 the agreement makes Docker Desktop free for businesses with fewer than 250 employees and less than $10 million in annual revenue and for personal, education, and non-commercial open-source use; other professional use needs a Pro, Team, or Business subscription. Docker Desktop license agreement Where interpretation differs, such as counting subsidiaries and affiliates, decide against the agreement text with Legal and Procurement.
Q2. If we switch to Podman Desktop, do we have to relearn the existing docker commands?
A. For the most part, you keep using them as-is. podman has high command compatibility with the docker CLI, and you can keep existing scripts via alias docker=podman or the DOCKER_HOST environment variable. However, because it is rootless, permissions and networking behave differently—review the “five things that commonly break” section above beforehand.
Q3. Can OrbStack be used on Windows? A. OrbStack is macOS-only. If the team mixes Windows/WSL2 environments, either use different tools per OS or standardize on a cross-platform option like Rancher Desktop or Podman Desktop—that’s less operational overhead.
Sources and checks vary by article. Only articles with a recorded check date, scope and sources below were checked, and only within that scope. For other articles, verify against the current docs for your version before applying anything, and email us about errors. Editorial policy · email us
This article has no recorded human check (date and scope) yet.
Comments
Be the first to comment.