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

Extending Aspire orchestration capability to Java-based apps #4491

Open
justinyoo opened this issue Jun 13, 2024 · 7 comments
Open

Extending Aspire orchestration capability to Java-based apps #4491

justinyoo opened this issue Jun 13, 2024 · 7 comments
Labels
area-app-model Issues pertaining to the APIs in Aspire.Hosting, e.g. DistributedApplication feature A single user-facing feature. Can be grouped under an epic.
Milestone

Comments

@justinyoo
Copy link

Background and Motivation

.NET Aspire, as an orchestration engine to build a clound-native application, is capable of bringing other type of applications written in different language like Java (Spring Boot for example). The current API offers both .AddContainer(...) and .AddExecutable(...) for the generic purpose.

However, it would be great if we can provide Java-specific extension methods like AddJavaApp(...) for generic Java app and AddSpringApp(...) for Spring-focused app, as we provide AddNodeApp(...) and AddNpmApp(...).

By doing so, we can wrap Java-specific arguments pre-built so that devs only focus on passing arguments they really need.

I've PoC'd for this suggestion here: https://github.com/aliencube/aspire-contribs/tree/main/src/Aspire.Contribs.Hosting.Java

Proposed API

I've got two API suggestions – one based on ExecutableResource and the other based on ContainerResource.

ExecutableResource-based API

  • It's good for the Java app is in the same repository.
  • It's easily built and orchestrated with the existing PublishAsDockerfile(...) method.
  • It's not easy to handle the Java app outside the .NET Aspire-based repository.
public static class JavaAppHostingExtension
{
    // Add Java app
    public static IResourceBuilder<JavaAppExecutableResource> AddJavaApp(
        this IDistributedApplicationBuilder builder,
        string name,
        string workingDirectory,
        JavaAppExecutableResourceOptions options)
    {

    // Add Spring app
    public static IResourceBuilder<JavaAppExecutableResource> AddSpringApp(
        this IDistributedApplicationBuilder builder,
        string name,
        string workingDirectory,
        JavaAppExecutableResourceOptions options)
    {

ContainerResource-based API

  • It's good for the Java app is outside the .NET Aspire-based repository. I think this is mostly the case.
  • It's good for existing Java app container images already published to a container registry.
public static class JavaAppHostingExtension
{
    // Add Java app
    public static IResourceBuilder<JavaAppContainerResource> AddJavaApp(
        this IDistributedApplicationBuilder builder,
        string name,
        JavaAppContainerResourceOptions options)
    {

    // Add Spring app
    public static IResourceBuilder<JavaAppContainerResource> AddSpringApp(
        this IDistributedApplicationBuilder builder,
        string name,
        JavaAppContainerResourceOptions options)
    {

I'd also like to introduce the options pattern here to pass some common options like:

// JavaAppExecutableResourceOptions
public class JavaAppExecutableResourceOptions
{
    public string? ApplicationName { get; set; } = "target/app.jar";
    public int Port { get; set; } = 8080;
    public string? OtelAgentPath { get; set; } = null;
    public string[]? Args { get; set; } = null;
}

// JavaAppContainerResourceOptions
public class JavaAppContainerResourceOptions
{
    public string? ContainerRegistry { get; set; } = "docker.io";
    public string? ContainerImageName { get; set; }
    public string ContainerImageTag { get; set; } = "latest";
    public int Port { get; set; } = 8080;
    public int TargetPort { get; set; } = 8080;
    public string? OtelAgentPath { get; set; } = null;
    public string[]? Args { get; set; } = null;
}

NOTE that the OtelAgentPath should be provided for Java app to be OpenTelemetry-able.

Therefore, based on the options instance, devs call the same method, AddSpringApp(...), and the method uses either container or executable.

Usage Examples

With this API suggestion, devs can orchestrate like this:

var containerapp = builder.AddSpringApp(
                              "containerapp",
                              new JavaAppContainerResourceOptions()
                              {
                                  ContainerRegistry = "docker.io",
                                  ContainerImageName = "my-org/my-spring-app",
                                  Port = 8080,
                                  TargetPort = 8080,
                                  OtelAgentPath = "/agents"
                              });

var executableapp = builder.AddSpringApp(
                               "executableapp",
                               workingDirectory: "../Aspire.Contribs.Spring.Maven",
                               new JavaAppExecutableResourceOptions()
                               {
                                   ApplicationName = "target/spring-maven-0.0.1-SNAPSHOT.jar",
                                   Port = 8085,
                                   OtelAgentPath = "../../agents",
                               });

var webapp = builder.AddProject<Projects.Aspire_Contribs_WebApp>("webapp")
                    .WithExternalHttpEndpoints()
                    .WithReference(containerapp)
                    .WithReference(executableapp)
                    .WithReference(apiapp);

Alternative Designs

Risks

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-app-model Issues pertaining to the APIs in Aspire.Hosting, e.g. DistributedApplication label Jun 13, 2024
@davidfowl davidfowl added the feature A single user-facing feature. Can be grouped under an epic. label Jun 13, 2024
@davidfowl davidfowl added this to the Backlog milestone Jun 13, 2024
@davidfowl
Copy link
Member

I think we need to unify the resource types:

  1. I want to be able to run a spring app as a java process
  2. I want to be able to run a spring app in a container
  3. I want to publish a spring app as a container

We have a pattern for 1 and 3 today, this new resource type is number 2. I wonder if there's a way we can represent number 2 without a split resource type.

The other thing I would mention is that that the options object is a bit different from our existing builder pattern API (not sure if it's a bad thing). Feels similar to #4472 for .NET project resources. There needs to be a way to say, use this endpoint name as the spring boot server port.

I'd like @mitchdenny's take on this.

@justinyoo
Copy link
Author

  1. I want to be able to run a spring app as a java process
  2. I want to be able to run a spring app in a container
  3. I want to publish a spring app as a container

Currently, the .AddExecutable(...) method supports the pattern 1, and the .AddContainer(...) method supports the pattern 3. For the pattern 2, it's already published to a container registry, and we can simply refer it. My gut feeling is that both pattern 2 and 3 can be consolidated, as long as the pattern 2 has a Dockerfile. Let me double check on my end.

The other thing I would mention is that that the options object is a bit different from our existing builder pattern API (not sure if it's a bad thing). Feels similar to #4472 for .NET project resources. There needs to be a way to say, use this endpoint name as the spring boot server port.

The introduction of the ...Options class is merely to simplify the number of commonly used arguments.

For the executable (pattern 1), it always uses server port and OTEL agent JAR file path with slight variations like port number value and agent path value.

For the container (pattern 3), yeah, I kind of agree it depends on the existing Dockerfile structure, it may not be necessary. But for the pattern 2, it may be necessary. Let me take a look.

@justinyoo
Copy link
Author

I did a few experiments for the pattern 2 and 3 and it really depends on how the container image has been built. Therefore, providing the ...Options class as a collection of common values wouldn't make sense.

For the pattern 1, I also think it's reasonable to leave devs to pass their arguments including the OTEL agent JAR file path, instead of using that ...Options class.

Thinking of the pattern 3, though, it's only valid if the Spring app is under the same repo where .AppHost project is located.

@mitchdenny
Copy link
Member

I'd like @mitchdenny's take on this.

I'm starting to think that we have a WithDockerfile extension method which works with IResourceBuilder<ExecutableResource> which effectively results in a container resource being created in the manifest (impacts run mode as well).

@justinyoo
Copy link
Author

Now, we can add Python app to .NET Aspire

#4142

Can Java follow the similar process?

@mitchdenny
Copy link
Member

@justinyoo absolutely!

@thangchung
Copy link

Now, we can add Python app to .NET Aspire

#4142

Can Java follow the similar process?

+1 for adding Java supports

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-app-model Issues pertaining to the APIs in Aspire.Hosting, e.g. DistributedApplication feature A single user-facing feature. Can be grouped under an epic.
Projects
None yet
Development

No branches or pull requests

4 participants