Skip to content
🎉 Launch sale:50% off everything over $22 — automatically applied at checkout· ends Aug 2Shop the sale →
DevOps AI ToolKit
Newsletter
← All packs & kits

🦊 Migrate off shell executors without breaking 40 pipelines

You know you should move to the Docker executor. You're also the one who gets paged when a pipeline breaks. This kit is the reversible, one-pipeline-at-a-time playbook — built from a real production migration of an infrastructure-heavy GitLab estate.

One-time purchase · runnable ZIP + 80-page PDF · single-team license · GitLab 16+

6
sections
10
before/after patterns
25
gotchas
tags
gradual cutover
What's inside

Six sections, in the order you'll use them

Not a blog post — runnable configs, scripts, and complete pipeline examples.

01 · Assessment

Audit checklist + a runnable audit-script.sh that scans your .gitlab-ci.yml files for shell-executor dependencies, plus a risk matrix to score each pipeline.

02 · Runner setup

Annotated config.toml (GitLab 16+ auth-token flow), an idempotent register script, a concurrency/sizing guide, and an Ansible role to deploy runners.

03 · Custom images

One-image-vs-many strategy, a pinned non-root base Dockerfile, a worked Ansible-toolchain image, the pipeline that builds your CI images, and a registry-auth guide.

04 · Pipeline migration

10 complete before/after .gitlab-ci.yml patterns, secrets → CI variables/Vault, getting cache & artifacts right, and honest dind-vs-BuildKit-vs-Buildah tradeoffs.

05 · Cutover

A tag-based gradual cutover runbook, a tested rollback plan, and a per-pipeline validation checklist so you sign off on parity before decommissioning.

06 · Gotchas

25 real gotchas — root-owned artifacts, ENTRYPOINT clashes, dind DNS/MTU, missing locales, cache permissions — each with the exact symptom, cause, and fix.

See the depth

Sample: the migration risk matrix

One file from the kit, in full — how you score pipelines and order the rollout.

The audit tells you what each pipeline depends on. The matrix turns that into a score and an order. You do not migrate the scariest pipeline first to "get it out of the way" — you migrate the easy ones first to build a repeatable pattern, warm your Docker-executor runners, and earn the team's trust, so that when you reach the hard ones you already know your images, your services:, your cache config, and your rollback drill.

The score maps directly to the signals audit-script.sh finds, so the tool and this rubric agree by construction.

The rubric

Easy — the job is already close to container-native. Pure build/test/lint, tools that can be baked into an image, no host state, no host secrets, no privilege. The only work is picking the right image: and confirming parity.

  • Audit signals: none of the risk signals, or at most host-installed tools you can bake into ci/base or a specialized image.

Moderate — the job leans on the host, but every dependency has a well-known Docker-world replacement. Nothing here requires a privilege or architecture decision; it's mechanical translation you'll repeat across many pipelines.

  • Audit signals: pkg-install (job-time apt-get/pip/apk), host-path (absolute paths / $HOME), ssh-keys, secrets-file, cron.
  • Typical work: move tools into an image; move secrets and keys into masked/protected CI variables (file-type where a file is expected); convert job-to-job hand-offs to artifacts:/cache:; convert host cron to a scheduled pipeline.

Hard — the job needs a real decision: elevated privilege, the Docker daemon, or host services. These aren't harder to type, they're harder to get right and safe, and they often force a design choice (docker-in-docker vs. buildah vs. mounted socket; a services: sidecar vs. an external managed service). Migrate these last, one at a time, with the rollback tag ready.

  • Audit signals: docker-socket, docker-build, systemctl, sudo.
  • Typical work: choose an image-build strategy (../04-pipeline-migration/dind-vs-kaniko-vs-socket.md — never kaniko, it's archived); replace host daemons with GitLab services:; remove sudo by fixing the image and running as the base image's non-root user; decide, deliberately, whether any job truly needs privileged mode.

Scoring rule: the highest-severity signal present wins. One docker.sock reference makes a pipeline hard even if everything else is clean — because that one line is the part that will hurt you.

Worked example matrix

Six realistic pipelines from an infrastructure-heavy estate, scored the way the audit scores them:

PipelineSignals foundScoreEst. effortBlocker / notes
docs-site/.gitlab-ci.ymlnone (node build + lint)Easy~1 hrPoint jobs at node:20-slim, confirm artifact parity. Perfect first migration — do this one to prove the tag-based cutover.
terraform-modules/.gitlab-ci.ymlhost tools (terraform, tflint) on host PATHEasy~2 hrNo host state; just needs a ci/terraform image. Pin provider cache via cache:.
python-api/.gitlab-ci.ymlpip install at job time; $HOME/.cache/pip reusedModerate~3 hrBake deps into an image or use cache: keyed on requirements.txt. No secrets, low risk.
deploy-staging/.gitlab-ci.ymlssh -i ~/.ssh/deploy_key, known_hosts, .env sourcedModerate~1 dayMove key + .env to masked/protected file-type CI variables; seed known_hosts explicitly; load via ssh-agent in before_script. Test against a staging host first.
image-factory/.gitlab-ci.ymldocker build, docker push, /var/run/docker.sock mountedHard~2–3 daysThe big one. Pick docker-in-docker or buildah (see 04-…/dind-vs-kaniko-vs-socket.md); set registry auth per 03-…/registry-auth-guide.md. Do this after the runners and images are proven.
db-migrate/.gitlab-ci.ymlsystemctl start postgresql; sudo; talks to localhost:5432Hard~2–3 daysNo host daemon in a container — replace with a services: [postgres:16] sidecar reached by hostname; drop sudo by fixing the image user. May need a schema-load rework. Migrate last.

Tally for this estate: 2 easy, 2 moderate, 2 hard — a healthy shape. Most real estates skew heavier toward moderate; if most of your pipelines score hard, that's a signal the shell runners were doing a lot of undocumented host work, and you should budget accordingly and lean hard on 06-gotchas/.

Ordering the rollout

Work strictly outward from easy:

  1. One easy pipeline, end to end. Prove the whole loop: Docker-executor runner tag, image pull, cache/artifacts, and — critically — the tag-flip rollback. You're validating the process, not the pipeline.
  2. The rest of the easy tier. Reuse the exact pattern. This is where you shake out locale/tz/PATH surprises cheaply, on jobs that can't cause real damage.
  3. Moderate tier, grouped by replacement type. Do all the "secrets to CI variables" pipelines together, then all the "cache rework" pipelines together — batching the same mechanical change is faster and less error-prone than context-switching.
  4. Hard tier, one at a time, never in parallel. Each hard pipeline gets its own change, its own parity check against the last shell run (timing, artifacts, permissions, exit codes), and its rollback tag kept live until you've seen it succeed on real traffic. If it breaks, flip the tag back and regroup — that reversibility is the entire reason for the tag-based strategy in the README.

Re-score after each tier. Migrating the easy and moderate pipelines often reveals that a "hard" one shares an image or a services: block you've already built — which quietly demotes its effort. The matrix is a living document; update the score and notes as you learn, and let it drive the sequence rather than gut feel.

Feed this straight from audit-script.sh: its SUMMARY already prints each file with a score and its signals, sorted hard-first. Paste that into a table like the one above, add an effort estimate and a blocker note per row, and you have your migration backlog.

Complete Kit
$79 $39.50 one-time

50% launch-sale price · applied automatically at checkout

The full migration playbook — runnable configs + scripts, plus a branded PDF. Single-team license.

  • 6 sections: assess → runner setup → custom images → migrate → cut over → gotchas
  • Runnable: audit scanner, config.toml, register script, Ansible role, Dockerfiles, image-build pipeline
  • 10 complete before/after .gitlab-ci.yml patterns (no elisions)
  • 25 gotchas, each with exact symptom → cause → fix
  • Tag-based gradual cutover + a tested rollback plan
  • Kit ZIP + branded PDF · single-team license
Get the Migration Kit — $39.50

Secure checkout via Stripe · instant download · 14-day refund

Free download · 368-page PDF

Free: the Shell Executor Audit Kit

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • audit-script.sh — scans your .gitlab-ci.yml files for shell-executor dependencies
  • The pipeline audit checklist — know exactly what you're up against before you migrate
  • Plus one practical DevOps email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.

Who built this

Built from a real production migration of an infrastructure-heavy GitLab estate — shell executor to Docker executor with purpose-built images for a Kolla-Ansible / OpenStack toolchain, across pipelines that couldn't afford to break. The gotchas section exists because every one of them was paid for the hard way.

— DevOps AI ToolKit · about

Questions

Which GitLab versions does this target?

GitLab 16.0+ and GitLab Runner 16.0+, which use the authentication-token runner flow. Notes are included where 15.x differs. Everything is standard GitLab CI — no GitLab-version lock-in beyond that.

Self-managed or gitlab.com?

Both. The migration patterns, images, and pipeline configs work the same. The runner-setup section covers self-managed runners in depth; on gitlab.com you can point jobs at your own Docker-executor runners the same way.

What do I actually get?

A ZIP of runnable files (audit scanner, config.toml, register script, Ansible role, Dockerfiles, an image-build pipeline, 10 before/after pattern files) plus an 80-page branded PDF companion. Instant download after checkout.

How do updates work?

Your download link stays live — re-download whenever the kit is updated (e.g. as GitLab Runner config or the build-images story evolves).

What license is this?

Single-team license: use it across your own team and internal infrastructure. Please don't resell or republish the kit.

Refund policy?

If it isn't useful, email james.joyner@devopsaitoolkit.com within 14 days for a full refund.

Does it cover the Kubernetes executor or runner autoscaling?

No — those are deliberately out of scope (autoscaling is mentioned, not documented; the Kubernetes executor is a separate concern). This kit is focused on shell → Docker executor.