Skip to content

[Feature]: Gitlab CI Support #12078

Open
Open

Description

@hypery2k

Module

No response

Problem

In many GitLab CI pipelines, integration tests that rely on Testcontainers need a running Docker daemon. The typical workaround is:

  1. Run a docker:dind service in privileged mode
  2. Mount the host Docker socket into the test container
  3. Set DOCKER_HOST=unix:///var/run/docker.sock in the test environment

This approach has several pain points:

Issue Impact
Privileged mode Requiresprivileged: truein the job, which is disallowed in many shared runners for security reasons.
Docker socket exposure Mounting/var/run/docker.sockcan inadvertently grant the test container full control over the host Docker daemon.
Port collisions & networking The test container must be on the same network namespace as thedocker:dindservice, which is fragile and hard to debug.
Resource overhead Each job starts a full DinD daemon, increasing build time and memory usage.
Complex configuration Users must remember to setDOCKER_HOST,DOCKER_TLS_VERIFY, etc., which is error‑prone.

A native GitLab CI services integration would eliminate the need for privileged mode, reduce configuration complexity, and improve security:

  • Security – Avoid exposing the host Docker socket or running privileged containers.
  • Simplicity – A single configuration flag should be sufficient to enable CI‑specific behavior.
  • Performance – Reuse the GitLab CI service container’s Docker daemon instead of launching a new DinD instance per job.
  • Consistency – Tests run in CI will mirror local development environments that use Testcontainers without any special CI configuration.

Solution

Add a new configuration option to the `Testcontainers` Java library (and analogous options for other languages) that allows the user to specify a GitLab CI service name and network alias. Example (Java):
TestcontainersConfiguration.getInstance()
           .withGitLabService("docker:dind", "docker");
Internally, Testcontainers will:

1.  Detect that it is running inside a GitLab CI job (e.g., by checking `CI` environment variable).
2.  Resolve the service container’s IP address via the GitLab CI network (`docker` alias).
3.  Set `DOCKER_HOST=tcp://<service-ip>:2375` (or `2376` if TLS is enabled).
4.  Optionally configure TLS certificates if the service exposes them.

Runtime Behavior

-   No privileged mode – The job can run without `privileged: true`.
-   Automatic network discovery – Testcontainers will query the GitLab CI network for the service alias.
-   TLS support – If the GitLab service exposes TLS, the library can automatically pick up the certificates from known paths (`/etc/docker/certs.d/`).

Fallback

If the CI environment is not detected or the service is missing, Testcontainers will fall back to its normal local Docker daemon strategy, preserving backward compatibility.

Benefit

| Category | Impact |
| --- | --- |
| Security | Positive – reduces privileged execution and socket exposure. |
| Performance | Slightly better – reusing the CI service container avoids launching a separate DinD daemon. |
| Developer Experience | Positive – fewer environment variables, clearer CI configuration. |
| Maintenance | Minimal – only a small API addition and a few environment checks. |
| Compatibility | Backward compatible; old jobs continue to work unchanged. |

Alternatives

  • Priviledge DinD Runner in Kubernetes

Would you like to help contributing this feature?

Yes

Activity

  1. AB-xdev commented on Sep 14, 2026

    @AB-xdev
    Contributor

    Some quick feedback from my side (I will not try to elaborate too deep because this issue looks AI generated) - we are using testcontainers in CI environments for many years now.

    So each CI setup behaves very different when it comes to setting stuff up but they all share on core part: You need to connect to an exposed docker socket.
    The default GitLab DinD documentation is IMHO quite straight forward and worked for us out of the box:
    Add a sidecar container, set some environment variables and that's basically it. Around ~10 lines of total YAML code.

    I also don't see how testcontainers - a java library - can influence a GitLab pipeline in such a way that the required docker setup is always correctly present.

    Also most of the mentioned "problems" are GitLab design problems and unrelated to testcontainers or hallucinated:

    privileged: true in the job, which is disallowed in many shared runners for security reasons

    This is not the case

    Mounting/var/run/docker.sockcan inadvertently grant the test container full control over the host Docker daemon.

    That's a general GitLab (Docker) CI problem

    The test container must be on the same network namespace as thedocker:dindservice, which is fragile and hard to debug.

    GitLab CI ensures this automatically

    Each job starts a full DinD daemon, increasing build time and memory usage.

    1. This is a design problem of your GitLab pipeline.
    2. The overhead is minimal - we notice maybe a few seconds of delay in our pipelines compared to the tests running for minutes.

    Users must remember to setDOCKER_HOST,DOCKER_TLS_VERIFY, etc., which is error‑prone.

    You can't copy paste 3 environment variables?

  2. hypery2k commented on Sep 14, 2026

    @hypery2k
    Author

    the problem is not to paste the env vars here. The problem is that you have to allow privileged containers which exposes security risks because it's a security ant-pattern. GitLab dynamic child pipelines allow you to trigger a downstream pipeline using a configuration file generated at runtime by a job, rather than a static YAML file saved in your repository which could be utilized by testcontainers

  3. AB-xdev commented on Sep 15, 2026

    @AB-xdev
    Contributor

    The problem is that you have to allow privileged containers which exposes security risks because it's a security ant-pattern.

    I'm not sure what you are talking about because my link to the docs clearly show that you do not need a privileged container, when using the "Example using DinD"?

    GitLab dynamic child pipelines allow you to trigger a downstream pipeline using a configuration file generated at runtime by a job, rather than a static YAML file saved in your repository which could be utilized by testcontainers

    You will also have the exact same problem with downstream pipelines because you still require a Docker execution environment/socket.

  4. hypery2k commented on Sep 15, 2026

    @hypery2k
    Author

    Docker-in-Docker must run in privileged mode to work properly. Be aware that privileged mode provides full access to the host environment. For more information, go to the Docker documentation on Runtime Privilege and Linux Capabilities and this issue.

    Within gitlab you need to run build pods privileged:

    config.template.toml:   |
          [[runners]]
            [runners.kubernetes]
              image = "docker:git"
              privileged = true

    But for other CI systems the same apply.
    The --priviledged flag gives all the capabilities to the container and it also lifts all the limitations enforced by the device cgroup controller. In other words, the container can do almost everything that the host, hereby Kubernetes worker node, can do. This flag exists to allow special use-cases, like running Docker-in-Docker: https://safeguard.sh/resources/blog/docker-privileged-mode-risks-alternatives

  5. AB-xdev commented on Sep 15, 2026

    @AB-xdev
    Contributor

    I'm not sure what you are talking about because my link to the docs clearly show that you do not need a privileged container, when using the "Example using DinD"?

    Okay nevermind I was wrong here. You have to configure privileged in the underlying GitLab runner for that solution to work.

    However this still doesn't change the fact that Testcontainers can't change how Docker or the GitLab CI works...

    PS: You don't have lecture me in an AI summary to me how Docker's privileged works - I have been working with Docker for years.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions