feat: add docker compose deployment to aspire host

This commit is contained in:
Meysam Hadeli 2025-07-29 23:13:26 +03:30
parent b9e1a1b949
commit 3bd8cb1db3
6 changed files with 229 additions and 66 deletions

3
.aspire/settings.json Normal file
View File

@ -0,0 +1,3 @@
{
"appHostPath": "../src/Aspire/src/AppHost/AppHost.csproj"
}

View File

@ -15,6 +15,13 @@
"dotnet-ef"
],
"rollForward": false
},
"aspire.cli": {
"version": "9.4.0-preview.1.25378.8",
"commands": [
"aspire"
],
"rollForward": false
}
}
}

View File

@ -455,6 +455,8 @@ dotnet_diagnostic.CA1707.severity = None
dotnet_diagnostic.CA1716.severity = Suggestion
# CA1032: Implement standard exception constructors
dotnet_diagnostic.CA1032.severity = Suggestion
# AV1500: A method should not exceed a predefined number (60-100 lines) of lines
dotnet_diagnostic.AV1500.severity = none
##################################################################################
# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/

View File

@ -217,13 +217,13 @@ dotnet dev-certs https --trust
### Aspire
To run the application using the `ASPIRE App Host`, execute the following command from the solution root:
To run the application using the `Aspire App Host`, execute the following command from the solution root:
```bash
dotnet run --project ./src/Aspire/src/AppHost
aspire run
```
> Note:The `ASPIRE dashboard` will be available at `http://localhost:18888`
> Note:The `Aspire dashboard` will be available at `http://localhost:18888`
> ### Docker Compose

View File

@ -13,6 +13,7 @@
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.3.1" />
<PackageReference Include="Aspire.Hosting.Docker" Version="9.3.1-preview.1.25305.6" />
<PackageReference Include="Aspire.Hosting.MongoDB" Version="9.3.1" />
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="9.3.1" />
<PackageReference Include="Aspire.Hosting.RabbitMQ" Version="9.3.1" />

View File

@ -2,39 +2,82 @@ using System.Net.Sockets;
var builder = DistributedApplication.CreateBuilder(args);
// 1. Database Services
var username = builder.AddParameter("username", "postgres", secret: true);
var password = builder.AddParameter("password", "postgres", secret: true);
builder.AddDockerComposeEnvironment("docker-compose");
var postgres = builder.AddPostgres("postgres", username, password)
// 1. Database Services
var pgUsername = builder.AddParameter("pg-username", "postgres", secret: true);
var pgPassword = builder.AddParameter("pg-password", "postgres", secret: true);
var postgres = builder.AddPostgres("postgres", pgUsername, pgPassword)
.WithImage("postgres:latest")
.WithEndpoint(port: 5432, targetPort: 5432, name: "postgres")
.WithEndpoint(
"tcp",
e =>
{
e.Port = 5432;
e.TargetPort = 5432;
e.IsProxied = true;
e.IsExternal = false;
})
.WithArgs(
"-c", "wal_level=logical",
"-c", "max_prepared_transactions=10"
)
.WithDataVolume("postgres-data")
.WithLifetime(ContainerLifetime.Persistent);
"-c",
"wal_level=logical",
"-c",
"max_prepared_transactions=10");
if (builder.ExecutionContext.IsPublishMode)
{
postgres.WithDataVolume("postgres-data")
.WithLifetime(ContainerLifetime.Persistent);
}
var flightDb = postgres.AddDatabase("flight");
var passengerDb = postgres.AddDatabase("passenger");
var identityDb = postgres.AddDatabase("identity");
var persistMessageDb = postgres.AddDatabase("persist-message");
var mongoUsername = builder.AddParameter("mongo-username", "root");
var mongoUsername = builder.AddParameter("mongo-username", "root", secret: true);
var mongoPassword = builder.AddParameter("mongo-password", "secret", secret: true);
var mongo = builder.AddMongoDB("mongo", userName: mongoUsername, password: mongoPassword)
.WithImage("mongo:latest")
.WithEndpoint(port: 27017, targetPort: 27017, name: "mongo")
.WithDataVolume("mongo-data")
.WithLifetime(ContainerLifetime.Persistent);
.WithImage("mongo")
.WithImageTag("latest")
.WithEndpoint(
"tcp",
e =>
{
e.Port = 27017;
e.TargetPort = 27017;
e.IsProxied = true;
e.IsExternal = false;
});
if (builder.ExecutionContext.IsPublishMode)
{
mongo.WithDataVolume("mongo-data")
.WithLifetime(ContainerLifetime.Persistent);
}
var redis = builder.AddRedis("redis")
.WithImage("redis:latest")
.WithEndpoint(port: 6379, targetPort: 6379, name: "redis")
.WithDataVolume("redis-data")
.WithLifetime(ContainerLifetime.Persistent);
.WithEndpoint(
"tcp",
e =>
{
e.Port = 6379;
e.TargetPort = 6379;
e.IsProxied = true;
e.IsExternal = false;
});
if (builder.ExecutionContext.IsPublishMode)
{
redis.WithDataVolume("redis-data")
.WithLifetime(ContainerLifetime.Persistent);
}
var eventstore = builder.AddEventStore("eventstore")
.WithImage("eventstore/eventstore")
@ -43,41 +86,103 @@ var eventstore = builder.AddEventStore("eventstore")
.WithEnvironment("EVENTSTORE_START_STANDARD_PROJECTIONS", "True")
.WithEnvironment("EVENTSTORE_INSECURE", "True")
.WithEnvironment("EVENTSTORE_ENABLE_ATOM_PUB_OVER_HTTP", "True")
.WithHttpEndpoint(port: 2113, targetPort: 2113, name: "eventstore-http")
.WithDataVolume("eventstore-data")
.WithLifetime(ContainerLifetime.Persistent);
.WithEndpoint(
"http",
e =>
{
e.TargetPort = 2113;
e.Port = 2113;
e.IsProxied = true;
e.IsExternal = true;
})
.WithEndpoint(
port: 1113,
targetPort: 1113,
name: "tcp",
isProxied: true,
isExternal: false);
if (builder.ExecutionContext.IsPublishMode)
{
eventstore.WithDataVolume("eventstore-data")
.WithLifetime(ContainerLifetime.Persistent);
}
// 2. Messaging Services
var rabbitmq = builder.AddRabbitMQ("rabbitmq")
.WithImage("rabbitmq:management")
.WithEndpoint(port: 5672, targetPort: 5672, name: "rabbitmq-amqp")
.WithEndpoint(port: 15672, targetPort: 15672, name: "rabbitmq-management")
.WithLifetime(ContainerLifetime.Persistent);
var rabbitmqUsername = builder.AddParameter("rabbitmq-username", "guest", secret: true);
var rabbitmqPassword = builder.AddParameter("rabbitmq-password", "guest", secret: true);
// 3. Observability Services
var rabbitmq = builder.AddRabbitMQ("rabbitmq", rabbitmqUsername, rabbitmqPassword)
.WithManagementPlugin()
.WithEndpoint(
"tcp",
e =>
{
e.TargetPort = 5672;
e.Port = 5672;
e.IsProxied = true;
e.IsExternal = false;
})
.WithEndpoint(
"management",
e =>
{
e.TargetPort = 15672;
e.Port = 15672;
e.IsProxied = true;
e.IsExternal = true;
});
if (builder.ExecutionContext.IsPublishMode)
{
rabbitmq.WithLifetime(ContainerLifetime.Persistent);
}
// // 3. Observability Services
var jaeger = builder.AddContainer("jaeger-all-in-one", "jaegertracing/all-in-one")
.WithEndpoint(port: 6831, targetPort: 6831, name: "jaeger-udp", protocol: ProtocolType.Udp)
.WithEndpoint(port: 16686, targetPort: 16686, name: "jaeger-ui")
.WithEndpoint(port: 14268, targetPort: 14268, name: "jaeger-api")
.WithEndpoint(port: 14317, targetPort: 4317, name: "jaeger-otlp-grpc")
.WithEndpoint(port: 14318, targetPort: 4318, name: "jaeger-otlp-http")
.WithLifetime(ContainerLifetime.Persistent);
.WithEndpoint(
port: 6831,
targetPort: 6831,
name: "agent",
protocol: ProtocolType.Udp,
isProxied: true,
isExternal: false)
.WithEndpoint(port: 16686, targetPort: 16686, name: "http", isProxied: true, isExternal: true)
.WithEndpoint(port: 14268, targetPort: 14268, name: "collector", isProxied: true, isExternal: false)
.WithEndpoint(port: 14317, targetPort: 4317, name: "otlp-grpc", isProxied: true, isExternal: false)
.WithEndpoint(port: 14318, targetPort: 4318, name: "otlp-http", isProxied: true, isExternal: false);
if (builder.ExecutionContext.IsPublishMode)
{
jaeger.WithLifetime(ContainerLifetime.Persistent);
}
var zipkin = builder.AddContainer("zipkin-all-in-one", "openzipkin/zipkin")
.WithEndpoint(port: 9411, targetPort: 9411, name: "zipkin-api")
.WithLifetime(ContainerLifetime.Persistent);
.WithEndpoint(port: 9411, targetPort: 9411, name: "http", isProxied: true, isExternal: true);
if (builder.ExecutionContext.IsPublishMode)
{
zipkin.WithLifetime(ContainerLifetime.Persistent);
}
var otelCollector = builder.AddContainer("otel-collector", "otel/opentelemetry-collector-contrib")
.WithBindMount("../../../../deployments/configs/otel-collector-config.yaml", "/etc/otelcol-contrib/config.yaml", isReadOnly: true)
.WithBindMount(
"../../../../deployments/configs/otel-collector-config.yaml",
"/etc/otelcol-contrib/config.yaml",
isReadOnly: true)
.WithArgs("--config=/etc/otelcol-contrib/config.yaml")
.WithEndpoint(port: 11888, targetPort: 1888, name: "otel-pprof")
.WithEndpoint(port: 8888, targetPort: 8888, name: "otel-metrics")
.WithEndpoint(port: 8889, targetPort: 8889, name: "otel-exporter-metrics")
.WithEndpoint(port: 13133, targetPort: 13133, name: "otel-health")
.WithEndpoint(port: 4317, targetPort: 4317, name: "otel-grpc")
.WithEndpoint(port: 4318, targetPort: 4318, name: "otel-http")
.WithEndpoint(port: 55679, targetPort: 55679, name: "otel-zpages")
.WithLifetime(ContainerLifetime.Persistent);
.WithEndpoint(port: 11888, targetPort: 1888, name: "otel-pprof", isProxied: true, isExternal: true)
.WithEndpoint(port: 8888, targetPort: 8888, name: "otel-metrics", isProxied: true, isExternal: true)
.WithEndpoint(port: 8889, targetPort: 8889, name: "otel-exporter-metrics", isProxied: true, isExternal: true)
.WithEndpoint(port: 13133, targetPort: 13133, name: "otel-health", isProxied: true, isExternal: true)
.WithEndpoint(port: 4317, targetPort: 4317, name: "otel-grpc", isProxied: true, isExternal: true)
.WithEndpoint(port: 4318, targetPort: 4318, name: "otel-http", isProxied: true, isExternal: true)
.WithEndpoint(port: 55679, targetPort: 55679, name: "otel-zpages", isProxied: true, isExternal: true);
if (builder.ExecutionContext.IsPublishMode)
{
otelCollector.WithLifetime(ContainerLifetime.Persistent);
}
var prometheus = builder.AddContainer("prometheus", "prom/prometheus")
.WithBindMount("../../../../deployments/configs/prometheus.yaml", "/etc/prometheus/prometheus.yml")
@ -87,8 +192,12 @@ var prometheus = builder.AddContainer("prometheus", "prom/prometheus")
"--web.console.libraries=/usr/share/prometheus/console_libraries",
"--web.console.templates=/usr/share/prometheus/consoles",
"--web.enable-remote-write-receiver")
.WithEndpoint(port: 9090, targetPort: 9090, name: "prometheus-web")
.WithLifetime(ContainerLifetime.Persistent);
.WithEndpoint(port: 9090, targetPort: 9090, name: "http", isProxied: true, isExternal: true);
if (builder.ExecutionContext.IsPublishMode)
{
prometheus.WithLifetime(ContainerLifetime.Persistent);
}
var grafana = builder.AddContainer("grafana", "grafana/grafana")
.WithEnvironment("GF_INSTALL_PLUGINS", "grafana-clock-panel,grafana-simple-json-datasource")
@ -97,8 +206,12 @@ var grafana = builder.AddContainer("grafana", "grafana/grafana")
.WithEnvironment("GF_FEATURE_TOGGLES_ENABLE", "traceqlEditor")
.WithBindMount("../../../../deployments/configs/grafana/provisioning", "/etc/grafana/provisioning")
.WithBindMount("../../../../deployments/configs/grafana/dashboards", "/var/lib/grafana/dashboards")
.WithEndpoint(port: 3000, targetPort: 3000, name: "grafana-web")
.WithLifetime(ContainerLifetime.Persistent);
.WithEndpoint(port: 3000, targetPort: 3000, name: "http", isProxied: true, isExternal: true);
if (builder.ExecutionContext.IsPublishMode)
{
grafana.WithLifetime(ContainerLifetime.Persistent);
}
var nodeExporter = builder.AddContainer("node-exporter", "prom/node-exporter")
.WithBindMount("/proc", "/host/proc", isReadOnly: true)
@ -108,22 +221,36 @@ var nodeExporter = builder.AddContainer("node-exporter", "prom/node-exporter")
"--path.procfs=/host/proc",
"--path.rootfs=/rootfs",
"--path.sysfs=/host/sys")
.WithEndpoint(port: 9101, targetPort: 9100, name: "node-exporter")
.WithLifetime(ContainerLifetime.Persistent);
.WithEndpoint(port: 9101, targetPort: 9100, name: "http", isProxied: true, isExternal: true);
if (builder.ExecutionContext.IsPublishMode)
{
nodeExporter.WithLifetime(ContainerLifetime.Persistent);
}
var tempo = builder.AddContainer("tempo", "grafana/tempo")
.WithBindMount("../../../../deployments/configs/tempo.yaml", "/etc/tempo.yaml", isReadOnly: true)
.WithArgs("--config.file=/etc/tempo.yaml")
.WithEndpoint(port: 3200, targetPort: 3200, name: "tempo")
.WithEndpoint(port: 24317, targetPort: 4317, name: "tempo-otlp-grpc")
.WithEndpoint(port: 24318, targetPort: 4318, name: "tempo-otlp-http")
.WithLifetime(ContainerLifetime.Persistent);
.WithEndpoint(port: 3200, targetPort: 3200, name: "http", isProxied: true, isExternal: false)
.WithEndpoint(port: 9095, targetPort: 9095, name: "grpc", isProxied: true, isExternal: false)
.WithEndpoint(port: 4317, targetPort: 4317, name: "otlp-grpc", isProxied: true, isExternal: false)
.WithEndpoint(port: 4318, targetPort: 4318, name: "otlp-http", isProxied: true, isExternal: false);
if (builder.ExecutionContext.IsPublishMode)
{
tempo.WithLifetime(ContainerLifetime.Persistent);
}
var loki = builder.AddContainer("loki", "grafana/loki")
.WithBindMount("../../../../deployments/configs/loki-config.yaml", "/etc/loki/local-config.yaml", isReadOnly: true)
.WithArgs("-config.file=/etc/loki/local-config.yaml")
.WithEndpoint(port: 3100, targetPort: 3100, name: "loki")
.WithLifetime(ContainerLifetime.Persistent);
.WithEndpoint(port: 3100, targetPort: 3100, name: "http", isProxied: true, isExternal: false)
.WithEndpoint(port: 9096, targetPort: 9096, name: "grpc", isProxied: true, isExternal: false);
if (builder.ExecutionContext.IsPublishMode)
{
loki.WithLifetime(ContainerLifetime.Persistent);
}
var elasticsearch = builder.AddElasticsearch("elasticsearch")
.WithImage("docker.elastic.co/elasticsearch/elasticsearch:8.17.0")
@ -139,18 +266,41 @@ var elasticsearch = builder.AddElasticsearch("elasticsearch")
.WithEnvironment("transport.host", "localhost")
.WithEnvironment("bootstrap.memory_lock", "true")
.WithEnvironment("cluster.routing.allocation.disk.threshold_enabled", "false")
.WithEndpoint(port: 9200, targetPort: 9200, name: "elasticsearch-http")
.WithEndpoint(port: 9300, targetPort: 9300, name: "elasticsearch-transport")
.WithDataVolume("elastic-data")
.WithLifetime(ContainerLifetime.Persistent);
.WithEndpoint(
"http",
e =>
{
e.TargetPort = 9200;
e.Port = 9200;
e.IsProxied = true;
e.IsExternal = false;
})
.WithEndpoint(
"internal",
e =>
{
e.TargetPort = 9300;
e.Port = 9300;
e.IsProxied = true;
e.IsExternal = false;
})
.WithDataVolume("elastic-data");
if (builder.ExecutionContext.IsPublishMode)
{
elasticsearch.WithLifetime(ContainerLifetime.Persistent);
}
var kibana = builder.AddContainer("kibana", "docker.elastic.co/kibana/kibana:8.17.0")
.WithEnvironment("ELASTICSEARCH_HOSTS", "http://elasticsearch:9200")
.WithEndpoint(port: 5601, targetPort: 5601, name: "kibana")
.WithEndpoint(port: 5601, targetPort: 5601, name: "http", isProxied: true, isExternal: true)
.WithReference(elasticsearch)
.WaitFor(elasticsearch)
.WithLifetime(ContainerLifetime.Persistent);
.WaitFor(elasticsearch);
if (builder.ExecutionContext.IsPublishMode)
{
kibana.WithLifetime(ContainerLifetime.Persistent);
}
// 5. Application Services
var identity = builder.AddProject<Projects.Identity_Api>("identity-service")