Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions src/Aspire.Hosting/Dcp/ContainerCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.Net.Sockets;
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Dcp.Model;
using Aspire.Hosting.Publishing;
using Aspire.Hosting.Utils;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
Expand Down Expand Up @@ -260,7 +261,7 @@ private async Task BuildAndCreateContainerAsync(RenderedModelResource<Container>
var dcpContainer = cr.DcpResource;
var modelContainer = cr.ModelResource;

await ApplyBuildArgumentsAsync(dcpContainer, cr.ModelResource, _executionContext.ServiceProvider, cToken).ConfigureAwait(false);
await ApplyBuildArgumentsAsync(dcpContainer, cr.ModelResource, _executionContext.ServiceProvider, logger, cToken).ConfigureAwait(false);

var spec = dcpContainer.Spec;

Expand Down Expand Up @@ -732,7 +733,7 @@ await modelResource.ProcessContainerRuntimeArgValues(
return (runArgs, failedToApplyArgs);
}

private static async Task ApplyBuildArgumentsAsync(Container dcpContainerResource, IResource modelContainerResource, IServiceProvider serviceProvider, CancellationToken cancellationToken)
private static async Task ApplyBuildArgumentsAsync(Container dcpContainerResource, IResource modelContainerResource, IServiceProvider serviceProvider, ILogger logger, CancellationToken cancellationToken)
{
if (modelContainerResource.Annotations.OfType<DockerfileBuildAnnotation>().SingleOrDefault() is { } dockerfileBuildAnnotation)
{
Expand Down Expand Up @@ -783,6 +784,18 @@ private static async Task ApplyBuildArgumentsAsync(Container dcpContainerResourc
Args = dcpBuildArgs,
Secrets = dcpBuildSecrets
};

#pragma warning disable ASPIREPIPELINES003 // ContainerBuildOptions APIs are experimental.
var buildOptionsContext = await modelContainerResource.ProcessContainerBuildOptionsCallbackAsync(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This would need to be done in a way that doesn't take a dependency on the publish types in DCP (no Aspire.Hosting.Publishing dependency).

serviceProvider,
logger,
cancellationToken: cancellationToken).ConfigureAwait(false);

if (buildOptionsContext.TargetPlatform is { } targetPlatform)
{
dcpContainerResource.Spec.Build.Platform = targetPlatform.ToRuntimePlatformString();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm nervous about us overriding the default run time platform to linux/amd64 regardless of the host architecture at run time when building a Dockerfile just because I've seen enough cases where the emulation layers fail. I'd want to consider supporting separate publish and runtime defaults (stick with linux/amd64 as the default publish platform, but continue to use the current machine architecture as the default at runtime.

}
#pragma warning restore ASPIREPIPELINES003
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/Aspire.Hosting/Dcp/Model/Container.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ internal sealed class BuildContext
// Optional labels to apply to the built image
[JsonPropertyName("labels")]
public List<ContainerLabel>? Labels { get; set; }

// Optional target platform for the build (e.g. "linux/amd64")
[JsonPropertyName("platform")]
public string? Platform { get; set; }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

There isn't a platform field in the DCP types (https://github.com/microsoft/dcp/blob/main/api/v1/container_types.go#L140), so any proposed change would need to start there.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Opened initial PR -> microsoft/dcp#140

}

internal sealed class BuildContextSecret
Expand Down
26 changes: 26 additions & 0 deletions tests/Aspire.Hosting.Tests/Dcp/DcpExecutorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using Aspire.Dashboard.Model;
using Aspire.Hosting.Dcp;
using Aspire.Hosting.Dcp.Model;
using Aspire.Hosting.Publishing;
using Aspire.Hosting.Tests.Utils;
using k8s.Models;
using Microsoft.AspNetCore.InternalTesting;
Expand Down Expand Up @@ -51,6 +52,31 @@ public async Task ContainersArePassedOtelServiceName()
Assert.Equal("CustomName", container.Metadata.Annotations["otel-service-name"]);
}

[Fact]
public async Task DockerfileContainerBuildSpecIncludesPlatform()
{
using var tempDockerfileContext = await DockerfileUtils.CreateTemporaryDockerfileAsync();

var builder = DistributedApplication.CreateBuilder();
#pragma warning disable ASPIREPIPELINES003 // ContainerBuildOptions APIs are experimental.
builder.AddDockerfile("mycontainer", tempDockerfileContext.ContextPath, tempDockerfileContext.DockerfilePath)
.WithContainerBuildOptions(ctx => ctx.TargetPlatform = ContainerTargetPlatform.LinuxArm64);
#pragma warning restore ASPIREPIPELINES003

var kubernetesService = new TestKubernetesService();

using var app = builder.Build();
var distributedAppModel = app.Services.GetRequiredService<DistributedApplicationModel>();

var appExecutor = CreateAppExecutor(distributedAppModel, kubernetesService: kubernetesService);

await appExecutor.RunApplicationAsync();

var container = Assert.Single(kubernetesService.CreatedResources.OfType<Container>());
Assert.NotNull(container.Spec.Build);
Assert.Equal("linux/arm64", container.Spec.Build!.Platform);
}

[Fact]
public async Task ResourceStarted_ProjectHasReplicas_EventRaisedOnce()
{
Expand Down
Loading