Speed up GitHub Actions and Act by removing the dep-install steps from your workflows
- Speed up CI (Even more relevant at the Agentic era)
- Provide an environment similar to the default
ubuntu-latest(docker compose,shell aliases, ...) - Debugable / Fast using
dindordood - Fast and light using the
Alpineversions - Easy to extend / Request a specific version
- Easy to revert / Small footprint in the CI workflows
Pull from Docker Hub (docker.io/jclaveau/<image>) — drop one into your workflow as the job
container::
# Example for acceptance tests
jobs:
e2e-front:
runs-on: ubuntu-latest
container: jclaveau/ubuntu-dood-playwright-gyp:latest
steps:
- uses: jclaveau/ci-prebuilds/.github/actions/prepare@v0 # DOCKER_MODE/HOST_ADDRESS defaults + start-dockerd under dind
- uses: actions/checkout@v4
- run: pnpm install --frozen-lockfile
- run: docker compose up -d --wait # no docker mcr.microsoft.com/playwright
- run: pnpm exec playwright test # no `playwright install --with-deps` required
e2e-back:
runs-on: ubuntu-latest
container: jclaveau/ubuntu-dood-pnpm-gyp:latest
steps:
- uses: jclaveau/ci-prebuilds/.github/actions/prepare@v0
- uses: actions/checkout@v4
- run: pnpm install --frozen-lockfile
- run: docker compose up -d --wait
- run: pnpm exec vitestImages are layered — each builds on the previous — and every layer above the base ships in two
flavors, -dood and -dind:
ubuntu-gha-tools GitHub ubuntu-latest mimic (users, env, OS tools; slim — no compiler)
└─ docker (internal) + Docker Engine & Compose
├─ dood shares the host daemon (mounted socket)
└─ dind boots its own inner daemon
then: node ─┬─ pnpm ─────── playwright (slim; each in both -dood and -dind)
└─ pnpm-gyp ─── playwright-gyp (+ node-gyp toolchain, for native addons)
Image names follow <os>-<mode>[-<layer>][-sudoer]. Pick one of each axis:
| Axis | Options | Default if unsure |
|---|---|---|
| OS | ubuntu · alpine |
ubuntu |
| Mode | dood (faster) · dind (isolated) |
dind |
| Layer | none · -node · -pnpm · -pnpm-gyp · -playwright · -playwright-gyp |
your needs |
| Flavor | default (no runtime sudo) · -sudoer |
hardened |
- One exception: Playwright on Alpine is Chromium-only for now (using a --shell-only Chromium).
| Image | What it adds | Docs |
|---|---|---|
ubuntu-gha-tools |
GitHub ubuntu-latest mimic (users, env, OS tools; no compiler) |
README |
ubuntu-dood / ubuntu-dind |
+ Docker Engine & Compose | dood · dind |
…-node |
+ Node, npm (slim — no compiler) | README |
…-pnpm |
+ pnpm | README |
…-pnpm-gyp |
+ node-gyp toolchain (for native addons) | README |
…-playwright |
+ Playwright | README |
…-playwright-gyp |
+ Playwright on the -gyp base |
README |
(The docker layer is an internal, unpublished base — see docker/README.md.)
Every combination is published with a :latest tag plus a version-pinned tag. Examples on the
current chain (Ubuntu 24.04 / Node 22.12 / pnpm 9.15 / Playwright 1.50):
| Image | :latest example |
Version-pinned tag example |
|---|---|---|
jclaveau/ubuntu-gha-tools |
:latest |
:ubuntu24.04 |
jclaveau/ubuntu-dood · jclaveau/ubuntu-dind |
:latest |
:ubuntu24.04 |
jclaveau/ubuntu-dood-node |
:latest |
:ubuntu24.04-node22.12 |
jclaveau/ubuntu-dood-pnpm |
:latest |
:ubuntu24.04-node22.12-pnpm9.15 |
jclaveau/ubuntu-dood-playwright |
:latest |
:ubuntu24.04-node22.12-pnpm9.15-pw1.50 |
jclaveau/ubuntu-dood-playwright-gyp |
:latest |
:ubuntu24.04-node22.12-pnpm9.15-pw1.50-gyp |
ghcr.io/jclaveau/…:sha-<commit>tags also exist but are build intermediates — the consumer contract is Docker Hub:latestand the version-pinned tags above.
- Once every deps are installed you may not require sudo anymore. So sudo is disabled by default
- add
-sudoerto any image to get sudo back - For local
act --binduse on untrusted code, prefer rootless docker
See The last benchmarks.
jobs:
e2e-front:
name: ${{ matrix.mode }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include: # Switch between ci environments to debug or save time
- mode: dood
image: jclaveau/ubuntu-dood-playwright-gyp:latest
options: --volume /var/run/docker.sock:/var/run/docker.sock
# - mode: dind
# image: jclaveau/ubuntu-dind-playwright-gyp:latest
# options: --privileged --env DOCKER_HOST=unix:///var/run/dind.sock
# - mode: vm
# image: "" # empty image → run on the host VM
# options: ""
container:
image: ${{ matrix.image }}
options: ${{ matrix.options }}
steps:
- uses: jclaveau/ci-prebuilds/.github/actions/prepare@v0 # DOCKER_MODE/HOST_ADDRESS defaults + start-dockerd under dind
- uses: actions/checkout@v4
- if: env.DOCKER_MODE == 'vm'
uses: actions/setup-node@v4
- if: env.DOCKER_MODE == 'vm'
uses: pnpm/action-setup@v4
with:
run_install: false
- run: pnpm install --frozen-lockfile
- run: docker compose up -d --wait
- if: env.DOCKER_MODE == 'vm'
name: Install Playwright browsers (vm)
run: pnpm exec playwright install --with-deps
- run: pnpm exec playwright testSee the action. Versioning:
@v0— moving tag, advanced manually on compatible action updates@v0.1.0(immutable) or a commit SHA — full reproducibility@v1will exist once the repo reaches v1
See open issues.
MIT