diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index dc6fb8f3bac571a88bfd42c31ccf30e7a8ac5c05..fe3854d4f24810ddb1f8c4c44003639390925ab8 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -65,3 +65,28 @@ test-job-alma8:
     - molecule idempotence --scenario-name ${SCENARIO}
     # - molecule verify --scenario-name ${SCENARIO}
     - molecule destroy --scenario-name ${SCENARIO}
+
+test-job-ubuntu2204:
+  stage: test
+  tags:
+    - "shell"
+  variables:
+    SCENARIO: "virtualbox_ubuntu2204"
+  script:
+    # make sure that Ansible Vaults are present and can be decrypted
+    - echo "${VAULT_INSTALL_COMMON}" > ../lza_install_common.pass
+    - export ANSIBLE_VAULT_PASSWORD_FILE=../lza_install_common.pass
+    - rm -rf ../ansible_vaults/
+    - git clone https://gitlab+deploy-token-25:${VAULT_ACCESS_TOKEN}@git.slub-dresden.de/slub-referat-2-3/ansible_vaults.git ../ansible_vaults/; \
+    # run Molecule tests
+    - molecule syntax --scenario-name ${SCENARIO}
+    # We cannot use `molecule lint` anymore because:
+    # - https://github.com/ansible-community/molecule/pull/3802 "Remove lint command"
+    # - https://github.com/ansible-community/molecule/discussions/3825#discussioncomment-4908366
+    - yamllint --strict --format colored ./
+    - ansible-lint --format full --profile production --strict --force-color ./
+    - molecule create --scenario-name ${SCENARIO}
+    - molecule converge --scenario-name ${SCENARIO}
+    - molecule idempotence --scenario-name ${SCENARIO}
+    # - molecule verify --scenario-name ${SCENARIO}
+    - molecule destroy --scenario-name ${SCENARIO}
diff --git a/handlers/main.yml b/handlers/main.yml
index fe7285ec35d8ebc51a66a87af836a265c5bc03f1..f76334e11acd602026e4ceabacc459290f780d7e 100644
--- a/handlers/main.yml
+++ b/handlers/main.yml
@@ -80,3 +80,6 @@
 - name: update package cache    # noqa no-changed-when
   ansible.builtin.package:
     update_cache: true
+
+- name: reboot
+  ansible.builtin.reboot:
diff --git a/molecule/resources/playbooks/prepare.yml b/molecule/resources/playbooks/prepare.yml
index ed672d261bb7247ab77838441478356a9c812c43..37dedc4b70d6a36cf92125888c75b5cb253bae49 100644
--- a/molecule/resources/playbooks/prepare.yml
+++ b/molecule/resources/playbooks/prepare.yml
@@ -8,20 +8,33 @@
         state: latest
         update_cache: true
       become: true
-    - name: add custom repo for SLUB's custom Debian repo
-      ansible.builtin.deb822_repository:
-        architectures: "amd64"
-        components: "main"
-        enabled: true
-        name: "slub"
-        pdiffs: true
-        signed_by: "https://sdvdebianrepo.slub-dresden.de/deb-repository/pub.gpg.key"
-        suites: "{{ ansible_lsb.codename }}"
-        uris: "https://sdvdebianrepo.slub-dresden.de/deb-repository"
-      notify: update apt cache
-      become: true
+    - name: Configure additional repos for Debian-based repos.
+      when: ansible_os_family == "Debian"
+      block:
+        - name: >
+            Set Mapping for Debian- and Ubuntu-Releasenames. This is necessary,
+            because SLUB's Debian repo server doesn't support Ubuntu releases
+            (yet?). Whenever this restriction is removed, then we can remove
+            the mapping as well.
+          ansible.builtin.set_fact:
+            releasenames:
+              jammy: "bookworm"
+              # noble: "?????????"
+        - name: Add custom repo for SLUB's custom Debian repo.
+          ansible.builtin.deb822_repository:
+            architectures: "amd64"
+            components: "main"
+            enabled: true
+            name: "slub"
+            pdiffs: true
+            signed_by: "https://sdvdebianrepo.slub-dresden.de/deb-repository/pub.gpg.key"
+            # suites: "{{ ansible_lsb.codename }}"
+            suites: "{{ ( ansible_distribution == 'Ubuntu' ) | ternary( releasenames[ansible_lsb.codename], ansible_lsb.codename ) }}"
+            uris: "https://sdvdebianrepo.slub-dresden.de/deb-repository"
+          notify: update package cache
+          become: true
   handlers:
-    - name: update apt cache
-      ansible.builtin.apt:
+    - name: update package cache
+      ansible.builtin.package:
         update_cache: true
       become: true
diff --git a/molecule/virtualbox_ubuntu2204/molecule.yml b/molecule/virtualbox_ubuntu2204/molecule.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5cf7f999e5e6eb2c4780f3d2bd5a48cd51864b58
--- /dev/null
+++ b/molecule/virtualbox_ubuntu2204/molecule.yml
@@ -0,0 +1,39 @@
+---
+dependency:
+  name: galaxy
+  enabled: false
+driver:
+  name: vagrant
+platforms:
+  # Check out the documentation at
+  # https://github.com/ansible-community/molecule-vagrant#documentation
+  # for more platform parameters.
+  - name: vm-runner-jammy
+    box: ubuntu/jammy64
+    memory: 1024
+    # List of raw Vagrant `config` options.
+    # provider_raw_config_args:
+    #   - "customize [ 'modifyvm', :id, '--natdnshostresolver1', 'on' ]"
+    # Dictionary of `config` options.
+    config_options:
+      ssh.keep_alive: true
+      ssh.remote_user: "lza"
+provisioner:
+  name: ansible
+  log: true
+  config_options:
+    defaults:
+      # https://stackoverflow.com/questions/57435811/ansible-molecule-pass-multiple-vault-ids
+      # vault_identity_list: "@$HOME/.ansible/roles/lza_install_common.pass, @$HOME/.ansible/roles/passfile_1.pass"
+      vault_identity_list: "../../../lza_install_common.pass"
+      display_skipped_hosts: false
+      display_ok_hosts: false
+  vvv: false
+  playbooks:
+    # create: ../resources/playbooks/create.yml
+    # destroy: ../resources/playbooks/destroy.yml
+    converge: ../resources/playbooks/converge.yml
+    prepare: ../resources/playbooks/prepare.yml
+    verify: ../resources/playbooks/verify.yml
+verifier:
+  name: ansible
diff --git a/tasks/configure_swap.yml b/tasks/configure_swap.yml
index 4ab46dfffeacf34e2ed42a94c3f8039044565c80..87e9d8a4cc90b7c0d6d9ddccbafbf36118fe09f4 100644
--- a/tasks/configure_swap.yml
+++ b/tasks/configure_swap.yml
@@ -6,6 +6,16 @@
       ansible.builtin.package:
         name: "zram-tools"
         state: latest
+    - name: configure zram based swap (Ubuntu)
+      ansible.builtin.package:
+        name: [ "linux-image-generic" ]
+        state: latest
+      when: ansible_distribution == "Ubuntu"
+      notify: reboot
+    - name: >
+        Reboot instantly if linux-modules-extra-*-generic were newly installed.
+        Otherwise, Ubuntu cannot load the zram.ko kernel module.
+      ansible.builtin.meta: flush_handlers
     - name: configure zram
       ansible.builtin.blockinfile:
         path: "/etc/default/zramswap"
diff --git a/tasks/install_packages.yml b/tasks/install_packages.yml
index 557cf5fe702ee083e49f84ca21c60ff80f32b2cc..0e3edb97771dca2466beed6b69588152826a2b76 100644
--- a/tasks/install_packages.yml
+++ b/tasks/install_packages.yml
@@ -73,9 +73,32 @@
   environment:
     NEEDRESTART_MODE: "automatically"
 
-# Installation Debian-spezifische Pakete
+- name: Installation of Debian-specific packages
+  ansible.builtin.apt:
+    name: [
+      'linux-perf',
+    ]
+    state: present
+  environment:
+    NEEDRESTART_MODE: "automatically"
+  when:
+    - ansible_os_family == "Debian"
+    - ansible_distribution == "Debian"
+
+- name: Installation of Ubuntu-specific packages
+  ansible.builtin.apt:
+    name: [
+      'linux-tools-common',
+    ]
+    state: present
+  environment:
+    NEEDRESTART_MODE: "automatically"
+  when:
+    - ansible_os_family == "Debian"
+    - ansible_distribution == "Ubuntu"
+
 # lsb-release (uncodified dependency for open-vm-tools), nfs-common (contains lockd, statd, showmount, nfsstat, gssd, idmapd, mount.nfs), procps (contains tload)
-- name: Installation Debian-spezifische Pakete
+- name: Install packages that are common to all Debian-based distributions.
   ansible.builtin.apt:
     name: [
       'acct',
@@ -89,7 +112,6 @@
       'gpg',
       'iptables-persistent',
       'iptraf',
-      'linux-perf',
       'lsb-release',
       'needrestart',
       'nfs-common',
@@ -99,8 +121,6 @@
       'procps',
       'iputils-tracepath',
       'ttyload',
-      # https://www.pro-linux.de/news/1/26836/debian-10-bleibt-bei-der-migration-zu-usr.html
-      # 'usrmerge',
       'vmtouch',
       'vim'
     ]