microsoft / DockerTools

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

Dockerfile COPY with 'app' destination does nothing #429

Closed jacob-winkler closed 2 months ago

jacob-winkler commented 6 months ago

I'm trying to copy some files into the app directory within my application's running docker container but they files never seem to persist when I run my container.

Here's my dockerfile:

#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
ADD ../AthleticClubAPI.Migrations/Scripts app/scripts
EXPOSE 8080
EXPOSE 8081

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["AthleticClubAPI/AthleticClubAPI.csproj", "AthleticClubAPI/"]
RUN dotnet restore "./AthleticClubAPI/./AthleticClubAPI.csproj"
COPY . .
WORKDIR "/src/AthleticClubAPI"
RUN dotnet build "./AthleticClubAPI.csproj" -c $BUILD_CONFIGURATION -o /app/build

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

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

This line ADD ../AthleticClubAPI.Migrations/Scripts app/scripts is what's failing. I've successfully copied these files to directories that aren't the app directory. For instance ADD ../AthleticClubAPI.Migrations/Scripts scripts successfully creates a scripts folder in the container's root and populates it with the files from AthleticClubAPI.Migrations/Scripts.

My running theory right now is that this is a symptom of visual studio's fast mode docker build. I imagine that somewhere along the way the entire app directory is being overwritten by things happening in secret after the base build stage executes. However, thus far I've been unsuccessful in disabling the fast mode to test this (I've tried the ways mentioned in the article with clean and rebuild of my solution, etc. I've seen no indication in the build logs that any of the other stages run.)

Here's is my docker-compose that's being used by visual studio, in case that's relevant also.

version: '3.4'

services:
  athleticclubapi:
    image: ${DOCKER_REGISTRY-}athleticclubapi
    build:
      context: .
      dockerfile: AthleticClubAPI/Dockerfile
    ports:
      - "8080:8080"
      - "8081:8081"

  athleticclub.db:
    image: postgres:latest
    container_name: athleticclub.db
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: athletic-club
    volumes:
      - ./.containers/athleticclub-db:/var/lib/postgresql/data
    ports:
      - "5432:5432"

Hopefully someone can shed some light on what's happening here, and help me come up with a solution to solve this. I need to copy these files to the app directory, as fluent migrator seems to pre-pend the directory context that the app is running in to any scripts that I try to execute in my migrations. I'm also involved in a lengthy investigation there to see if there could be a workaround, but so far it doesn't look good.

Thanks for reading!

NCarlsonMSFT commented 6 months ago

I must admit I'm confused that your ADD command ever works. Per Docker's documentation "The <src> path must be inside the build context; you can't use ADD ../something /something" (https://docs.docker.com/reference/dockerfile/#add)

Putting that aside for the moment, you are correct that VS's fast mode is overwriting the app folder with a volume mount (docs) You can disable Fast mode by setting the msbuild property DockerDevelopmentMode to Regular (docs) in your .dcproj. Alternatively, I'd recommend using MSBuild to copy the file to the output directory, for instance adding:

<ItemGroup>
  <None Update="Scripts\CopyMe.txt">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
  </None>
</ItemGroup>

to your service project. This has the benefit of working in both Fast and Regular mode.

jacob-winkler commented 6 months ago

I must admit I'm confused that your ADD command ever works. Per Docker's documentation "The <src> path must be inside the build context; you can't use ADD ../something /something" (https://docs.docker.com/reference/dockerfile/#add)

I did not know that about the ADD command. Strangely this is working for me somehow. Here's a screenshot of my container's filesystem having used the ADD command specified above: image

Regarding your suggestion, I tried to modify it to copy an entire directory and all of its contents. I came across this answer on stackoverflow. Unfortunately, this didn't seem to work for me. I tried the variation in the article, along with a variation closer to what you suggested

<None Update="..\AthleticClubAPI.Migrations\Scripts\*.*">
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>

I tried adding this in two different locations. The .dcproj file and the .csproj file of the project that my dockerfile lives in (my app consists of multiple projects.)

Hopefully I've just missed something simple here. Cheers!

NCarlsonMSFT commented 6 months ago

If you're not getting the layout you like with the automatic copy, you may need to create a custom target as in this answer in the linked article: https://stackoverflow.com/a/44378406/12567640

jacob-winkler commented 1 month ago

I've come back to this and started to tinker again. From my testing, Fast build mode will also overwrite files copied using MSBuild.

The migrations tooling I use automatically sets all of the migrations that I create to copy to the output directory:

<ItemGroup>
   <None Update="Scripts\20240515184509_RenameUserTableToMember.sql">
     <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
   </None>
</ItemGroup>

When I set DockerDevelopmentMode to Regular these files are copied and persist in the output directory's app/Scripts folder. But if I switch back to Fast mode, they aren't there.

Here is my dockerfile

#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080
EXPOSE 8081

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["AthleticClubAPI/AthleticClubAPI.csproj", "AthleticClubAPI/"]
RUN dotnet restore "./AthleticClubAPI/./AthleticClubAPI.csproj"
COPY . .
WORKDIR "/src/AthleticClubAPI"
RUN dotnet build "./AthleticClubAPI.csproj" -c $BUILD_CONFIGURATION -o /app/build

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

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

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

For the time being, I will just run in Regular mode. However I would still like to find a more robust solution that can be used with Fast mode also, if possible.