Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable container-to-container service communication #5628

Merged
merged 20 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ public static IResourceBuilder<AzureEventHubsResource> RunAsEmulator(this IResou
var tableEndpoint = storage.GetEndpoint("table");

context.EnvironmentVariables.Add("ACCEPT_EULA", "Y");
context.EnvironmentVariables.Add("BLOB_SERVER", $"{blobEndpoint.ContainerHost}:{blobEndpoint.Port}");
context.EnvironmentVariables.Add("METADATA_SERVER", $"{tableEndpoint.ContainerHost}:{tableEndpoint.Port}");
context.EnvironmentVariables.Add("BLOB_SERVER", $"{blobEndpoint.ContainerHost}:{blobEndpoint.ContainerPort}");
context.EnvironmentVariables.Add("METADATA_SERVER", $"{tableEndpoint.ContainerHost}:{tableEndpoint.ContainerPort}");
}));

if (configureContainer != null)
Expand Down
4 changes: 2 additions & 2 deletions src/Aspire.Hosting.Kafka/KafkaBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public static IResourceBuilder<KafkaServerResource> WithKafkaUI(this IResourceBu
static void ConfigureKafkaUIContainer(EnvironmentCallbackContext context, EndpointReference endpoint, int index)
{
var bootstrapServers = context.ExecutionContext.IsRunMode
? ReferenceExpression.Create($"{endpoint.ContainerHost}:{endpoint.Property(EndpointProperty.Port)}")
? ReferenceExpression.Create($"{endpoint.ContainerHost}:{endpoint.Property(EndpointProperty.ContainerPort)}")
: ReferenceExpression.Create($"{endpoint.Property(EndpointProperty.Host)}:{endpoint.Property(EndpointProperty.Port)}");

context.EnvironmentVariables.Add($"KAFKA_CLUSTERS_{index}_NAME", endpoint.Resource.Name);
Expand Down Expand Up @@ -164,7 +164,7 @@ private static void ConfigureKafkaContainer(EnvironmentCallbackContext context,
var internalEndpoint = resource.InternalEndpoint;

var advertisedListeners = context.ExecutionContext.IsRunMode
? ReferenceExpression.Create($"PLAINTEXT://localhost:29092,PLAINTEXT_HOST://localhost:{primaryEndpoint.Property(EndpointProperty.Port)},PLAINTEXT_INTERNAL://{internalEndpoint.ContainerHost}:{internalEndpoint.Property(EndpointProperty.Port)}")
? ReferenceExpression.Create($"PLAINTEXT://localhost:29092,PLAINTEXT_HOST://localhost:{primaryEndpoint.Property(EndpointProperty.Port)},PLAINTEXT_INTERNAL://{internalEndpoint.ContainerHost}:{internalEndpoint.Property(EndpointProperty.ContainerPort)}")
: ReferenceExpression.Create(
$"PLAINTEXT://{primaryEndpoint.Property(EndpointProperty.Host)}:29092,PLAINTEXT_HOST://{primaryEndpoint.Property(EndpointProperty.Host)}:{primaryEndpoint.Property(EndpointProperty.Port)},PLAINTEXT_INTERNAL://{internalEndpoint.Property(EndpointProperty.Host)}:{internalEndpoint.Property(EndpointProperty.Port)}");

Expand Down
16 changes: 8 additions & 8 deletions src/Aspire.Hosting.Milvus/MilvusBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ public static class MilvusBuilderExtensions
/// var milvus = builder.AddMilvus("milvus");
/// var api = builder.AddProject&lt;Projects.Api&gt;("api")
/// .WithReference(milvus);
///
/// builder.Build().Run();
///
/// builder.Build().Run();
/// </code>
/// </example>
/// <remarks>
Expand Down Expand Up @@ -80,11 +80,11 @@ public static IResourceBuilder<MilvusServerResource> AddMilvus(this IDistributed
///
/// var booksdb = builder.AddMilvus("milvus");
/// .AddDatabase("booksdb");
///
///
/// var api = builder.AddProject&lt;Projects.Api&gt;("api")
/// .WithReference(booksdb);
///
/// builder.Build().Run();
///
/// builder.Build().Run();
/// </code>
/// </example>
/// <param name="builder">The Milvus server resource builder.</param>
Expand Down Expand Up @@ -117,8 +117,8 @@ public static IResourceBuilder<MilvusDatabaseResource> AddDatabase(this IResourc
/// .WithAttu();
/// var api = builder.AddProject&lt;Projects.Api&gt;("api")
/// .WithReference(milvus);
///
/// builder.Build().Run();
///
/// builder.Build().Run();
/// </code>
/// </example>
/// <param name="builder">The Milvus server resource builder.</param>
Expand Down Expand Up @@ -186,6 +186,6 @@ public static IResourceBuilder<MilvusServerResource> WithConfigurationBindMount(

private static void ConfigureAttuContainer(EnvironmentCallbackContext context, MilvusServerResource resource)
{
context.EnvironmentVariables.Add("MILVUS_URL", $"{resource.PrimaryEndpoint.Scheme}://{resource.PrimaryEndpoint.ContainerHost}:{resource.PrimaryEndpoint.Port}");
context.EnvironmentVariables.Add("MILVUS_URL", $"{resource.PrimaryEndpoint.Scheme}://{resource.PrimaryEndpoint.ContainerHost}:{resource.PrimaryEndpoint.ContainerPort}");
}
}
2 changes: 1 addition & 1 deletion src/Aspire.Hosting.MongoDB/MongoDBBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ public static IResourceBuilder<MongoDBServerResource> WithInitBindMount(this IRe

private static void ConfigureMongoExpressContainer(EnvironmentCallbackContext context, MongoDBServerResource resource)
{
context.EnvironmentVariables.Add("ME_CONFIG_MONGODB_URL", $"mongodb://{resource.PrimaryEndpoint.ContainerHost}:{resource.PrimaryEndpoint.Port}/?directConnection=true");
context.EnvironmentVariables.Add("ME_CONFIG_MONGODB_URL", $"mongodb://{resource.PrimaryEndpoint.ContainerHost}:{resource.PrimaryEndpoint.ContainerPort}/?directConnection=true");
context.EnvironmentVariables.Add("ME_CONFIG_BASICAUTH", "false");
}
}
6 changes: 3 additions & 3 deletions src/Aspire.Hosting.MySql/MySqlBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public static IResourceBuilder<T> WithPhpMyAdmin<T>(this IResourceBuilder<T> bui
var endpoint = singleInstance.PrimaryEndpoint;
phpMyAdminContainerBuilder.WithEnvironment(context =>
{
context.EnvironmentVariables.Add("PMA_HOST", $"{endpoint.ContainerHost}:{endpoint.Port}");
context.EnvironmentVariables.Add("PMA_HOST", $"{endpoint.ContainerHost}:{endpoint.ContainerPort}");
context.EnvironmentVariables.Add("PMA_USER", "root");
context.EnvironmentVariables.Add("PMA_PASSWORD", singleInstance.PasswordParameter.Value);
});
Expand All @@ -127,7 +127,7 @@ public static IResourceBuilder<T> WithPhpMyAdmin<T>(this IResourceBuilder<T> bui
{
var endpoint = mySqlInstance.PrimaryEndpoint;
writer.WriteLine("$i++;");
writer.WriteLine($"$cfg['Servers'][$i]['host'] = '{endpoint.ContainerHost}:{endpoint.Port}';");
writer.WriteLine($"$cfg['Servers'][$i]['host'] = '{endpoint.ContainerHost}:{endpoint.ContainerPort}';");
writer.WriteLine($"$cfg['Servers'][$i]['verbose'] = '{mySqlInstance.Name}';");
writer.WriteLine($"$cfg['Servers'][$i]['auth_type'] = 'cookie';");
writer.WriteLine($"$cfg['Servers'][$i]['user'] = 'root';");
Expand Down Expand Up @@ -157,7 +157,7 @@ public static IResourceBuilder<T> WithPhpMyAdmin<T>(this IResourceBuilder<T> bui
public static IResourceBuilder<PhpMyAdminContainerResource> WithHostPort(this IResourceBuilder<PhpMyAdminContainerResource> builder, int? port)
{
ArgumentNullException.ThrowIfNull(builder);

return builder.WithEndpoint("http", endpoint =>
{
endpoint.Port = port;
Expand Down
10 changes: 5 additions & 5 deletions src/Aspire.Hosting.PostgreSQL/PostgresBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ public static IResourceBuilder<T> WithPgAdmin<T>(this IResourceBuilder<T> builde
writer.WriteString("Name", postgresInstance.Name);
writer.WriteString("Group", "Servers");
writer.WriteString("Host", endpoint.ContainerHost);
writer.WriteNumber("Port", endpoint.Port);
writer.WriteNumber("Port", (decimal)endpoint.ContainerPort!);
danegsta marked this conversation as resolved.
Show resolved Hide resolved
writer.WriteString("Username", "postgres");
writer.WriteString("SSLMode", "prefer");
writer.WriteString("MaintenanceDB", "postgres");
Expand Down Expand Up @@ -269,11 +269,11 @@ public static IResourceBuilder<PgWebContainerResource> WithHostPort(this IResour
/// var postgres = builder.AddPostgres("postgres")
/// .WithPgWeb();
/// var db = postgres.AddDatabase("db");
///
///
/// var api = builder.AddProject&lt;Projects.Api&gt;("api")
/// .WithReference(db);
///
/// builder.Build().Run();
///
/// builder.Build().Run();
/// </code>
/// </example>
/// <remarks>
Expand Down Expand Up @@ -322,7 +322,7 @@ public static IResourceBuilder<PostgresServerResource> WithPgWeb(this IResourceB

var fileContent = $"""
host = "{postgresDatabase.Parent.PrimaryEndpoint.ContainerHost}"
port = {postgresDatabase.Parent.PrimaryEndpoint.Port}
port = {postgresDatabase.Parent.PrimaryEndpoint.ContainerPort}
user = "{user}"
password = "{postgresDatabase.Parent.PasswordParameter.Value}"
database = "{postgresDatabase.DatabaseName}"
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Hosting.Redis/RedisBuilderExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public static IResourceBuilder<RedisResource> WithRedisCommander(this IResourceB
{
if (redisInstance.PrimaryEndpoint.IsAllocated)
{
var hostString = $"{(hostsVariableBuilder.Length > 0 ? "," : string.Empty)}{redisInstance.Name}:{redisInstance.PrimaryEndpoint.ContainerHost}:{redisInstance.PrimaryEndpoint.Port}:0";
var hostString = $"{(hostsVariableBuilder.Length > 0 ? "," : string.Empty)}{redisInstance.Name}:{redisInstance.PrimaryEndpoint.ContainerHost}:{redisInstance.PrimaryEndpoint.ContainerPort}:0";
hostsVariableBuilder.Append(hostString);
}
}
Expand Down
23 changes: 22 additions & 1 deletion src/Aspire.Hosting/ApplicationModel/EndpointReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ internal string GetExpression(EndpointProperty property = EndpointProperty.Url)
EndpointProperty.Port => "port",
EndpointProperty.Scheme => "scheme",
EndpointProperty.TargetPort => "targetPort",
EndpointProperty.ContainerPort => "containerPort",
danegsta marked this conversation as resolved.
Show resolved Hide resolved
_ => throw new InvalidOperationException($"The property '{property}' is not supported for the endpoint '{EndpointName}'.")
};

Expand All @@ -81,6 +82,11 @@ public EndpointReferenceExpression Property(EndpointProperty property)
/// </summary>
public int? TargetPort => EndpointAnnotation.TargetPort;

/// <summary>
/// Returns the port to use when referencing this endpoint from a container.
/// </summary>
public int? ContainerPort => Resource.IsContainer() ? EndpointAnnotation.TargetPort : AllocatedEndpoint.Port;
danegsta marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Gets the host for this endpoint.
/// </summary>
Expand Down Expand Up @@ -177,6 +183,7 @@ public class EndpointReferenceExpression(EndpointReference endpointReference, En
EndpointProperty.Port => new(Endpoint.Port.ToString(CultureInfo.InvariantCulture)),
EndpointProperty.Scheme => new(Endpoint.Scheme),
EndpointProperty.TargetPort => new(ComputeTargetPort()),
EndpointProperty.ContainerPort => new(ComputeContainerPort()),
_ => throw new InvalidOperationException($"The property '{Property}' is not supported for the endpoint '{Endpoint.EndpointName}'.")
};

Expand All @@ -195,6 +202,16 @@ public class EndpointReferenceExpression(EndpointReference endpointReference, En
?? throw new InvalidOperationException("The endpoint does not have an associated TargetPortExpression from the orchestrator.");
}

private string? ComputeContainerPort()
{
if (Endpoint.Resource.IsContainer())
{
return ComputeTargetPort();
}

return Endpoint.Port.ToString(CultureInfo.InvariantCulture);
}

IEnumerable<object> IValueWithReferences.References => [Endpoint];
}

Expand Down Expand Up @@ -226,5 +243,9 @@ public enum EndpointProperty
/// <summary>
/// The target port of the endpoint.
/// </summary>
TargetPort
TargetPort,
/// <summary>
/// The port of the endpoint when consumed from a container
/// </summary>
ContainerPort,
}
39 changes: 39 additions & 0 deletions src/Aspire.Hosting/Dcp/ApplicationExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ public async Task RunApplicationAsync(CancellationToken cancellationToken = defa

await CreateServicesAsync(cancellationToken).ConfigureAwait(false);

await CreateContainerNetworksAsync(cancellationToken).ConfigureAwait(false);

await CreateContainersAndExecutablesAsync(cancellationToken).ConfigureAwait(false);

var afterResourcesCreatedEvent = new AfterResourcesCreatedEvent(serviceProvider, _model);
Expand Down Expand Up @@ -889,6 +891,18 @@ await execution.ExecuteAsync(async (attemptCancellationToken) =>
}
}

private async Task CreateContainerNetworksAsync(CancellationToken cancellationToken)
{
var toCreate = _appResources.Where(r => r.DcpResource is ContainerNetwork);
foreach (var containerNetwork in toCreate)
{
if (containerNetwork.DcpResource is ContainerNetwork cn)
{
await kubernetesService.CreateAsync(cn, cancellationToken).ConfigureAwait(false);
}
}
}

private async Task CreateContainersAndExecutablesAsync(CancellationToken cancellationToken)
{
var toCreate = _appResources.Where(r => r.DcpResource is Container || r.DcpResource is Executable || r.DcpResource is ExecutableReplicaSet);
Expand All @@ -914,6 +928,14 @@ private void AddAllocatedEndpointInfo(IEnumerable<AppResource> resources)

foreach (var appResource in resources)
{
if (appResource.DcpResource is Container container)
{
if (container.Spec.Networks?.Any() == true)
{
containerHost = appResource.ModelResource.Name;
danegsta marked this conversation as resolved.
Show resolved Hide resolved
}
}

foreach (var sp in appResource.ServicesProduced)
{
var svc = (Service)sp.DcpResource;
Expand Down Expand Up @@ -1377,6 +1399,15 @@ private void PrepareContainers()
}
}

ctr.Spec.Networks = new List<ContainerNetworkConnection>
{
new ContainerNetworkConnection
{
Name = "aspire-network",
Aliases = new List<string> { container.Name },
}
};

var containerAppResource = new AppResource(container, ctr);
AddServicesProducedInfo(container, ctr, containerAppResource);
_appResources.Add(containerAppResource);
Expand Down Expand Up @@ -1427,6 +1458,14 @@ await notificationService.PublishUpdateAsync(cr.ModelResource, s => s with
}

var tasks = new List<Task>();

// Create a custom container network for Aspire if there are container resources
if (containerResources.Any())
{
// The network will be created with a unique postfix to avoid conflicts with other Aspire AppHost networks
tasks.Add(kubernetesService.CreateAsync(ContainerNetwork.Create("aspire-network"), cancellationToken));
}

foreach (var cr in containerResources)
{
tasks.Add(CreateContainerAsyncCore(cr, cancellationToken));
Expand Down
1 change: 1 addition & 0 deletions src/Aspire.Hosting/Dcp/Model/GroupVersion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ static Dcp()
{
Schema.Add<Executable>(ExecutableKind, "executables");
Schema.Add<Container>(ContainerKind, "containers");
Schema.Add<ContainerNetwork>(ContainerNetworkKind, "containernetworks");
Schema.Add<Service>(ServiceKind, "services");
Schema.Add<Endpoint>(EndpointKind, "endpoints");
Schema.Add<ExecutableReplicaSet>(ExecutableReplicaSetKind, "executablereplicasets");
Expand Down
2 changes: 1 addition & 1 deletion src/Aspire.Hosting/Dcp/Model/Network.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public ContainerNetwork(ContainerNetworkSpec spec) : base(spec) { }

public static ContainerNetwork Create(string name, bool useIpV6 = false)
{
var c = new ContainerNetwork(new ContainerNetworkSpec { NetworkName = name, IPV6 = useIpV6 });
var c = new ContainerNetwork(new ContainerNetworkSpec { IPV6 = useIpV6 });

c.Kind = Dcp.ContainerNetworkKind;
c.ApiVersion = Dcp.GroupVersion.ToString();
Expand Down
2 changes: 2 additions & 0 deletions src/Aspire.Hosting/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Aspire.Hosting.ApplicationModel.ContainerLifetimeType.Default = 0 -> Aspire.Host
Aspire.Hosting.ApplicationModel.ContainerLifetimeType.Persistent = 1 -> Aspire.Hosting.ApplicationModel.ContainerLifetimeType
Aspire.Hosting.ApplicationModel.CustomResourceSnapshot.HealthStatus.get -> Microsoft.Extensions.Diagnostics.HealthChecks.HealthStatus?
Aspire.Hosting.ApplicationModel.CustomResourceSnapshot.HealthStatus.init -> void
Aspire.Hosting.ApplicationModel.EndpointProperty.ContainerPort = 6 -> Aspire.Hosting.ApplicationModel.EndpointProperty
Aspire.Hosting.ApplicationModel.EndpointReference.ContainerPort.get -> int?
Aspire.Hosting.ApplicationModel.HealthCheckAnnotation
Aspire.Hosting.ApplicationModel.HealthCheckAnnotation.HealthCheckAnnotation(string! key) -> void
Aspire.Hosting.ApplicationModel.HealthCheckAnnotation.Key.get -> string!
Expand Down
2 changes: 1 addition & 1 deletion tests/Aspire.Hosting.PostgreSQL.Tests/AddPostgresTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ private static string CreatePgWebBookmarkfileContent(PostgresDatabaseResource po

var fileContent = $"""
host = "{postgresDatabase.Parent.PrimaryEndpoint.ContainerHost}"
port = {postgresDatabase.Parent.PrimaryEndpoint.Port}
port = {postgresDatabase.Parent.PrimaryEndpoint.ContainerPort}
user = "{user}"
password = "{postgresDatabase.Parent.PasswordParameter.Value}"
database = "{postgresDatabase.DatabaseName}"
Expand Down