microsoft / DockerTools

Tools For Docker, including Visual Studio Provisioning and Publishing
Other
175 stars 26 forks source link

Port of ASP.NET Core api project gets not exposed when running in VS #364

Closed gingters closed 1 year ago

gingters commented 1 year ago

I have an ASP.NET Core project that is build with a slightly modified docker file. Following best practices, it uses a different user than root in the container. Since we don't run as root we can't bind to port 80 in the container, so we use a high port to run the api on. Also, in the execution environment TLS is terminated externally so we only host http and not https.

So this is the part of our Dockerfile that defines the runtime image:

# RUNTIME image
FROM mcr.microsoft.com/dotnet/aspnet:7.0-bullseye-slim AS base

# set dir and create a non-root user to run under
WORKDIR /app
RUN adduser -u 5678 --disabled-password --gecos "" api && chown -R api /app

# Address CIS-DI-0008
RUN chmod u-s /usr/bin/gpasswd /usr/bin/chsh /bin/umount /bin/mount /sbin/unix_chkpwd /usr/bin/expiry /usr/bin/newgrp /usr/bin/chage /usr/bin/chfn /usr/bin/wall /usr/bin/passwd /bin/su && \
    chmod g-s /usr/bin/gpasswd /usr/bin/chsh /bin/umount /bin/mount /sbin/unix_chkpwd /usr/bin/expiry /usr/bin/newgrp /usr/bin/chage /usr/bin/chfn /usr/bin/wall /usr/bin/passwd /bin/su

# copy published output to runtime image as runtime user
USER api
COPY --chown=api --from=build /app/publish .

# define exposed port
EXPOSE 5000
ENV ASPNETCORE_URLS=http://+:5000

# define entry point
ENTRYPOINT ["dotnet", "MyApi.dll"]

This is what I have in the launchSettings.json for the docker profile:

"Docker": {
      "commandName": "Docker",
      "launchBrowser": false,
      "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/health/ready",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ASPNETCORE_URLS": "http://+:5000" // tried it with and without this line
      },
      "publishAllPorts": true, // As I understood, this should bind all exposed ports in the container (in my case 5000) to a random port on my host machine
      "useSSL": false
}

However when I run the project using the Docker profile, it launches the container, but no (not a single) port is mapped to the container.

The log of the application the container says: [11:38:24 INF] Now listening on: http://[::]:5000 so the binding within the container obviously works. But this port is not mapped to my host.

The Containers window under my container -> ports says "There are no port mappings available for this container.".

What did I do wrong, or is this a bug in the tooling?

I currently use VS 2022 17.4.3 and Docker Desktop 4.15.0 (93002) with the WSL2 based engine.

NCarlsonMSFT commented 1 year ago

@gingters I suspect what you are running into is an artifact of how Container Debugging gets optimized in VS (docs) Most likely what is happening is you need to include:

EXPOSE 5000
ENV ASPNETCORE_URLS=http://+:5000

In the first stage of your Dockerfile

I was able to get a service running on port 5000 with the Dockerfile:

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 5000
ENV ASPNETCORE_URLS=http://+:5000

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["WebApplication2/WebApplication2.csproj", "WebApplication2/"]
RUN dotnet restore "WebApplication2/WebApplication2.csproj"
COPY . .
WORKDIR "/src/WebApplication2"
RUN dotnet build "WebApplication2.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "WebApplication2.csproj" -c Release -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication2.dll"]

And a launch profile:

"Docker": {
  "commandName": "Docker",
  "launchBrowser": true,
  "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}",
  "publishAllPorts": true,
  "useSSL": false,
  "environmentVariables": {
    "ASPNETCORE_URLS": "http://+:5000"
  }
}
gingters commented 1 year ago

Thank you, Nathan. Indeed, I have to first declare the runtime image and expose the ports, and then switch to the build image before switching back to the runtime image. Reading the docs more carefully in the first place would have helped. Sorry for that.