microsoft / vscode-docker

Docker Extension for Visual Studio Code
https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-docker
Other
1.18k stars 508 forks source link

Generated Dockerfile not buildable via CLI 'docker build' when generated for Project in subdirectory; paths break convention #4303

Closed twhitmorenz closed 1 month ago

twhitmorenz commented 1 month ago

I used the 'Docker: Add Dockerfiles to Workspace' default setup for a solution with the main project in a subdirectory. The generated Dockerfile worked when run from VS Code Tasks, but failed when run via docker build from from the command-line.

The cause is that the 'docker-build' task in tasks.json and Dockerfile are generated using the root folder of the solution as the cwd, but this is misaligned with standard 'docker build ' CLI command path expectations; these Dockerfiles then fail when attempting to build with standard tools.

Standard 'docker build \' CLI command behavior uses \ as the directory, finds the Dockerfile there named by convention, and executes with the directory containing the Dockerfile as it's context (cwd).

Docker extension v1.29.1, VS Code v1.89.1.

Example of problem:

Generated tasks.json excerpt:

{
    "type": "docker-build",
    "label": "docker-build: debug",
    "dependsOn": [
        "build"
    ],
    "dockerBuild": {
        "tag": "licensingserver:dev",
        "target": "base",
        "dockerfile": "${workspaceFolder}/RhapsodyLicensing/Dockerfile",
        "context": "${workspaceFolder}",
        "pull": true
    },
    "netCore": {
        "appProject": "${workspaceFolder}/RhapsodyLicensing/RhapsodyLicensing.csproj"
    }
}

Generated Dockerfile excerpt:

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

Note that host path is the solution root rather than /RhapsodyLicensing. This breaks when Docker build CLI is run from the terminal or CLI:

In both cases failure is on the COPY ["RhapsodyLicensing/RhapsodyLicensing.csproj", "RhapsodyLicensing/"] command which has been incorrectly generated expecting cwd to be a different directory from the Dockerfile directory.

Observation: The generated Dockerfile appears to copy the entire solution into the build container, not just the indicated project.

Potential solution 1

Result: Dockerfile will be runnable both from VSCode task & Docker CLI. Build will only have access to the specific project.

Potential solution 2

Result: Dockerfile will be runnable both from VSCode task & Docker CLI. Build will build all projects in the solution.

danegsta commented 1 month ago

To match the build behavior of the VSCode extension tasks from the CLI, you'll want to run your docker build commands from the solution root using the pattern docker build -f <path to Dockerfile> ..

We chose the layout we did for .NET Dockerfiles due to the need to support both building images for individual projects as well as building images for projects that reference other projects in a solution (such as shared libraries). If we used the individual project folders as the build context, we wouldn't be able to include referenced projects in the build (as they would fall outside the current build context) and if we used a single Dockerfile in the solution root, users would lose the ability to build specific images for individual projects.

If your project uses a supported .NET SDK (7.0.300+, 8.0+), you can actually build a container image directly (and debug it in VSCode) without needing a Dockerfile. For projects that don't need advanced configuration, such as installing additional OS packages, it's a great way to build container images for .NET projects without the messy nature of integrating .NET and Dockerfiles cleanly. You can get the same results from the CLI by running the appropriate .NET publish command.

Closing this as not planned since we can't change our existing Dockerfile scaffolding strategy without breaking a number of use cases.

twhitmorenz commented 1 month ago

Thanks. I recognize these architectural drivers, but this still leaves the approach non-compliant with the standard way a user would expect to run these files.

This could probably be solved by documentation. In either of:

I would suggest adding a section to https://code.visualstudio.com/docs/containers/troubleshooting as follows:

H2. Generated Dockerfiles won't build from the command line

For projects in subfolders, Dockerfiles are generated to run with the solution root as the working directory. This gives increased flexibility when needing to incorporate other components into the image. To build such files from the commandline, run your docker build commands from the solution root using the pattern docker build -f <path to Dockerfile>.

Thanks!