diff --git a/lib/util/exec/common.ts b/lib/util/exec/common.ts
index 3c8464e14d36543e614247e92b9ac35bcd8944c8..c229cf62dde44b9900c7ee2c6a438c4c20655ef2 100644
--- a/lib/util/exec/common.ts
+++ b/lib/util/exec/common.ts
@@ -20,7 +20,10 @@ export interface ExecConfig {
 }
 
 export type VolumesPair = [string, string];
-export type VolumeOption = string | VolumesPair | null | undefined;
+export type VolumeOption = Opt<string | VolumesPair>;
+
+export type DockerExtraCommand = Opt<string>;
+export type DockerExtraCommands = Opt<DockerExtraCommand[]>;
 
 export interface DockerOptions {
   image: string;
@@ -28,6 +31,8 @@ export interface DockerOptions {
   volumes?: Opt<VolumeOption[]>;
   envVars?: Opt<Opt<string>[]>;
   cwd?: Opt<string>;
+  preCommands?: DockerExtraCommands;
+  postCommands?: DockerExtraCommands;
 }
 
 export interface RawExecOptions extends ChildProcessExecOptions {
diff --git a/lib/util/exec/docker/index.ts b/lib/util/exec/docker/index.ts
index 2aa4b5315586b8b445f908be789f356b8d041233..94e4d9f5e9daf90455345b18c8433501617b4376 100644
--- a/lib/util/exec/docker/index.ts
+++ b/lib/util/exec/docker/index.ts
@@ -3,6 +3,7 @@ import {
   VolumesPair,
   DockerOptions,
   ExecConfig,
+  DockerExtraCommands,
   rawExec,
 } from '../common';
 import { logger } from '../../../logger';
@@ -56,12 +57,24 @@ function prepareVolumes(volumes: VolumeOption[] = []): string[] {
   });
 }
 
+function prepareCommands(commands: DockerExtraCommands = []): string[] {
+  return commands.filter(command => command && typeof command === 'string');
+}
+
 export async function generateDockerCommand(
-  cmd: string,
+  commands: string[],
   options: DockerOptions,
   config: ExecConfig
 ): Promise<string> {
-  const { image, tag, envVars, cwd, volumes = [] } = options;
+  const {
+    image,
+    tag,
+    envVars,
+    cwd,
+    volumes = [],
+    preCommands,
+    postCommands,
+  } = options;
   const { localDir, cacheDir, dockerUser } = config;
 
   const result = ['docker run --rm'];
@@ -83,7 +96,12 @@ export async function generateDockerCommand(
   await prefetchDockerImage(taggedImage);
   result.push(taggedImage);
 
-  result.push(cmd);
+  const bashCommand = [
+    ...prepareCommands(preCommands),
+    ...commands,
+    ...prepareCommands(postCommands),
+  ].join(' && ');
+  result.push(`bash -l -c "${bashCommand.replace(/"/g, '\\"')}"`);
 
   return result.join(' ');
 }
diff --git a/lib/util/exec/index.ts b/lib/util/exec/index.ts
index 578e4a326d5ed8b512bdbe818efefae449e0f02d..a47b6e93239d09bd3bb1c68e5d02c2bce3c7bd3a 100644
--- a/lib/util/exec/index.ts
+++ b/lib/util/exec/index.ts
@@ -103,10 +103,8 @@ export async function exec(
       envVars: dockerEnvVars(extraEnv, childEnv),
     };
 
-    let dockerCommand = commands.join(' && ');
-    dockerCommand = `bash -l -c "${dockerCommand.replace(/"/g, '\\"')}"`;
-    dockerCommand = await generateDockerCommand(
-      dockerCommand,
+    const dockerCommand = await generateDockerCommand(
+      commands,
       dockerOptions,
       execConfig
     );
diff --git a/test/util/exec.spec.ts b/test/util/exec.spec.ts
index e182903c8da5b060fa3002a0e676412c57d29c96..453f819358e6de3df50f68c301e88901d7c2cd81 100644
--- a/test/util/exec.spec.ts
+++ b/test/util/exec.spec.ts
@@ -295,7 +295,7 @@ describe(`Child process execution wrapper`, () => {
         },
         processEnv,
         inCmd,
-        inOpts: { docker: { image } },
+        inOpts: { docker },
         outCmd: [
           dockerPullCmd,
           `docker run --rm --user=foobar ${defaultVolumes} -w "${cwd}" ${image} bash -l -c "${inCmd}"`,
@@ -303,6 +303,30 @@ describe(`Child process execution wrapper`, () => {
         outOpts: [dockerPullOpts, { cwd, encoding, env: envMock.basic }],
       },
     ],
+
+    [
+      'Docker extra commands',
+      {
+        execConfig: {
+          ...execConfig,
+          binarySource: BinarySource.Docker,
+        },
+        processEnv,
+        inCmd,
+        inOpts: {
+          docker: {
+            image,
+            preCommands: ['preCommand1', 'preCommand2', null],
+            postCommands: ['postCommand1', undefined, 'postCommand2'],
+          },
+        },
+        outCmd: [
+          dockerPullCmd,
+          `docker run --rm ${defaultVolumes} -w "${cwd}" ${image} bash -l -c "preCommand1 && preCommand2 && ${inCmd} && postCommand1 && postCommand2"`,
+        ],
+        outOpts: [dockerPullOpts, { cwd, encoding, env: envMock.basic }],
+      },
+    ],
   ];
 
   test.each(testInputs)('%s', async (_msg, testOpts) => {