dotnet / aspire

Tools, templates, and packages to accelerate building observable, production-ready apps
https://learn.microsoft.com/dotnet/aspire
MIT License
3.95k stars 486 forks source link

Help! Cannot get azd package to build the container either with, or without a Dockerfile #1154

Open chrisrlewis opened 1 year ago

chrisrlewis commented 1 year ago

I've been unable to package my Aspire-enabled single Api project because the azd is unable to build my Docker container image. My knowledge of Docker, dockerfiles, azd and Azure is 'newbie' but as I understand it, Aspire is intended to ease the path to deployment in Azure.

I have been able to build and deploy the Starter app with no difficulty at all, but my own Api project is not having any of it!

Without a Dockerfile in my Api project, I am getting these errors:

[detector] Warning: Platform requested experimental feature 'Dockerfiles'
[detector] Timer: Detector started at 2023-11-30T21:06:42Z
[detector] ======== Output: oryx/dotnet-install@0.0.1 ========
[detector] Unable to detect platform components for platform 'dotnet' in provided application.
[detector] ======== Results ========
[detector] pass: oryx/dotnet-runtime@0.0.1
[detector] fail: oryx/dotnet-install@0.0.1
[detector] pass: fagiani/apt@0.2.5
[detector] pass: oryx/dotnet-build@0.0.1
[detector] ======== Output: oryx/dotnet-install@0.0.1 ========
[detector] Unable to detect platform components for platform 'dotnet' in provided application.
[detector] ======== Results ========
[detector] pass: oryx/node-runtime@0.0.1
[detector] fail: oryx/dotnet-install@0.0.1
[detector] pass: fagiani/apt@0.2.5
[detector] pass: oryx/dotnet-build@0.0.1
...
[detector] ERROR: No buildpack groups passed detection.
[detector] ERROR: Please check that you are running against the correct path.
[detector] ERROR: failed to detect: no buildpacks participating
, stderr: ERROR: failed to build: executing lifecycle: failed with status code: 20
No Dockerfile was found, and image could not be automatically built from source.
Suggested action: Author a Dockerfile and save it as ...

So adding a Dockerfile, which does build within the Api project itself, results in these errors:

ERROR: failed building service 'zzzSettingsManager.Api': failing invoking action 'build', building container: zzzSettingsManager.Api at .: building image: exit code: 1, stdout: , stderr: #0 building with "default" instance using docker driver
...
#9 [build  6/13] COPY [zzzManager.ServiceDefaults/zzzManager.ServiceDefaults.csproj, zzzManager.ServiceDefaults/]
#9 ERROR: failed to calculate checksum of ref 9125e95d-70c7-4016-9af1-614068a50fe2::d05yq978p2ms77jkw2xo1z5b6: "/zzzManager.ServiceDefaults/zzzManager.ServiceDefaults.csproj": not found
...
[further dependent projects also with same error]
...
ERROR: failed to solve: failed to compute cache key: failed to calculate checksum of ref 9125e95d-70c7-4016-9af1-614068a50fe2::d05yq978p2ms77jkw2xo1z5b6: "/src/Modules/zzzSettingsManager/zzzSettingsManager.Infrastructure/zzzSettingsManager.Infrastructure.csproj": not found

I should mention that this is an Api built with a Clean Architecture structure, with a folder structure - which seems to me the possible problem here. I'm also using central package management, which doesn't seem to play well with Aspire orchestration which does not expect this and adds package versions locally, which need to be manually moved to the Directory.Packages.props.

The folder structure and key files looks like this:

To my newbie eye, it seems that the hierarchical folder structure here may be at the root of the problem? Perhaps the central package management is also an issue as to why azd package can't build the container without a Dockerfile?

I'm really struggling with this, and have spent many fruitless (and frustrating) hours trying to get it to work.

I'd be enormously grateful for any steer on where I'm going wrong.

DamianEdwards commented 1 year ago

I'm also using central package management, which doesn't seem to play well with Aspire orchestration which does not expect this and adds package versions locally, which need to be manually moved to the Directory.Packages.props.

This isn't a .NET Aspire thing but rather a general thing between .NET templates and NuGet Central Package Management (CPM). That issue is being tracked at https://github.com/NuGet/Home/issues/12629

Can you verify the version of AZD you're using and share it here please?

/Cc @ellismg @bradygaster

ellismg commented 1 year ago

I've been unable to package my Aspire-enabled single Api project because the azd is unable to build my Docker container image. My knowledge of Docker, dockerfiles, azd and Azure is 'newbie' but as I understand it, Aspire is intended to ease the path to deployment in Azure.

It's surprising to me to see this sort of output:

[detector] Warning: Platform requested experimental feature 'Dockerfiles' [detector] Timer: Detector started at 2023-11-30T21:06:42Z [detector] ======== Output: oryx/dotnet-install@0.0.1 ========

When working with an Aspire app. To me, this means we are trying to use oryx to try to create a container for the application, but azd should not be doing that for an Aspire app. Instead, it should be using dotnet publish to create the container. This also does not require a Dockerfile and should "Just Work".

In addition to the verison of azd that you have (it should be 1.5.0) could you share what your azure.yaml looks like? It sounds like things might be set up in a way such that azd doesn't fully understand your Aspire app is actually an Aspire app and it's doing the wrong thing because of it.

chrisrlewis commented 1 year ago

I'm also using central package management, which doesn't seem to play well with Aspire orchestration which does not expect this and adds package versions locally, which need to be manually moved to the Directory.Packages.props.

This isn't a .NET Aspire thing but rather a general thing between .NET templates and NuGet Central Package Management (CPM). That issue is being tracked at NuGet/Home#12629

Can you verify the version of AZD you're using and share it here please?

/Cc @ellismg @bradygaster

Thanks for your response. Understood re the template issue, I didn't realise it was a template issue - this is the first time I've used azd.

The version I'm using is 1.5.0

@ellismg @bradygaster

chrisrlewis commented 1 year ago

I've been unable to package my Aspire-enabled single Api project because the azd is unable to build my Docker container image. My knowledge of Docker, dockerfiles, azd and Azure is 'newbie' but as I understand it, Aspire is intended to ease the path to deployment in Azure.

It's surprising to me to see this sort of output:

[detector] Warning: Platform requested experimental feature 'Dockerfiles' [detector] Timer: Detector started at 2023-11-30T21:06:42Z [detector] ======== Output: oryx/dotnet-install@0.0.1 ========

When working with an Aspire app. To me, this means we are trying to use oryx to try to create a container for the application, but azd should not be doing that for an Aspire app. Instead, it should be using dotnet publish to create the container. This also does not require a Dockerfile and should "Just Work".

In addition to the verison of azd that you have (it should be 1.5.0) could you share what your azure.yaml looks like? It sounds like things might be set up in a way such that azd doesn't fully understand your Aspire app is actually an Aspire app and it's doing the wrong thing because of it.

Thanks for getting back. My azure.yml (the whole contents) is:

name: zzzManager
metadata:
    template: azd-init@1.5.0
services:
    zzzSettingsManager.Api:
        project: src\Modules\zzzSettingsManager\zzzSettingsManager.Api
        host: containerapp
        language: dotnet

And I am using azd 1.5.0 as you can see here. I'm happy to provide any other details you think may help.

ellismg commented 1 year ago

Thanks, @chrisrlewis.

I suspect the problem here is that your azure.yaml file is pointing at the individual service instead of the AppHost project in the root of your solution. For the Aspire support in azd to work, we expect that the service in your azure.yaml file references the App Host itself (which contains the complete set of information about your Aspire application instead of an individual service)

I would have expected that the azure.yaml would have looked like this:

name: zzzManager
services:
    app:
        project: zzzManager.AppHost\zzManager.AppHost.csproj
        host: containerapp
        language: dotnet

I think this is what azd would have written out for you when you ran azd init and initialized from your existing codebase.

Given the shape of your azure.yaml, perhaps the AppHost project did not exist when you initially ran azd init, and only your API service did? In that case, we would have initialized this as a non Aspire .NET project, which would explain why we are seeing these weird errors.

If you delete (or temporarily rename) both the .azure and azure.yaml files and re-run azd init from the root of your solution, does it correctly detect your app host project? It should say that it detected a .NET Asprie application instead of just regular .NET. It should also ask you during init which of your aspire services you want to expose to the internet (similar to what you saw in the starter application).

If that's still not working, let me know and we can collect some debug logs and try to dig in further.

chrisrlewis commented 1 year ago

Thanks, @chrisrlewis.

I suspect the problem here is that your azure.yaml file is pointing at the individual service instead of the AppHost project in the root of your solution. For the Aspire support in azd to work, we expect that the service in your azure.yaml file references the App Host itself (which contains the complete set of information about your Aspire application instead of an individual service)

I would have expected that the azure.yaml would have looked like this:

name: zzzManager
services:
    app:
        project: zzzManager.AppHost\zzManager.AppHost.csproj
        host: containerapp
        language: dotnet

I think this is what azd would have written out for you when you ran azd init and initialized from your existing codebase.

Given the shape of your azure.yaml, perhaps the AppHost project did not exist when you initially ran azd init, and only your API service did? In that case, we would have initialized this as a non Aspire .NET project, which would explain why we are seeing these weird errors.

If you delete (or temporarily rename) both the .azure and azure.yaml files and re-run azd init from the root of your solution, does it correctly detect your app host project? It should say that it detected a .NET Asprie application instead of just regular .NET. It should also ask you during init which of your aspire services you want to expose to the internet (similar to what you saw in the starter application).

If that's still not working, let me know and we can collect some debug logs and try to dig in further.

Thanks for responding @ellismg

I've tried both of your suggestions, starting with amending the azure.yml file. The azd package succeeded, but the provision stage then failed with this error:

ERROR: deployment failed: failing invoking action 'provision', error deploying infrastructure: resolving bicep parameters file: substituting environment variables inside parameter file: missing closing brace

So then I deleted the .azure and azure.yml, and also .infra folder, to get back to the pre-init state. Hopefully not to confuse things too much I have also started to play with Blazor, and added a Blazor Web app to the solution.

I ran azd init again, and checked the new azure.yml file which is shown below

# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json

name: zzzManager
metadata:
    template: azd-init@1.5.0
services:
    zzzManager.Web:
        project: src\Web\zzzManager.Web\zzzManager.Web
        host: containerapp
        language: dotnet
    zzzManager.Web.Client:
        project: src\Web\zzzManager.Web\zzzManager.Web.Client
        host: containerapp
        language: dotnet
    zzzSettingsManager.Api:
        project: src\Modules\zzzSettingsManager\zzzSettingsManager.Api
        host: containerapp
        language: dotnet

You can see that the file again looks like my original .yml file - i.e. doesn't refer to the zzzManager.AppHost.csproj (it is there) but instead lists the three individual project folders? When I subsequently run azd up, this is the error:

Packaging services (azd package)

  (x) Failed: Packaging service zzzManager.Web

ERROR: failed building service 'zzzManager.Web': failing invoking action 'build', exit code: 1, stdout: debian-buster-20231004.1: Pulling from oryx/builder
Digest: sha256:0db4b4095ffb10e34516553aa0431892bb5528ed3bbb94d4c78d63609dea4729
Status: Image is up to date for mcr.microsoft.com/oryx/builder:debian-buster-20231004.1
stack-run-debian-buster-20230926.1: Pulling from oryx/builder
Digest: sha256:793188bbaad7892965b5ef74ba9e2bf5b1c40a6ea52eb3c631ced1053b620fe8
Status: Image is up to date for mcr.microsoft.com/oryx/builder:stack-run-debian-buster-20230926.1
0.17.0: Pulling from buildpacksio/lifecycle
Digest: sha256:bc0d791f89bda0e8fbf9bf3e47c2faf1ac4eca4b16f0b01c6cb606883759766a
Status: Image is up to date for buildpacksio/lifecycle:0.17.0
===> ANALYZING
[analyzer] Timer: Analyzer started at 2023-12-03T19:03:28Z
[analyzer] Image with name "zzzmanager-zzzmanager.web" not found
[analyzer] Timer: Analyzer ran for 569.629µs and ended at 2023-12-03T19:03:28Z
===> DETECTING
[detector] Warning: Platform requested experimental feature 'Dockerfiles'
[detector] Timer: Detector started at 2023-12-03T19:03:35Z
[detector] oryx/dotnet-runtime 0.0.1
[detector] oryx/dotnet-install 0.0.1
[detector] fagiani/apt         0.2.5
[detector] oryx/dotnet-build   0.0.1
[detector] Timer: Detector ran for 1.182284056s and ended at 2023-12-03T19:03:37Z
[detector] Timer: Generator started at 2023-12-03T19:03:37Z
[detector] Loading environment variables from existing 'oryx.env' file.
[detector] BP_PLATFORM_VERSION=8.0
[detector] BP_RUNTIME_IMAGE=mcr.microsoft.com/oryx/dotnetcore:8.0-debian-buster
[detector] Warning: new runtime base image 'mcr.microsoft.com/oryx/dotnetcore:8.0-debian-buster' not found in run metadata
[detector] Timer: Generator ran for 14.797589ms and ended at 2023-12-03T19:03:37Z
, stderr: ERROR: failed to build: executing lifecycle: image 'mcr.microsoft.com/oryx/dotnetcore:8.0-debian-buster' does not exist on the daemon: not found

So I modified the azure.yml file again, as your suggestions and this gets me further, but fails again with this error:

By default, a service can only be reached from inside the Azure Container Apps environment it is running in. Selecting a service here will also allow it to be reached from the Internet.
? Select which services to expose to the Internet zzzmanager.web, zzzsettingsmanager.api

Packaging services (azd package)

Provisioning Azure resources (azd provision)
Provisioning Azure resources can take some time.

Subscription: Azure subscription 1 (xxxxxxxx-xxxx-46xxx01-xxxx-c25344ff87e9)
Location: UK South

ERROR: deployment failed: failing invoking action 'provision', error deploying infrastructure: resolving bicep parameters file: substituting environment variables inside parameter file: missing closing brace

I really appreciate you looking at this, and for any further insights. As I mentioned before, happy to provide any further info, logs, etc. that would help.

chrisrlewis commented 1 year ago

@ellismg

Attached an 'azd provision --debug' log out put for reference. azd provision debug.txt

weikanglim commented 12 months ago

@chrisrlewis Thanks for being patient with us! azd init currently prioritizes the src directory if it exists above all else (relevant code). This was done in attempt to limit catching other tooling projects unnecessarily, with the expectation that if src exists -- all source projects are likely under the src directory.

We could revisit this behavior, or provide an opt-out in the future. One option here without additional changes is to move the AppHost directory under src if that's tenable for you.

When you run azd init, you should see .NET (Aspire) and the AppHost project referenced in the detection summary, like so:

image

If you don't see the .NET (Aspire) in this prompt, something else is still going wrong.

Hope some of that helps!

chrisrlewis commented 12 months ago

Hi Wei, Many thanks for your response. I have removed all trace of Aspire from the solution a few times to re-try things. When I added Aspire orchestration back in (from scratch) I did specify the path to include /src/... but this is ignored, and always puts the AppHost and ServiceDefaults in the solution root folder? I've tried this twice and the result is the same.

Anyway, I did what you suggested and manually removed the AppHost project, and moved it to the src folder, added it back in and fixed references, etc., then ran azd init again. This time I get a different error - one I can see referenced with a TODO in your code extract (line 122: // TODO(ellismg): We will have to figure out how to relax this over time.). Here is the result:

PS C:\Users\clewis\source\personal\CleanArchitecture\Convey\MotManager> azd init

Initializing an app to run on Azure (azd init)

? How do you want to initialize your app? Use code in the current directory

  (✓) Done: Scanning app code in current directory

ERROR: only a single Aspire project is supported at this time

There is only one AppHost project, plus the Blazor Web app (using the new 'auto' Blazor project template - which adds two projects - a server project plus the client project). I think that the azd init possibly has a problem with finding two 'web' projects?

So I removed the Blazor auto-render projects (server and client) completely from the solution, and replaced with a Blazor static SSR project which adds only one project. This resolved the azd init. I then ran azd up, and this got as far as azd deploy then failed with this error:

  (✓) Done: Resource group: rg-zzzmanager-uksouth-dev
  (✓) Done: Container Registry: xxx
  (✓) Done: Log Analytics workspace: xxxx
  (✓) Done: Container Apps Environment: xxx

Deploying services (azd deploy)

  (x) Failed: Deploying service zzzsettingsmanager.api

ERROR: failed deploying service 'zzzsettingsmanager.api': failing invoking action 'deploy', updating container app service: applying manifest: PUT https://management.azure.com/subscriptions/[subscriptionid]/resourceGroups/rg-zzzmanager-uksouth-dev/providers/Microsoft.App/containerApps/zzzsettingsmanager.api
--------------------------------------------------------------------------------
RESPONSE 400: 400 Bad Request
ERROR CODE: ContainerAppInvalidName
--------------------------------------------------------------------------------
{
  "error": {
    "code": "ContainerAppInvalidName",
    "message": "Invalid ContainerApp name 'zzzsettingsmanager.api'. A name must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character and cannot have '--'. The length must not be more than 32 characters."
  }
}
--------------------------------------------------------------------------------

Which seems like a straightforward issue (my api project name is 'zzzsettingsmanager.api'), but this translates to a container app name that Azure doesn't allow apparently, and this has not been picked up by the workflow - perhaps should be replaced with a hyphen, which is allowed?

I can see that there is a config.json file in .azure// that contains the name of the exposed services, so I have updated that and tried to re-run azd deploy but I then get 'panic: runtime error: invalid memory address or nil pointer dereference'

Further update:

I renamed my project to remove the period (zzzsettingsmanagerapi), removed the Aspire init files, cleaned up all of the provisioned resources on Azure and re-ran azd init, azd provision and then azd deploy - and it has now deployed!

I did notice that the AppHost project assigns the name of the project:

builder.AddProject<Projects.zzzSettingsManagerApi>("zzzsettingsmanagerapi");

So I wondered whether just amending this name would have had the same effect (i.e. to create a container app with this name, without the period)?

In summary, my learnings/questions based on the above are:

  1. Specifying a path for the Aspire orchestration template doesn't seem to work if the path is './src'
  2. The new Blazor 'auto render' app template, which creates two projects for the server and client sides seems to cause the azd init a problem?
  3. Using a period (.) in a project name (or a name that will be a container app) is not allowed by Azure Container Apps.
weikanglim commented 11 months ago

@chrisrlewis Been trying to get better answers and move some background work to resolve some of the issues, and that has taken some time. But to answer your immediate questions:

  1. The limitation here is that if there's a src directory, azd would expect all source code to be contained within the src directory. For example, putting one project within src, but other projects outside of src would not work.
  2. There is indeed an issue with the client webassembly project and azd's stronger validation currently, this issue is being tracked and addressed as https://github.com/Azure/azure-dev/issues/3024
  3. We're still in discussions on appropriate naming, but you are correct that having "." in the resource names is currently unsupported.
chrisrlewis commented 11 months ago

Thanks @weikanglim. To clarify point 1 - from my experience what I found was that I did specify that the Aspire components should be added in to an existing project (containing a Blazor client and an API) under the existing 'src' directory, but this seems to be overridden (ignored) by the Aspire template, because despite specifying that AppHost and ServiceDefaults should be added into the 'src' directory, they are added in to the solution root folder regardless. I then needed to manually move the AppHost project to the 'src' directory to make the azd deployment work (incidentally, I did not have to move the ServiceDefaults project - it stayed in the solution root, and this azd deployment worked).

weikanglim commented 11 months ago

@chrisrlewis I see. I totally misunderstood that point. To confirm, was this the "Add .NET Aspire Orchestrator" option inside Visual Studio? As you said, this flow defaults the AppHost project to be directly under the solution directory.