diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..29d9c03897bae3bdf09cdbfd85052e6b582cc0a4
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,73 @@
+stages:          # List of stages for jobs, and their order of execution
+  - build
+  - test
+  - packaging
+
+variables:
+  EXLIBRIS_SDK_DIR: "/exlibris"
+  ROSETTASDK: "${EXLIBRIS_SDK_DIR}/7.3/lib/"
+  IMAGE_TARGET: "$CI_REGISTRY_IMAGE/bullseye_subapp"
+  FF_USE_FASTZIP: "true"
+  # These can be specified per job or per pipeline
+  ARTIFACT_COMPRESSION_LEVEL: "fast"
+  CACHE_COMPRESSION_LEVEL: "fast"
+#  CI_DEBUG_TRACE: "true"
+
+default:
+  image:
+    # use this image for all later stages that happen after the build stage
+    name: "${IMAGE_TARGET}:latest"
+
+before_script:    # These steps are run before EACH job.
+  - export ROSETTASDK="${ROSETTASDK}"
+
+build-env-job:       # This job runs in the build stage, which runs first.
+  stage: build
+  timeout: 30m
+  tags:
+    - "docker"
+  image:
+    # Use Kaniko base image to build a Docker image to use as the base image for later jobs.
+    name: gcr.io/kaniko-project/executor:debug
+    entrypoint: [""]
+  # Do not run the before_script tasks here, they wouldn't be included in the Docker image. Instead, provide an empty list of tasks.
+  before_script: []
+  # docu: https://docs.gitlab.com/ee/ci/docker/using_kaniko.html, this is basically copy-pasted from there
+  script:
+    - mkdir -p /kaniko/.docker
+    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"auth\":\"$(printf "%s:%s" "$CI_REGISTRY_USER" "$CI_REGISTRY_PASSWORD" | base64 | tr -d '\n')\"},\"$(printf "%s" "$CI_DEPENDENCY_PROXY_SERVER" | cut -d':' -f1)\":{\"auth\":\"$(printf "%s:%s" "$CI_DEPENDENCY_PROXY_USER" "$CI_DEPENDENCY_PROXY_PASSWORD" | base64 | tr -d '\n')\"}}}" > /kaniko/.docker/config.json
+    # In this task, Kaniko executor is called to build the Image based on the Dockerfile provided with "--dockerfile".
+    - echo "CI_PROJECT_DIR=${CI_PROJECT_DIR}"
+    - >-
+      /kaniko/executor
+      --context "${CI_PROJECT_DIR}"
+      --dockerfile "${CI_PROJECT_DIR}/gitlab-ci/Dockerfile"
+      --destination "${IMAGE_TARGET}:latest"
+      --build-arg "GITDIR=${CI_PROJECT_DIR}"
+      --cache=true
+      --cache-repo=${CI_REGISTRY_IMAGE}
+      --cache-copy-layers=true
+      --snapshotMode=redo
+      --use-new-run
+      --ignore-var-run
+
+test-job:
+  stage: test
+  timeout: 3h
+  tags:
+    - "docker"
+  script:
+    - ls -lha /exlibris/
+    - ROSETTASDK=$ROSETTASDK make -e check_prerequisites
+    - ROSETTASDK=$ROSETTASDK make -e test
+
+packaging-job:
+  stage: packaging
+  timeout: 3h
+  tags:
+    - "docker"
+  script:
+    - ROSETTASDK=$ROSETTASDK make -e
+  artifacts:
+    paths:
+      - ./*.jar
diff --git a/gitlab-ci/Dockerfile b/gitlab-ci/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..71b05e811b75fd6b0a41d6b5fd5bf73889a62cc1
--- /dev/null
+++ b/gitlab-ci/Dockerfile
@@ -0,0 +1,26 @@
+FROM git.slub-dresden.de/debian-packaging/dependency_proxy/containers/debian:bullseye-slim
+
+ARG GITDIR
+ENV DEBIAN_FRONTEND=noninteractive
+ENV EXLIBRIS_REPO=https://github.com/ExLibrisGroup/Rosetta.dps-sdk-projects.git
+ENV EXLIBRIS_REPODIR=Rosetta.dps-sdk-projects
+ENV EXLIBRIS_PATH=/exlibris
+
+RUN apt-get update; \
+    apt-get install -y --no-install-recommends gnupg wget; \
+    wget -O - http://sdvdebianrepo.slub-dresden.de/deb-repository/pub.gpg.key | apt-key add - ; \
+    echo "deb http://sdvdebianrepo.slub-dresden.de/deb-repository bullseye main" > /etc/apt/sources.list.d/slub.list;
+
+RUN apt-get update; \
+    apt-get -y upgrade; \
+    apt-get install -y \
+      apt-file \
+      apt-utils \
+      make \
+      openjdk-17-jdk \
+      junit4 \
+      git \
+    ;
+RUN apt-file update;
+RUN git clone https://github.com/ExLibrisGroup/Rosetta.dps-sdk-projects.git
+RUN ln -s ${EXLIBRIS_REPODIR} ${EXLIBRIS_PATH}