Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Visual Studio can't start containerized ASP.NET Core if Docker HealthChecks present whilst debugging #446

Open
zharchimage opened this issue Sep 8, 2024 · 5 comments

Comments

@zharchimage
Copy link

zharchimage commented Sep 8, 2024

I'm building 2 ASP.NET Core Web API services containerized with Docker, WebApplication1 and WebApplication2. WebApplication2 depends on WebApplication1 that is why in WebApplication1, I have an endpoint exposed for the HealthCheck that docker compose will implement for WebApplication1:

using System.Net;   
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();

var app = builder.Build();
app.UseRouting();

var containerInfo = app.MapGroup("/health1");
containerInfo.MapGet("/", (HttpContext context) =>
{
    return HttpStatusCode.OK;
});

app.UseAuthorization();
app.MapControllers();
app.Run();

With Dockerfile

 # This stage is used when running from VS in fast mode (Default for Debug configuration)
FROM mcr.microsoft.com/dotnet/aspnet:9.0-preview AS base
USER app
WORKDIR /app
EXPOSE 8080

USER root
RUN apt-get update && apt-get install -y curl
USER app

# This stage is used to build the service project
FROM mcr.microsoft.com/dotnet/sdk:9.0-preview AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["WebApplication1.csproj", "."]
RUN dotnet restore "./WebApplication1.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "./WebApplication1.csproj" -c $BUILD_CONFIGURATION -o /app/build

# This stage is used to publish the service project to be copied to the final stage
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./WebApplication1.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
FROM base AS final
WORKDIR /app

COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication1.dll"]

Startup code and Dockerfile for WebApplication2 is exactly the same. This is the Docker Compose file:

  webapplication1:
    image: ${DOCKER_REGISTRY-}webapplication1
    build:
      context: WebApplication1
      dockerfile: Dockerfile
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_HTTP_PORTS=8080      
    ports:
      - 53661:8080
      - 53662:8081
    healthcheck:         
        test: curl http://localhost:8080/health1 || exit 1              
        start_period: 10s
        start_interval: 10s
        interval: 5s
        timeout: 20s
        retries: 5 
  webapplication2:
    image: ${DOCKER_REGISTRY-}webapplication2
    build:
      context: WebApplication2
      dockerfile: Dockerfile
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_HTTP_PORTS=8080
    depends_on:
        webapplication1:    
          condition: service_healthy 
    ports:
      - 63661:8080
      - 63662:8081

Notice this line test: curl http://localhost:8080/health1 || exit 1 is the code that should be marking WebApplication1 as healthy so WebApplication2 can start. When I debug the docker compose orchestration, it fails:

3>#12 DONE 0.0s
3> Container WebApplication1  Creating
3> Container WebApplication1  Created
3> Container WebApplication2  Creating
3> Container WebApplication2  Created
3> Container WebApplication1  Starting
3> Container WebApplication1  Started
3> Container WebApplication1  Waiting
3> Container WebApplication1  Error
3>dependency failed to start: container WebApplication1 is unhealthy
3>C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Sdks\Microsoft.Docker.Sdk\build\Microsoft.VisualStudio.Docker.Compose.targets(430,5): error DT1001: dependency failed to start: container WebApplication1 is unhealthy
3>C:\Program Files\Microsoft Visual Studio\2022\Preview\MSBuild\Sdks\Microsoft.Docker.Sdk\build\Microsoft.VisualStudio.Docker.Compose.targets(430,5): error DT1001: If the error persists, try restarting Docker Desktop.
3>Done building project "docker-compose.dcproj" -- FAILED.
========== Build: 2 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
========== Build completed at 07:48 and took 36.168 seconds ==========

image

Running

docker inspect `WebApplication1` --format  '{{range .State.Health.Log}}{{.End}} | Exit Code: {{.ExitCode}} | {{.Output}}{{end}}'

results in this error:
curl: (7) Failed to connect to localhost port 8080 after 0 ms: Couldn't connect to server

I placed a breakpoint in Program.cs from WebApplication1 and it doesn't get started under this configuration, but if I comment the healthcheck code from the compose file it works as expected. Weirdly enough if I do a docker compose up --build, it works properly

image

My first thoughts were that should be something with the Visual Studio Docker tools configuration in Debug mode, it was suggested in other StackOverFlow posts to add this:

<PropertyGroup>
    <ContainerDevelopmentMode>Regular</ContainerDevelopmentMode>
</PropertyGroup>

But doesn't work either. Any ideas what is going wrong with the health checks?

I attach a working project DockerWebApiHealthChecksBug.zip so it can be easily tested

@NCarlsonMSFT
Copy link
Member

@zharchimage this is an issue with the debug support from VS. Currently there is no support for decencies and health checks when running from visual studio, although this is something we are working on improving.

@zharchimage
Copy link
Author

zharchimage commented Sep 10, 2024

Hi @NCarlsonMSFT thanks for the answer, is there any workaround we can do to disable the fast mode for asp.net core containers? I have healthchecks in a custom SQLServer Image calling a shell script and works fine, so just wondering if there is something we can tweak in the docker-compose.dcproj for now I added a docker-compose.vs.debug.yml override

services:
  webapplication1:    
    environment:
      - URLS=http://+:8080;        
      - ASPNETCORE_HTTP_PORTS=8080      
      - ASPNETCORE_ENVIRONMENT=Development
  webapplication2:    
    scale: 1
    depends_on:
        webapplication1:    
          condition: service_started
    environment:
      - URLS=http://+:8080;        
      - ASPNETCORE_HTTP_PORTS=8080      
      - ASPNETCORE_ENVIRONMENT=Development

But it is not ideal as WebApplication2 often fails as depends in WebApplication1 finishing first doing some warmup work.

@NCarlsonMSFT
Copy link
Member

The only other work-around I can suggest is to use the label com.microsoft.visual-studio.project-name to empty string to disable debugging in the dependent service which works around the issue, but then requires attaching to debug the 2nd service.

@zharchimage
Copy link
Author

Thanks, will try that for now.

@WMTaylor2Degrees
Copy link

Commenting in here as this is something that's also causing me issues. Spent too long trying to figure out what was wrong too.

For reference, I have two containers, A and B. B depends on A. Both are ASP.Net applications.
Container A has a healthcheck defined which uses curl (curl is installed in the container).
Container B has a depends_on defined which requires container A to be healthy.

When the depends_on is commented out in docker-compose for container B, both containers spin up simultaneously (causing issues with B) however the health check for container A passes, and shows healthy (showing the health check itself is fine).

When depends_on is uncommented, it causes container A to fail to start up. The curl request fails saying the connection was refused and the container is left in an unhealthy state.

This only happens when running in Visual Studio.

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

No branches or pull requests

3 participants