I've just spent a few hours trying to figure out what's wrong with the cache in my GitLab CI job, running locally.

The short answer is: nothing. There is a difference between running a CI job via git push to GitLab, and running it locally with gitlab-runner exec.

When run locally with exec, the cache implementation isn't being mounted to my container as /cache.

You can work around this by passing this as an extra command-line argument:

sudo gitlab-runner exec docker --docker-volumes "/var/cache:/cache" test

This does mean that you now have two caches: whatever the GitLab CI pipeline uses when it normally runs, and the one you use manually on the command line.