## TL;DR
The job's image simply does not contain the docker CLI: the default images for most jobs have no docker binary. Either use an image with docker installed, install it in before_script, or use the docker-in-docker service properly. Also confirm you actually need the docker CLI: many "docker build" steps are better as kaniko or buildah jobs that never needed docker at all.

## The query
```text
GitLab CI "docker: command not found" in before_script: image debugging
```

## Use this when
- Jobs fail with docker: command not found
- Choosing docker-in-docker vs socket binding
- before_script assumes tools the image lacks
- Migrating jobs between images

## Not for when
- Cannot connect to the docker daemon (CLI exists, daemon missing)
- Docker build failures (the CLI works, the build fails)
- Registry authentication

## Steps

### Step 1: Check what the image actually contains
Inspect the job's image: does it ship a docker CLI. Most language images do not. The fix starts from knowing the image contents, not from assuming.
Expected output: the image's toolset known; docker confirmed absent.

### Step 2: Use a docker-capable image or install the CLI
Switch the job to an image containing the docker CLI, or install it in before_script from the official static binaries. Installing per-job is slower but keeps your preferred base image.
Expected output: the docker CLI available in the job environment.

### Step 3: Decide: DinD service vs host socket
If you need to build images, add the docker:dind service and configure the client to talk to it, or bind-mount the host's docker socket (simpler, but the builds share the host daemon with security implications). Choose deliberately per runner type.
Expected output: a working docker daemon reachable from the job.

### Step 4: Consider daemonless builders instead
For image builds, kaniko or buildah run without a docker daemon at all and sidestep the entire DinD complexity. If the job only builds and pushes, you may not need docker whatsoever.
Expected output: the job building images without docker-in-docker.

### Step 5: Pin the builder image version
Whether docker image or kaniko, pin the version. "Latest" builder images change behavior under you; pinned builders make the pipeline reproducible.
Expected output: deterministic builder tooling.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_ahQK6NMFyhTBn6IoEzNIWg
