How do you choose between the docker-ce repository packages, the get.docker.com script and Docker Desktop when provisioning build hosts?
answer
- Three channels, three different audiences
- Only one lets you name a version
- One is documented as not for production
- One is a licensed workstation product
- The fleet cares about sameness, not speed
basics
~20 sUse Docker's docker-ce repository packages with an explicit pinned version for servers and build hosts; the get.docker.com convenience script is for quick throwaway boxes, not production; Docker Desktop is a licensed developer workstation product, not a server install.
solid answer
~50 sThere are three delivery channels and they answer different questions. **Docker's own apt/dnf repository** installs `docker-ce`, `docker-ce-cli`, `containerd.io`, `docker-buildx-plugin` and `docker-compose-plugin` — it is the production path because you can name an exact version, hold it, and roll the fleet deliberately. The **get.docker.com convenience script** does exactly that repository setup for you unattended; Docker documents it as unsuitable for production, because it always takes the latest release, needs root to pipe a remote script into a shell, and gives you no version control — fine for a laptop VM or a demo box. **Docker Desktop** is a workstation product with its own VM and a licence that is not free for larger organisations; it is not how you put an engine on a server. Distro-shipped packages such as `docker.io` are a fourth option, older but supported by the distro's own security stream.
code
bash · 5 linesapt-cache madison docker-ce
VER=$(apt-cache madison docker-ce | awk 'NR==1{print $3}')
sudo apt-get install -y docker-ce="$VER" docker-ce-cli="$VER" containerd.io docker-buildx-plugin docker-compose-plugin
sudo apt-mark hold docker-ce docker-ce-cli
docker versiongo deeper
Know that there is more than one way to get Docker onto a machine, and that Docker Desktop is the laptop product while servers get the engine packages. Be able to name docker-ce and docker-ce-cli as separate packages.
Explain what each channel does under the hood — the convenience script configures the same repository the manual instructions do — and why installing a named version and holding it matters for a machine that lives longer than a day.
Argue from failure modes: engine drift across a fleet, an unattended upgrade restarting dockerd mid-build, client and daemon packages moving apart, half-installed hosts with two package sources. Tie the choice to provisioning rather than to a command.
Own the estate policy: one install source, one pinned version, upgrades as a scheduled batch with agents drained, licence exposure for Desktop understood, and the engine version treated as a declared property of a host image rather than something an operator types.
### The three channels, and what each is actually for **1. Docker's package repository (`docker-ce`).** You add Docker's apt or dnf repository and its signing key, then install the engine as ordinary packages. The current set is five: `docker-ce` (the daemon), `docker-ce-cli` (the client), `containerd.io`, `docker-buildx-plugin` and `docker-compose-plugin`. This is the only channel that gives you the two properties a fleet needs: you can install a **named version** rather than "whatever is newest today", and you can hold it so an unrelated `apt upgrade` does not move the engine underneath a running workload. ``` VER=$(apt-cache madison docker-ce | awk 'NR==1{print $3}') sudo apt-get install -y docker-ce="$VER" docker-ce-cli="$VER" \ containerd.io docker-buildx-plugin docker-compose-plugin sudo apt-mark hold docker-ce docker-ce-cli ``` The reason to pin both `docker-ce` and `docker-ce-cli` to the same string is the skew problem: they are separate packages and nothing stops a host from acquiring a newer client than daemon. **2. The convenience script at get.docker.com.** `curl -fsSL https://get.docker.com -o get-docker.sh && sudo sh get-docker.sh` detects the distribution, configures the same repository, and installs the latest release. It is genuinely useful — for a scratch VM, a lab box, a five-minute reproduction. Docker's own documentation says it is **not recommended for production**, and the reasons are worth being able to list: it requires piping a remote script into a root shell; it always installs the latest version with no way to pick one; it may enable prerelease channels if you ask it to; it does not integrate with whatever configuration management already owns the host; and it can behave surprisingly on a machine that already has some Docker packages installed. If you need unattended installs at scale, the honest answer is "configuration management driving the repository packages", not "the script in a loop". **3. Docker Desktop.** Desktop is a developer workstation product for macOS, Windows and Linux desktops. It bundles a GUI, its own Linux virtual machine, and a licence that requires a paid subscription for organisations above Docker's published size threshold. It is the right answer for "how do developers get an engine on their laptop" and the wrong answer for "how does a build host get an engine". Confusing the two is a common interview stumble. **4. The distribution's own package.** Debian and Ubuntu ship `docker.io`, Fedora ships a `moby-engine`. These are packaged by the distro rather than by Docker: usually older, tied to the distro release cycle, and carried by the distro's security updates. They are a legitimate choice for a conservative estate that wants one update mechanism for everything, and a poor one if you need a recent BuildKit or a feature from a recent release. Mixing them with Docker's own repository on the same host is where conflicts come from — pick one source per host. ### The fleet question underneath Suppose 41 CI build hosts compile a Go CLI into a `scratch` image. What you care about is not which command installs Docker but whether all 41 hosts have the **same** engine, and whether that engine changes only when you decide it does. That reframes the choice completely: - **Reproducibility.** Named version plus hold, applied by configuration management, so a host rebuilt in six months lands on the version you chose rather than the one that shipped this morning. - **Uniformity.** Skew between hosts is what generates the "works on 37 of 41 agents" tickets. One source, one version, upgraded as a batch. - **Upgrade path.** Engine upgrades restart dockerd. Plan them as a maintenance action — drain the agent, upgrade, put it back — not as a side effect of unattended-upgrades running at 03:00. - **Provenance.** The repository is signed; verifying the key is part of the install and part of what you can show an auditor. A `curl | sh` install has a much weaker story. ### How to answer the question in an interview State the decision rule first, then the reasons: **repository packages with an explicit version for anything long-lived; the convenience script only for disposable hosts; Desktop only for workstations, with the licence caveat named.** Then show that you know the failure modes — drifting engine versions across a fleet, CLI and daemon packages moving independently, an unattended upgrade restarting the daemon mid-build, and a host that has both the distro package and Docker's own repository half-installed. Those are the things that actually cost time, and naming them is what distinguishes an operator's answer from a recital of install commands.
- Why does Docker document the get.docker.com script as unsuitable for production?It always installs the latest release with no version selection, it requires piping a remote script into a root shell, and it configures the host outside whatever configuration management owns it. On a fleet that produces drift — hosts provisioned on different days end up on different engines — and it removes the deliberate, batched upgrade you want for a service whose restart kills running builds. It is a convenience for disposable machines.
- Why pin docker-ce and docker-ce-cli to the same version string rather than just the engine?They are separate packages that can move independently, and the client and daemon speak a versioned API. Pinning only the daemon lets a routine upgrade pull a newer CLI onto the host, which is exactly the configuration that produces version-skew failures. Pinning both, and holding them, keeps the pair coherent and makes the engine version a deliberate change rather than a side effect.
- When is the distribution's own docker.io package the better choice?When the estate values one update mechanism and one security stream over having a recent engine — a conservative server fleet where the distro's support lifecycle is the governing constraint. The tradeoff is age: you get whatever the distro release froze, so recent BuildKit and CLI features may be missing. The rule is one source per host; mixing distro packages with Docker's repository is where conflicts come from.
saying these in an interview costs you the question
- Recommends curl | sh on production servers
- Proposes Docker Desktop as a server install
- Ignores the Desktop subscription requirement
- Installs latest everywhere with no version pin
- Mixes distro packages and Docker's repository on one host
- Pins the daemon package but lets the CLI float