private void prune(PruneType pruneType, List<Map.Entry<String, String>> filters) {
        String[] labels = filters
            .stream()
            .filter(it -> "label".equals(it.getKey()))
            .map(Map.Entry::getValue)
            .toArray(String[]::new);
        switch (pruneType) {
            // Docker only prunes stopped containers, so we have to do it manually
            case CONTAINERS:
                List<Container> containers = dockerClient
                    .listContainersCmd()
                    .withFilter("label", Arrays.asList(labels))
                    .withShowAll(true)
                    .exec();

                containers
                    .parallelStream()
                    .forEach(container -> {
                        dockerClient
                            .removeContainerCmd(container.getId())
                            .withForce(true)
                            .withRemoveVolumes(true)
                            .exec();
                    });
                break;
            default:
                dockerClient.pruneCmd(pruneType).withLabelFilter(labels).exec();
                break;
        }
    }
A {@link ResourceReaper} implementation that uses {@link Runtime#addShutdownHook(Thread)}
to cleanup containers.
core/src/main/java/org/testcontainers/utility/JVMHookResourceReaper.java