diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c5d499b321..ed5383ab50 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -2,8 +2,10 @@ stages:
   - build
   - test
   - containers
+  - test-containers
 
 include:
   - 'automation/gitlab-ci/build.yaml'
   - 'automation/gitlab-ci/test.yaml'
   - 'automation/gitlab-ci/containers.yaml'
+  - 'automation/gitlab-ci/test-containers.yaml'
diff --git a/automation/gitlab-ci/test-containers.yaml b/automation/gitlab-ci/test-containers.yaml
new file mode 100644
index 0000000000..5dbf3902ff
--- /dev/null
+++ b/automation/gitlab-ci/test-containers.yaml
@@ -0,0 +1,239 @@
+.testbuild-tmpl: &testbuild
+  stage: test-containers
+  image: registry.gitlab.com/xen-project/xen/${CONTAINER}-test
+  script:
+    - ./automation/scripts/build 2>&1 | tee build.log
+  artifacts:
+    paths:
+      - binaries/
+      - xen-config
+      - '*.log'
+      - '*/*.log'
+    when: always
+  rules: !reference [.container-build-tmpl, rules]
+
+.gcc-tmpl:
+  variables: &gcc
+    CC: gcc
+    CXX: g++
+
+.clang-tmpl:
+  variables: &clang
+    CC: clang
+    CXX: clang++
+    clang: y
+
+.clang-8-tmpl:
+  variables: &clang-8
+    CC: clang-8
+    CXX: clang++-8
+    LD: ld.lld-8
+    clang: y
+
+.x86-64-testbuild-tmpl:
+  <<: *testbuild
+  variables:
+    XEN_TARGET_ARCH: x86_64
+  tags:
+    - x86_64
+
+.x86-64-testbuild:
+  extends: .x86-64-testbuild-tmpl
+  variables:
+    debug: n
+
+.x86-64-testbuild-debug:
+  extends: .x86-64-testbuild-tmpl
+  variables:
+    debug: y
+
+.x86-32-testbuild-tmpl:
+  <<: *testbuild
+  variables:
+    XEN_TARGET_ARCH: x86_32
+  tags:
+    - x86_32
+
+.x86-32-testbuild:
+  extends: .x86-32-testbuild-tmpl
+  variables:
+    debug: n
+
+.x86-32-testbuild-debug:
+  extends: .x86-32-testbuild-tmpl
+  variables:
+    debug: y
+
+.gcc-x86-64-testbuild:
+  extends: .x86-64-testbuild
+  variables:
+    <<: *gcc
+
+.gcc-x86-64-testbuild-debug:
+  extends: .x86-64-testbuild-debug
+  variables:
+    <<: *gcc
+
+.gcc-x86-32-testbuild:
+  extends: .x86-32-testbuild
+  variables:
+    <<: *gcc
+
+.gcc-x86-32-testbuild-debug:
+  extends: .x86-32-testbuild-debug
+  variables:
+    <<: *gcc
+
+.clang-x86-64-testbuild:
+  extends: .x86-64-testbuild
+  variables:
+    <<: *clang
+
+.clang-x86-64-testbuild-debug:
+  extends: .x86-64-testbuild-debug
+  variables:
+    <<: *clang
+
+.clang-8-x86-64-testbuild:
+  extends: .x86-64-testbuild
+  variables:
+    <<: *clang-8
+
+.clang-8-x86-64-testbuild-debug:
+  extends: .x86-64-testbuild-debug
+  variables:
+    <<: *clang-8
+
+.clang-x86-32-testbuild:
+  extends: .x86-32-testbuild
+  variables:
+    <<: *clang
+
+.clang-x86-32-testbuild-debug:
+  extends: .x86-32-testbuild-debug
+  variables:
+    <<: *clang
+
+.arm32-cross-testbuild-tmpl:
+  <<: *testbuild
+  variables:
+    XEN_TARGET_ARCH: arm32
+  tags:
+    - x86_64
+
+.arm32-cross-testbuild:
+  extends: .arm32-cross-testbuild-tmpl
+  variables:
+    debug: n
+
+.arm32-cross-testbuild-debug:
+  extends: .arm32-cross-testbuild-tmpl
+  variables:
+    debug: y
+
+.gcc-arm32-cross-testbuild:
+  extends: .arm32-cross-testbuild
+  variables:
+    <<: *gcc
+
+.gcc-arm32-cross-testbuild-debug:
+  extends: .arm32-cross-testbuild-debug
+  variables:
+    <<: *gcc
+
+.arm64-testbuild-tmpl:
+  <<: *testbuild
+  variables:
+    XEN_TARGET_ARCH: arm64
+  tags:
+    - arm64
+
+.arm64-testbuild:
+  extends: .arm64-testbuild-tmpl
+  variables:
+    debug: n
+
+.arm64-testbuild-debug:
+  extends: .arm64-testbuild-tmpl
+  variables:
+    debug: y
+
+.gcc-arm64-testbuild:
+  extends: .arm64-testbuild
+  variables:
+    <<: *gcc
+
+.gcc-arm64-testbuild-debug:
+  extends: .arm64-testbuild-debug
+  variables:
+    <<: *gcc
+
+.riscv64-cross-testbuild-tmpl:
+  <<: *testbuild
+  variables:
+    XEN_TARGET_ARCH: riscv64
+  tags:
+    - x86_64
+
+.riscv64-cross-testbuild:
+  extends: .riscv64-cross-testbuild-tmpl
+  variables:
+    debug: n
+
+.riscv64-cross-testbuild-debug:
+  extends: .riscv64-cross-testbuild-tmpl
+  variables:
+    debug: y
+
+.gcc-riscv64-cross-testbuild:
+  extends: .riscv64-cross-testbuild
+  variables:
+    <<: *gcc
+
+.gcc-riscv64-cross-testbuild-debug:
+  extends: .riscv64-cross-testbuild-debug
+  variables:
+    <<: *gcc
+
+# Jobs below this line
+
+.container-debian-unstable-testtmpl:
+  variables:
+    CONTAINER: debian:unstable
+    BUILD_CONTAINER: debian/unstable
+  needs:
+    - debian-unstable-container
+
+test-debian-unstable-clang:
+  extends:
+    - .clang-x86-64-testbuild
+    - .container-debian-unstable-testtmpl
+
+test-debian-unstable-clang-debug:
+  extends:
+    - .clang-x86-64-testbuild-debug
+    - .container-debian-unstable-testtmpl
+
+test-debian-unstable-gcc:
+  extends:
+    - .gcc-x86-64-testbuild
+    - .container-debian-unstable-testtmpl
+
+test-debian-unstable-gcc-debug:
+  extends:
+    - .gcc-x86-64-testbuild-debug
+    - .container-debian-unstable-testtmpl
+
+test-debian-unstable-gcc-randconfig:
+  extends:
+    - .gcc-x86-64-testbuild
+    - .container-debian-unstable-testtmpl
+  variables:
+    RANDCONFIG: y
+
+test-debian-unstable-gcc-debug-randconfig:
+  extends:
+    - .gcc-x86-64-testbuild-debug
+    - .container-debian-unstable-testtmpl
+  variables:
+    RANDCONFIG: y
