Testcontainers for .NET error Auto discovery did not detect a Docker host configuration
Asked Answered
F

1

6

I use Testcontainers.MsSql 3.0.0 for integration tests in asp.net project. Integration tests run successfully in visual studio test runner. But when I run tests in docker desktop version 20.10.7 by docker build command I get error:

Auto discovery did not detect a Docker host configuration Cannot detect the Docker endpoint. Use either the environment variables or the ~/.testcontainers.properties file to customize your configuration

This is container’s create code:

Var dbContainer
                    = new MsSqlBuilder()
                    .WithImage(imageName)
                    .WithCleanUp(true)
                    .Build();

And this is my docker file:

FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build-env

ARG buildVersion

WORKDIR /app
COPY . ./

RUN dotnet restore ./Test.sln

RUN dotnet test ./Test.sln /p:CollectCoverage=true 

RUN dotnet publish ./Test/ -c Release  -o out

FROM mcr.microsoft.com/dotnet/aspnet:7.0

WORKDIR /app
COPY --from=build-env /app/out .

ENV TZ=Asia/Tehran
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN dpkg-reconfigure -f noninteractive tzdata

EXPOSE 80 80/tcp

ENTRYPOINT ["dotnet", "Test.dll"]

I searched on github but the solutions didn't work for me. For example I tried by docker-compose but it didn’t work:

 version: "3"
services:
  docker_compose_test:
    build:
      dockerfile: Dockerfile
      context: .
    entrypoint: dotnet
    command: test
    environment:
      - TESTCONTAINERS_HOST_OVERRIDE=host.docker.internal
    volumes:
      - $PWD:$PWD
      - /var/run/docker.sock:/var/run/docker.sock

This is my complete source code.

Foxtrot answered 17/4, 2023 at 21:5 Comment(0)
B
6

I had the same problem. I hope to give you some info to solve it.

If you try to build the docker image using the command docker build -t my-image-name ., you will notice that the build process fails at dotnet test.

The reason for the failure is that TestContainer is trying to run a second Docker container, but it is unable to communicate with Dockerd.

If you look at some websites (even the TestContainer dind docs), they suggest adding the volume -v /var/run/docker.sock:/var/run/docker.sock, as you found in the docker compose you posted.

Note that this solution only works if you are running dotnet test through a docker run because it is not possible to add an external volume during a docker build.

Same problem if you try to run docker-compose up. You docker-compose has a build section where it says to build a container from the dockerfile you created, and it crashes as described above.

Why does it work when you run tests using the VS testrunner? it works because you testrunner is running dotnet test in an environment where dockerd is already present.

Possible solution: using a multi stage dockefile.

as we can see the problem is the execution of dotnet test during the docker build process. We must execute after it.

A multi stage dockerfile can help us. Take this dockerfile as example:

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS base
WORKDIR /App

COPY . ./
RUN dotnet restore
RUN dotnet build

FROM base as test
CMD [ "dotnet", "test" ]

# multiple stages (like publish and so on)

This dockerfile declares at least 2 stages: base and test.

Note that dotnet test is no longer run during the build process, but as a command whenever you run the container from the test stage.

execute the command:

docker build -t my-image-name --target test . to create an image of your application up to the test stage

now execute the command:

docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock --name my-container-name my-image-name

And Voilà your tests are working and TestContainer is able to run another docker container!

Then you can proceed and build your whole image executing the command:

docker build -t my-image-name .

Docker Compose Solution

A solution for Docker Compose might be as follows:

  1. Create a dockerfile for testing purposes only
  2. Run your containers if and only if the container based on the test dockerfile completes successfully.

Here is an example based on the dockerfile above. My docker-compose.yml will run the container "docker_hello_world" if and only if the container built from my dockerfile (to run the dotnet test) completes successfully.

version: "3.8"
services:
  docker_hello_world:
    image: hello-world
    depends_on:
      docker_compose_test:
        condition: service_completed_successfully
  docker_compose_test:
    build:
      dockerfile: Dockerfile
      context: .
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

At your end you will need

  1. a dockerfile that contains the definition to create an image that can be run with the dotnet test command.
  2. a dockerfile containing the definition to build an image for use in production (without running dotnet test)
  3. a docker-compose.yml where your production container depends on the result of running the container based on the docker image created for testing purposes.

I hope I helped you in some way. let me know if you need more info.

some references:

https://dotnet.testcontainers.org/examples/dind/

https://docs.docker.com/build/building/multi-stage/

https://docs.docker.com/language/java/run-tests/

https://docs.docker.com/compose/startup-order/

Brigid answered 18/4, 2023 at 8:1 Comment(5)
Thank you for taking the time to provide an answer. Your solution was helpful, but it didn't fully solve my problem because I want run this docker file from cicd pipeline.Foxtrot
I also need to integrate it into my CI/CD pipeline. I don't use docker-compose, so my strategy is the same as I described in the answer: create a test-stage image, run tests attaching the socket as a volume, and if the tests pass successfully, proceed to build the final stage of the image.Brigid
The root of the problem is that you cannot create a Docker container (as TestContainer tries to do) during the Docker build process.Brigid
@vahidtajari I edited my answer with an example for docker-composeBrigid
A thing that tripped me up was that my tests were not running as the container's root user, and my user did not have access to /var/run/docker.sock, even after it was mounted. Running an entrypoint script as root in the container, setfacl --modify user:myuser:rw /var/run/docker.sock, gave it the necessary permissions so that docker could be accessed. I then used su-exec to run my tests as the non-root user. I found that executing docker ps in my container gave me better information about connectivity issues than relying on the information coming from the Testcontainer errors.Dalt

© 2022 - 2024 — McMap. All rights reserved.