Skip to content

Conversation

@eerhardt
Copy link
Member

@eerhardt eerhardt commented Oct 21, 2025

Description

This allows a resource that contains static files (for example a Javascript frontend) to embed its static files into another app server - for example a fastapi python app backend.

Key changes:

  • Add ContainerFilesSourceAnnotation which goes on the resource that can produce static files. A resource with this annotation builds a docker image, but the image doesn't get pushed to a registry.
  • Add ContainerFilesDestinationAnnotation which goes on the resource that receives the static files. Resources that support this COPY the static files from the source resource into their own docker image.
  • All compute environment resources respect the new StaticDockerFilesAnnotation to mean that this resource shouldn't be considered a compute resource.
  • AzureEnvironment only builds "build-only" containers, but doesn't push them.

Contributes to #12162

Checklist

  • Is this feature complete?
    • No. Follow-up changes expected.
  • Are you including unit tests for the changes and scenario tests if relevant?
    • Yes
  • Did you add public API?
    • Yes
      • If yes, did you have an API Review for it?
        • Yes
        • No
      • Did you add <remarks /> and <code /> elements on your triple slash comments?
        • Yes
  • Does the change make any security assumptions or guarantees?
    • No
  • Does the change require an update in our Aspire docs?

@github-actions
Copy link
Contributor

github-actions bot commented Oct 21, 2025

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 12265

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 12265"

/// <param name="appDirectory">The directory containing the Python application files.</param>
/// <param name="moduleName"></param>
/// <returns>A resource builder for further configuration of the Uvicorn Python application resource.</returns>
public static IResourceBuilder<PythonAppResource> AddUvicornApp(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to decide if we make this UvicornAppResource : PythonAppResource

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would be the advantage to doing this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can build extension methods that target unvicorn configuration. We'll want that but lets file a follow up issue.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public static IResourceBuilder<PythonAppResource> AddUvicornApp(
this IDistributedApplicationBuilder builder, [ResourceName] string name, string appDirectory, string moduleName)
{
var resourceBuilder = builder.AddPythonExecutable(name, appDirectory, "uvicorn")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adamint - is this going to cause a problem with VS Code debugging?

// VS Code debug support - only applicable for Script and Module types
if (entrypointType is EntrypointType.Script or EntrypointType.Module)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we cannot debug any python executable. You'll need to call WithVSCodeDebugSupport and in the launch configuration provide the right entrypoint and then uvicorn as the module

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We an switch to a module instead

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to switch, we just need to indicate to the AppHost to start the right module

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OR, we can switch and make it just work in all cases :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just not sure if there are performance differences between using the uvicorn executable and running as a python module

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows a resource that contains files (for example a Javascript frontend) to embed its files into another app server - for example a fastapi python app backend.

Key changes:

* Add ContainerFilesSourceAnnotation which goes on the resource that can produce files. A resource with this annotation builds a docker image, but the image doesn't get pushed to a registry.
* Add ContainerFilesDestinationAnnotation which goes on the resource that receives the files. Resources that support this COPY the static files from the source resource into their own docker image.
* All compute environment resources respect a new HasEntrypoint=false bool to mean that this resource shouldn't be considered a compute resource, but should still build an image.

Contributes to dotnet#12162
@eerhardt eerhardt force-pushed the RemoveDockerFileFromPyTemplate branch from 1030250 to 69e92f1 Compare October 23, 2025 22:32
@eerhardt eerhardt marked this pull request as ready for review October 24, 2025 00:00
@Copilot Copilot AI review requested due to automatic review settings October 24, 2025 00:00
@eerhardt
Copy link
Member Author

I think this is now ready. I added a few tests.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces support for embedding static files from one Docker container into another during the build process. This enables scenarios like embedding a JavaScript frontend (built with Vite) into a Python backend server (FastAPI/Uvicorn).

Key changes:

  • New annotation system (ContainerFilesSourceAnnotation, ContainerFilesDestinationAnnotation) to mark resources that produce/consume static files
  • DockerfileBuildAnnotation.HasEntrypoint property to distinguish build-only containers from compute resources
  • Pipeline integration to ensure static file sources are built before their consumers
  • AddUvicornApp extension method for FastAPI/Uvicorn applications with automatic endpoint configuration

Reviewed Changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
ResourceBuilderExtensions.cs Adds PublishWithContainerFiles extension method for configuring file copying between containers
ResourceExtensions.cs Splits image build logic into RequiresImageBuild and RequiresImageBuildAndPush to handle build-only containers
IResourceWithContainerFiles.cs New marker interface for resources that can produce container files
DockerfileBuildAnnotation.cs Adds HasEntrypoint property to identify containers without entrypoints
DockerfileStage.cs Renames parameter from stage to from for clarity in CopyFrom method
ContainerFilesSourceAnnotation.cs Annotation marking the source path of files within a container
ContainerFilesDestinationAnnotation.cs Annotation specifying where to copy files and from which source
PythonAppResourceBuilderExtensions.cs Adds AddUvicornApp method and build pipeline logic for static file integration
ViteAppResource.cs Implements IResourceWithContainerFiles interface
NodeExtensions.cs Configures Vite apps as build-only containers with static file annotations
AzureEnvironmentResource.cs Updates to use RequiresImageBuild instead of RequiresImageBuildAndPush
Test files New tests and snapshots for the static files feature

@@ -1,15 +1,4 @@
# Stage 1: Build the Vite app
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love that the Dockerfile from the template moved to the test. 😆 Now you can see the diff in the dockerfile we generate vs what was laid down before.

@davidfowl
Copy link
Member

Attempting to deploy the template with this it seems like we're still trying to deploy the frontend even though we don't push it.

— Failed to deploy frontend: Deployment failed: ContainerAppOperationError: Failed to provision revision for container
app 'frontend'. Error details: The following field(s) are either invalid or missing. Field 'template.containers.frontend.image' is invalid with details:
'Invalid value: "envacrz6be3sjkvk7s2.azurecr.io/frontend:aspire-deploy-20251024061827": GET https:: MANIFEST_UNKNOWN: manifest tagged by
"aspire-deploy-20251024061827" is not found; map[Tag:aspire-deploy-20251024061827]';..

Comment on lines +31 to +34
if (r.IsBuildOnlyContainer())
{
continue;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like it's in the wrong place or this method has the wrong name.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion it isn't. A "build only container" (i.e. one that doesn't have an entrypoint) isn't a "Compute Resource". It can't stand alone. It doesn't have an entrypoint.

@davidfowl davidfowl merged commit f5e40da into dotnet:main Oct 24, 2025
305 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the 13.0 milestone Oct 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants