diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000000000000000000000000000000000000..bae8a2b26aa0214aeea8e77e9fd58b7aabbfb8cd
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,14 @@
+.git/
+misc/
+templates/
+tmp/
+
+.dockerignore
+.gitattributes
+.gitignore
+.gitlab-ci.yml
+.pylintrc
+.yamllint
+Dockerfile.*
+README.md
+tmp/
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
index 526c8a38d4a53c339833267bbf86577f023ec507..857c41acc505c12d76c0cdd0bea2aaa481a6119b 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1 +1,2 @@
-*.sh text eol=lf
\ No newline at end of file
+*.sh text eol=lf
+Dockerfile.* text eol=lf
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index dbe9c82b3610ccd58d1c681848dcd322e500051e..4a484ff563e4785f6d23762b45bf0934583e30fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
-.vscode/
\ No newline at end of file
+.vscode/
+tmp/
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4d2bf985878ee7df0f159df24eb283a43fe54920..4d6bf08c4568b21a25934e3669ee62f95d6b091a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -147,6 +147,16 @@ build_image_remover_image:
       exists:
         - Dockerfile.image-remover
 
+build_benchmark_test_runner_image:
+  extends: .build_docker_image
+  stage: build
+  variables:
+    BUILD_TARGET: "benchmark-test-runner"
+  rules:
+    - if: $CI_COMMIT_BRANCH
+      exists:
+        - Dockerfile.benchmark-test-runner
+
 prepare_example_hived_data_5m_image:
   extends: .prepare_hived_data_5m_image
   stage: example-build
diff --git a/Dockerfile.benchmark-test-runner b/Dockerfile.benchmark-test-runner
new file mode 100644
index 0000000000000000000000000000000000000000..6f56bacc8028465ccdecfc69421d19855bfcc3f2
--- /dev/null
+++ b/Dockerfile.benchmark-test-runner
@@ -0,0 +1,67 @@
+# syntax=docker/dockerfile:1.4
+FROM alpine:3.17.0 as build
+
+COPY <<-EOF /opt/patch.sed
+  s/jtl2junit/m2u/g
+  s/results file/results file (required)/g
+  23 i final Options helpOpt = new Options();
+  23 i helpOpt.addOption("?", "help", false, "");
+  23 i helpOpt.addOption(new Option("i", CMD_OPTION_INPUT, true, ""));
+  23 i helpOpt.addOption(new Option("o", CMD_OPTION_OUTPUT, true, ""));
+  23 i helpOpt.addOption(new Option("t", CMD_OPTION_TESTSUITE_NAME, true, ""));
+  23 i helpOpt.addOption(new Option("f", M2UConstants.JUNIT_FILTER_SWITCH_NAME, true, ""));
+  23 i final CommandLine helpCmd = parser.parse( helpOpt, argv );
+  23 i if (helpCmd.hasOption("help")) {
+  23 i new HelpFormatter().printHelp( APPLICATION_NAME, options );
+  23 i System.exit(0);
+  23 i }
+  72 i options.addOption("?", "help", false, "Show this usage instructions");
+EOF
+
+RUN <<EOF
+  # Install system dependencies
+  apk add --no-cache ca-certificates wget unzip openjdk11-jdk maven git
+
+  # Prepare tools directory
+  mkdir -p /opt/tools
+  cd /opt/tools
+
+  # Install Apache JMeter
+  wget --quiet https://dlcdn.apache.org//jmeter/binaries/apache-jmeter-5.4.3.zip -O jmeter.zip
+  unzip -qq jmeter.zip
+  rm jmeter.zip
+  mv apache-jmeter-5.4.3 jmeter
+  wget --quiet https://jdbc.postgresql.org/download/postgresql-42.3.1.jar -O /opt/tools/jmeter/lib/postgresql-42.3.1.jar
+
+  # Build m2u from source
+  mkdir -p m2u
+  git clone --single-branch --branch master https://github.com/tguzik/m2u.git m2u-source
+  cd m2u-source
+  find -name CommandLineParser.java -exec sed -i -f /opt/patch.sed {} \;
+  mvn
+
+  # Install m2u
+  mv target/m2u.jar ../m2u/m2u.jar
+  cd ../m2u
+  rm -R ../m2u-source
+  echo 'java -jar /opt/tools/m2u/m2u.jar $@' > m2u
+  chmod +x m2u
+EOF
+
+FROM alpine:3.17.0
+
+COPY --from=build /opt/tools /opt/tools
+
+RUN <<EOF
+  # Install system dependencies
+  apk add --no-cache bash ca-certificates openjdk11-jre python3 py3-pip
+
+  # Install Python dependencies
+  pip3 install prettytable
+
+  # Creater symlinks in bin directory
+  ln -s /opt/tools/jmeter/bin/jmeter /usr/bin/jmeter
+  ln -s /opt/tools/m2u/m2u /usr/bin/m2u
+EOF
+
+CMD ["/bin/bash"]
\ No newline at end of file