diff --git a/lib/workers/branch/lock-files/__snapshots__/yarn.spec.ts.snap b/lib/manager/npm/post-update/__snapshots__/yarn.spec.ts.snap
similarity index 72%
rename from lib/workers/branch/lock-files/__snapshots__/yarn.spec.ts.snap
rename to lib/manager/npm/post-update/__snapshots__/yarn.spec.ts.snap
index 34243ee43e4674850c8a5ec56bf3d94cdfd6ea53..54ef2abfc64f06111e31469c33894c0db673e4d0 100644
--- a/lib/workers/branch/lock-files/__snapshots__/yarn.spec.ts.snap
+++ b/lib/manager/npm/post-update/__snapshots__/yarn.spec.ts.snap
@@ -1,6 +1,6 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
-exports[`workers/branch/lock-files/yarn catches errors 1`] = `
+exports[`manager/npm/post-update/yarn catches errors 1`] = `
 Array [
   Object {
     "cmd": "yarn install --ignore-scripts --ignore-engines --ignore-platform",
@@ -22,27 +22,10 @@ Array [
 ]
 `;
 
-exports[`workers/branch/lock-files/yarn docker using yarn v1.0.0 1`] = `
+exports[`manager/npm/post-update/yarn generates lock files using yarn v1.22.0 1`] = `
 Array [
   Object {
-    "cmd": "docker run --rm -v \\"some-dir\\":\\"some-dir\\" -v \\"dummy/dir\\":\\"dummy/dir\\" -e NPM_CONFIG_CACHE -e npm_config_store -w \\"some-dir\\" renovate/yarn yarn install --ignore-scripts --ignore-engines --ignore-platform",
-    "options": Object {
-      "cwd": "some-dir",
-      "encoding": "utf-8",
-      "env": Object {
-        "HOME": "/home/user",
-        "HTTPS_PROXY": "https://example.com",
-        "HTTP_PROXY": "http://example.com",
-        "LANG": "en_US.UTF-8",
-        "LC_ALL": "en_US",
-        "NO_PROXY": "localhost",
-        "PATH": "/tmp/path",
-      },
-      "timeout": 900000,
-    },
-  },
-  Object {
-    "cmd": "docker run --rm -v \\"some-dir\\":\\"some-dir\\" -v \\"dummy/dir\\":\\"dummy/dir\\" -e NPM_CONFIG_CACHE -e npm_config_store -w \\"some-dir\\" renovate/yarn yarn upgrade some-dep --ignore-scripts --ignore-engines --ignore-platform",
+    "cmd": "yarn install --ignore-scripts --ignore-engines --ignore-platform",
     "options": Object {
       "cwd": "some-dir",
       "encoding": "utf-8",
@@ -58,13 +41,8 @@ Array [
       "timeout": 900000,
     },
   },
-]
-`;
-
-exports[`workers/branch/lock-files/yarn finds yarn v1.0.0 globally 1`] = `
-Array [
   Object {
-    "cmd": "yarn install --ignore-scripts --ignore-engines --ignore-platform",
+    "cmd": "npx yarn-deduplicate --strategy fewer",
     "options": Object {
       "cwd": "some-dir",
       "encoding": "utf-8",
@@ -80,11 +58,6 @@ Array [
       "timeout": 900000,
     },
   },
-]
-`;
-
-exports[`workers/branch/lock-files/yarn generates lock files using yarn v1.0.0 1`] = `
-Array [
   Object {
     "cmd": "yarn install --ignore-scripts --ignore-engines --ignore-platform",
     "options": Object {
@@ -103,7 +76,7 @@ Array [
     },
   },
   Object {
-    "cmd": "npx yarn-deduplicate --strategy fewer && yarn",
+    "cmd": "npx yarn-deduplicate --strategy highest",
     "options": Object {
       "cwd": "some-dir",
       "encoding": "utf-8",
@@ -120,7 +93,7 @@ Array [
     },
   },
   Object {
-    "cmd": "npx yarn-deduplicate --strategy highest && yarn",
+    "cmd": "yarn install --ignore-scripts --ignore-engines --ignore-platform",
     "options": Object {
       "cwd": "some-dir",
       "encoding": "utf-8",
@@ -139,7 +112,7 @@ Array [
 ]
 `;
 
-exports[`workers/branch/lock-files/yarn performs lock file updates using yarn v1.0.0 1`] = `
+exports[`manager/npm/post-update/yarn performs lock file updates using yarn v1.22.0 1`] = `
 Array [
   Object {
     "cmd": "yarn install --ignore-scripts --ignore-engines --ignore-platform",
diff --git a/lib/workers/branch/lock-files/yarn.spec.ts b/lib/manager/npm/post-update/yarn.spec.ts
similarity index 64%
rename from lib/workers/branch/lock-files/yarn.spec.ts
rename to lib/manager/npm/post-update/yarn.spec.ts
index 23055eb40de05f56cd281b0151077956e4dc5808..9cf127d643733140938068e0fb571a784659c3f8 100644
--- a/lib/workers/branch/lock-files/yarn.spec.ts
+++ b/lib/manager/npm/post-update/yarn.spec.ts
@@ -2,9 +2,8 @@ import { exec as _exec } from 'child_process';
 import _fs from 'fs-extra';
 import { ExecSnapshots, envMock, mockExecAll } from '../../../../test/execUtil';
 import { getName, mocked } from '../../../../test/util';
-import * as _yarnHelper from '../../../manager/npm/post-update/yarn';
-import { BinarySource } from '../../../util/exec/common';
 import * as _env from '../../../util/exec/env';
+import * as _yarnHelper from './yarn';
 
 jest.mock('fs-extra');
 jest.mock('child_process');
@@ -15,6 +14,8 @@ const env = mocked(_env);
 const fs = mocked(_fs);
 const yarnHelper = mocked(_yarnHelper);
 
+delete process.env.NPM_CONFIG_CACHE;
+
 // TODO: figure out snapshot similarity for each CI platform
 const fixSnapshots = (snapshots: ExecSnapshots): ExecSnapshots =>
   snapshots.map((snapshot) => ({
@@ -27,7 +28,7 @@ describe(getName(__filename), () => {
     jest.resetAllMocks();
     env.getChildProcessEnv.mockReturnValue(envMock.basic);
   });
-  it.each([['1.0.0']])(
+  it.each([['1.22.0']])(
     'generates lock files using yarn v%s',
     async (yarnVersion) => {
       const execSnapshots = mockExecAll(exec, {
@@ -36,6 +37,7 @@ describe(getName(__filename), () => {
       });
       fs.readFile = jest.fn(() => 'package-lock-contents') as never;
       const config = {
+        dockerMapDotfiles: true,
         postUpdateOptions: ['yarnDedupeFewer', 'yarnDedupeHighest'],
       };
       const res = await yarnHelper.generateLockFile('some-dir', {}, config);
@@ -44,7 +46,7 @@ describe(getName(__filename), () => {
       expect(fixSnapshots(execSnapshots)).toMatchSnapshot();
     }
   );
-  it.each([['1.0.0']])(
+  it.each([['1.22.0']])(
     'performs lock file updates using yarn v%s',
     async (yarnVersion) => {
       const execSnapshots = mockExecAll(exec, {
@@ -54,30 +56,15 @@ describe(getName(__filename), () => {
 
       fs.readFile = jest.fn(() => 'package-lock-contents') as never;
       const res = await yarnHelper.generateLockFile('some-dir', {}, {}, [
-        { depName: 'some-dep', isLockfileUpdate: true },
+        {
+          depName: 'some-dep',
+          isLockfileUpdate: true,
+        },
       ]);
       expect(res.lockFile).toEqual('package-lock-contents');
       expect(fixSnapshots(execSnapshots)).toMatchSnapshot();
     }
   );
-  it.each([['1.0.0']])('docker using yarn v%s', async (yarnVersion) => {
-    const execSnapshots = mockExecAll(exec, {
-      stdout: yarnVersion,
-      stderr: '',
-    });
-
-    fs.readFile = jest.fn(() => 'package-lock-contents') as never;
-    const config = {
-      upgrades: [{}],
-      binarySource: BinarySource.Docker,
-      cacheDir: 'dummy/dir',
-    };
-    const res = await yarnHelper.generateLockFile('some-dir', {}, config, [
-      { depName: 'some-dep', isLockfileUpdate: true },
-    ]);
-    expect(res.lockFile).toEqual('package-lock-contents');
-    expect(fixSnapshots(execSnapshots)).toMatchSnapshot();
-  });
   it('catches errors', async () => {
     const execSnapshots = mockExecAll(exec, {
       stdout: '1.9.4',
@@ -92,17 +79,4 @@ describe(getName(__filename), () => {
     expect(res.lockFile).not.toBeDefined();
     expect(fixSnapshots(execSnapshots)).toMatchSnapshot();
   });
-
-  it.each([['1.0.0']])('finds yarn v%s globally', async (yarnVersion) => {
-    const execSnapshots = mockExecAll(exec, {
-      stdout: yarnVersion,
-      stderr: '',
-    });
-
-    fs.readFile = jest.fn(() => 'package-lock-contents') as never;
-    const res = await yarnHelper.generateLockFile('some-dir');
-    expect(fs.readFile).toHaveBeenCalledTimes(1);
-    expect(res.lockFile).toEqual('package-lock-contents');
-    expect(fixSnapshots(execSnapshots)).toMatchSnapshot();
-  });
 });
diff --git a/lib/manager/npm/post-update/yarn.ts b/lib/manager/npm/post-update/yarn.ts
index 036b8049ee0fade8098c2e84520493c7e9da35a8..04129551b419efe8ee6efb641ee6f29ac009c5ad 100644
--- a/lib/manager/npm/post-update/yarn.ts
+++ b/lib/manager/npm/post-update/yarn.ts
@@ -3,8 +3,7 @@ import { join } from 'upath';
 import { SYSTEM_INSUFFICIENT_DISK_SPACE } from '../../../constants/error-messages';
 import { DatasourceError } from '../../../datasource';
 import { logger } from '../../../logger';
-import { exec } from '../../../util/exec';
-import { BinarySource } from '../../../util/exec/common';
+import { ExecOptions, exec } from '../../../util/exec';
 import { PostUpdateConfig, Upgrade } from '../../common';
 
 export interface GenerateLockFileResult {
@@ -21,101 +20,68 @@ export async function generateLockFile(
 ): Promise<GenerateLockFileResult> {
   logger.debug(`Spawning yarn install to create ${cwd}/yarn.lock`);
   let lockFile = null;
-  let stdout = '';
-  let stderr = '';
-  let cmd = 'yarn';
   try {
-    if (config.binarySource === BinarySource.Docker) {
-      logger.debug('Running yarn via docker');
-      cmd = `docker run --rm `;
-      // istanbul ignore if
-      if (config.dockerUser) {
-        cmd += `--user=${config.dockerUser} `;
-      }
-      const volumes = [cwd];
-      if (config.cacheDir) {
-        volumes.push(config.cacheDir);
-      }
-      cmd += volumes.map((v) => `-v "${v}":"${v}" `).join('');
-      // istanbul ignore if
-      if (config.dockerMapDotfiles) {
-        const homeDir =
-          process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
-        const homeNpmrc = join(homeDir, '.npmrc');
-        cmd += `-v ${homeNpmrc}:/home/ubuntu/.npmrc `;
-      }
-      const envVars = ['NPM_CONFIG_CACHE', 'npm_config_store'];
-      cmd += envVars.map((e) => `-e ${e} `).join('');
-      cmd += `-w "${cwd}" `;
-      cmd += `renovate/yarn yarn`;
+    const preCommands = ['npm i -g yarn'];
+    const commands = [];
+    let cmdOptions = '';
+    if (global.trustLevel !== 'high' || config.ignoreScripts) {
+      cmdOptions = '--ignore-scripts --ignore-engines --ignore-platform';
     }
-
-    let cmdExtras = '';
-    const cmdEnv = { ...env };
-    cmdExtras += ' --ignore-scripts';
-    cmdExtras += ' --ignore-engines';
-    cmdExtras += ' --ignore-platform';
-    const installCmd = cmd + ' install' + cmdExtras;
-    // TODO: Switch to native util.promisify once using only node 8
-    await exec(installCmd, {
+    const execOptions: ExecOptions = {
       cwd,
-      env: cmdEnv,
-    });
+      extraEnv: {
+        NPM_CONFIG_CACHE: env?.NPM_CONFIG_CACHE,
+        npm_config_store: env?.npm_config_store,
+      },
+      docker: {
+        image: 'renovate/node',
+        preCommands,
+      },
+    };
+    if (config.dockerMapDotfiles) {
+      const homeDir =
+        process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE;
+      const homeNpmrc = join(homeDir, '.npmrc');
+      execOptions.docker.volumes = [[homeNpmrc, '/home/ubuntu/.npmrc']];
+    }
+
+    // This command updates the lock file based on package.json
+    commands.push(`yarn install ${cmdOptions}`.trim());
+
+    // rangeStrategy = update-lockfile
     const lockUpdates = upgrades
       .filter((upgrade) => upgrade.isLockfileUpdate)
       .map((upgrade) => upgrade.depName);
     if (lockUpdates.length) {
       logger.debug('Performing lockfileUpdate (yarn)');
-      const updateCmd =
-        cmd +
-        ' upgrade' +
-        lockUpdates.map((depName) => ` ${depName}`).join('') +
-        cmdExtras;
-      const updateRes = await exec(updateCmd, {
-        cwd,
-        env,
-      });
-      // istanbul ignore next
-      stdout += updateRes.stdout || '';
-      stderr += updateRes.stderr || '';
+      commands.push(
+        `yarn upgrade ${lockUpdates.join(' ')} ${cmdOptions}`.trim()
+      );
     }
 
-    if (
-      config.postUpdateOptions &&
-      config.postUpdateOptions.includes('yarnDedupeFewer')
-    ) {
+    // postUpdateOptions
+    if (config.postUpdateOptions?.includes('yarnDedupeFewer')) {
       logger.debug('Performing yarn dedupe fewer');
-      const dedupeCommand = 'npx yarn-deduplicate --strategy fewer && yarn';
-      const dedupeRes = await exec(dedupeCommand, {
-        cwd,
-        env,
-      });
-      // istanbul ignore next
-      stdout += dedupeRes.stdout || '';
-      stderr += dedupeRes.stderr || '';
+      commands.push('npx yarn-deduplicate --strategy fewer');
+      // Run yarn again in case any changes are necessary
+      commands.push(`yarn install ${cmdOptions}`.trim());
     }
-    if (
-      config.postUpdateOptions &&
-      config.postUpdateOptions.includes('yarnDedupeHighest')
-    ) {
+    if (config.postUpdateOptions?.includes('yarnDedupeHighest')) {
       logger.debug('Performing yarn dedupe highest');
-      const dedupeCommand = 'npx yarn-deduplicate --strategy highest && yarn';
-      const dedupeRes = await exec(dedupeCommand, {
-        cwd,
-        env,
-      });
-      // istanbul ignore next
-      stdout += dedupeRes.stdout || '';
-      stderr += dedupeRes.stderr || '';
+      commands.push('npx yarn-deduplicate --strategy highest');
+      // Run yarn again in case any changes are necessary
+      commands.push(`yarn install ${cmdOptions}`.trim());
     }
+
+    // Run the commands
+    await exec(commands, execOptions);
+
+    // Read the result
     lockFile = await readFile(join(cwd, 'yarn.lock'), 'utf8');
   } catch (err) /* istanbul ignore next */ {
     logger.debug(
       {
-        cmd,
         err,
-        stdout,
-        stderr,
         type: 'yarn',
       },
       'lock file error'