Aspire 는 클라우드에서 분산 애플리케이션의 개발을 간소화하는 의견 스택입니다. Azure Functions와 Aspire를 통합하면 Aspire 앱 호스트의 일부로 Azure Functions .NET 프로젝트를 개발, 디버그 및 오케스트레이션할 수 있습니다.
필수 조건
Azure Functions를 Aspire와 함께 사용하기 위한 개발 환경을 설정합니다.
-
Aspire 필수 구성 요소를 설치합니다.
- Azure Functions 통합을 완전히 지원하려면 Aspire 13.1 이상이 필요합니다. Aspire 13.0에는 라이브로 지원되는 릴리스 후보 역할을 하는 미리 보기 버전
Aspire.Hosting.Azure.Functions도 포함되어 있습니다.
- Azure Functions 통합을 완전히 지원하려면 Aspire 13.1 이상이 필요합니다. Aspire 13.0에는 라이브로 지원되는 릴리스 후보 역할을 하는 미리 보기 버전
- Azure Functions 핵심 도구를 설치합니다.
Visual Studio를 사용하는 경우 17.12 이상 버전으로 업데이트합니다. Visual Studio용 Azure Functions 도구의 최신 버전도 있어야 합니다. 업데이트를 확인하려면 다음을 수행합니다.
- 도구>옵션으로 이동합니다.
- 프로젝트 및 솔루션에서 Azure Functions를 선택합니다.
- 업데이트 확인을 선택하고 메시지가 표시되면 업데이트를 설치합니다.
솔루션 구조
Azure Functions 및 Aspire를 사용하는 솔루션에는 앱 호스트 프로젝트와 하나 이상의 Functions 프로젝트를 비롯한 여러 프로젝트가 있습니다.
앱 호스트 프로젝트는 애플리케이션의 진입점입니다. Functions 프로젝트를 포함하여 애플리케이션 구성 요소의 설정을 오케스트레이션합니다.
솔루션에는 일반적으로 서비스 기본 프로젝트 도 포함됩니다. 이 프로젝트는 애플리케이션의 프로젝트에서 사용할 기본 서비스 및 구성 집합을 제공합니다.
앱 호스트 프로젝트
통합을 성공적으로 구성하려면 앱 호스트 프로젝트가 다음 요구 사항을 충족하는지 확인합니다.
- 앱 호스트 프로젝트는 Aspire.Hosting.Azure.Functions를 참조해야 합니다. 이 패키지는 통합에 필요한 논리를 정의합니다.
- 앱 호스트 프로젝트에는 오케스트레이션에 포함하려는 각 Functions 프로젝트에 대한 프로젝트 참조가 있어야 합니다.
- 앱 호스트의
AppHost.cs파일에서AddAzureFunctionsProject<TProject>()인스턴스에 대해IDistributedApplicationBuilder을(를) 호출하여 프로젝트를 포함해야 합니다. Aspire의 다른 프로젝트 형식에 사용하는AddProject<TProject>()메서드 대신 이 메서드를 사용합니다. 만약AddProject<TProject>()를 사용하면, 해당 Functions 프로젝트를 제대로 시작할 수 없습니다.
다음 예제에서는 앱 호스트 프로젝트에 대한 최소 AppHost.cs 파일을 보여줍니다.
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject");
builder.Build().Run();
Azure Functions 프로젝트
통합을 성공적으로 구성하려면 Azure Functions 프로젝트가 다음 요구 사항을 충족하는지 확인합니다.
Functions 프로젝트는 Microsoft.Azure.Functions.Worker 및 Microsoft.Azure.Functions.Worker.Sdk의 2.x 버전을 참조해야 합니다. 또한 Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore 참조를 2.x 버전으로 업데이트해야 합니다.
Program.cs파일은IHostApplicationBuilder의 버전을 사용해야 합니다. 이 요구 사항은FunctionsApplication.CreateBuilder(args)을 사용해야 한다는 것을 의미합니다.솔루션에 서비스 기본 프로젝트가 포함된 경우 Functions 프로젝트가 이를 사용하도록 구성되어 있는지 확인합니다.
- Functions 프로젝트에는 서비스 기본 프로젝트에 대한 프로젝트 참조가 포함되어야 합니다.
-
IHostApplicationBuilder에서Program.cs를 빌드하기 전에builder.AddServiceDefaults()호출을 포함하도록 합니다.
다음 예제에서는 Aspire에서 사용되는 Functions 프로젝트에 대한 최소 Program.cs 파일을 보여 줍니다.
using Microsoft.Azure.Functions.Worker.Builder;
using Microsoft.Extensions.Hosting;
var builder = FunctionsApplication.CreateBuilder(args);
builder.AddServiceDefaults();
builder.ConfigureFunctionsWebApplication();
builder.Build().Run();
이 예제에는 다른 Program.cs 많은 예제 및 Azure Functions 템플릿에 표시되는 기본 Application Insights 구성이 포함되지 않습니다. 대신 메서드를 호출하여 Aspire에서 OpenTelemetry 통합을 구성합니다 builder.AddServiceDefaults .
통합을 최대한 활용하려면 다음 지침을 고려하세요.
- Functions 프로젝트에 직접 Application Insights 통합을 포함하지 마세요. Aspire의 모니터링은 대신 OpenTelemetry 지원을 통해 처리됩니다. 서비스 기본 프로젝트를 통해 Azure Monitor로 데이터를 내보내도록 Aspire를 구성할 수 있습니다.
- Functions 프로젝트에 대한 파일에서
local.settings.json사용자 지정 앱 설정을 정의하지 마세요.local.settings.json에 있어야 하는 유일한 설정은"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"입니다. 앱 호스트 프로젝트를 통해 다른 모든 앱 구성을 설정합니다.
Aspire를 사용하여 연결 구성
앱 호스트 프로젝트는 리소스를 정의하고 코드를 사용하여 리소스 간에 연결을 만드는 데 도움이 됩니다. 이 섹션에서는 Azure Functions 프로젝트에서 사용하는 연결을 구성하고 사용자 지정하는 방법을 보여 줍니다.
Aspire에는 시작하는 데 도움이 되는 기본 연결 권한이 포함됩니다. 그러나 이러한 권한은 애플리케이션에 적절하지 않거나 충분하지 않을 수 있습니다.
Azure RBAC(역할 기반 액세스 제어)를 사용하는 시나리오의 경우 프로젝트 리소스에 대한 메서드를 호출 WithRoleAssignments() 하여 권한을 사용자 지정할 수 있습니다. 호출 WithRoleAssignments()할 때 모든 기본 역할 할당이 제거되고 원하는 전체 집합 역할 할당을 명시적으로 정의해야 합니다. Azure Container Apps에서 애플리케이션을 호스트하는 경우 WithRoleAssignments()을 사용하는 것은 AddAzureContainerAppEnvironment()에서 DistributedApplicationBuilder을 호출해야 합니다.
Azure Functions 호스트 스토리지
Azure Functions에는 핵심 동작 중 일부를 위해 호스트 스토리지 연결(AzureWebJobsStorage)이 필요합니다. 앱 호스트 프로젝트에서 AddAzureFunctionsProject<TProject>()를 호출하면 기본적으로 AzureWebJobsStorage 연결이 생성되어 Functions 프로젝트에 제공됩니다. 이 기본 연결은 로컬 개발 실행에 Azure Storage 에뮬레이터를 사용하고 배포될 때 스토리지 계정을 자동으로 프로비전합니다. 더 많은 제어를 위해 Functions 프로젝트 리소스를 호출 .WithHostStorage() 하여 이 연결을 바꿀 수 있습니다.
호스트 스토리지 연결에 대해 Aspire가 설정하는 기본 권한은 호출 WithHostStorage() 여부에 따라 달라집니다. 추가 WithHostStorage() 하면 스토리지 계정 기여자 할당이 제거됩니다. 다음 표에서는 호스트 스토리지 연결에 대해 Aspire가 설정하는 기본 사용 권한을 나열합니다.
| 호스트 스토리지 연결 | 기본 역할 |
|---|---|
WithHostStorage()에 호출 없음 |
Storage Blob 데이터 기여자, Storage 큐 데이터 기여자, 스토리지 테이블 데이터 기여자 스토리지 계정 기여자 |
WithHostStorage() 호출 |
Storage Blob 데이터 기여자, Storage 큐 데이터 기여자, 스토리지 테이블 데이터 기여자 |
다음 예제에서는 호스트 스토리지를 대체하고 역할 할당을 지정하는 앱 호스트 프로젝트에 대한 최소 AppHost.cs 파일을 보여 줍니다.
using Azure.Provisioning.Storage;
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureContainerAppEnvironment("myEnv");
var myHostStorage = builder.AddAzureStorage("myHostStorage");
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithHostStorage(myHostStorage)
.WithRoleAssignments(myHostStorage, StorageBuiltInRole.StorageBlobDataOwner);
builder.Build().Run();
비고
스토리지 Blob 데이터 소유자는호스트 스토리지 연결의 기본 요구 사항에 권장되는 역할입니다. Blob 서비스에 대한 연결에 Storage Blob 데이터 기여자의 Aspire 기본값만 있는 경우 앱에 문제가 발생할 수 있습니다.
프로덕션 시나리오의 경우 둘 다 WithHostStorage() 및 WithRoleAssignments().에 대한 호출을 포함합니다. 그런 다음 필요한 다른 역할과 함께 이 역할을 명시적으로 설정할 수 있습니다.
트리거 및 바인딩 연결
트리거와 바인딩은 이름으로 연결을 참조하세요. 다음 Aspire 통합은 프로젝트 리소스에 대한 호출을 WithReference() 통해 이러한 연결을 제공합니다.
다음 예제에서는 큐 트리거를 구성하는 앱 호스트 프로젝트에 대한 최소 AppHost.cs 파일을 보여 줍니다. 이 예제에서는 해당 큐 트리거의 속성이 Connection으로 설정되므로, MyQueueTriggerConnection 호출에서 이름을 지정합니다.
var builder = DistributedApplication.CreateBuilder(args);
var myAppStorage = builder.AddAzureStorage("myAppStorage").RunAsEmulator();
var queues = myAppStorage.AddQueues("queues");
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithReference(queues, "MyQueueTriggerConnection");
builder.Build().Run();
다른 통합의 경우 다른 방식으로 구성을 설정하기 위한 WithReference 호출입니다. 구성을 Aspire 클라이언트 통합에 사용할 수 있지만 트리거 및 바인딩에는 사용할 수 없습니다. 이러한 통합의 경우 트리거 또는 바인딩을 해결할 연결 정보를 전달하도록 WithEnvironment()를 호출합니다.
다음 예제에서는 연결 문자열 식을 노출하는 리소스에 대한 환경 변수 MyBindingConnection 를 설정하는 방법을 보여 줍니다.
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithEnvironment("MyBindingConnection", otherIntegration.Resource.ConnectionStringExpression);
Aspire 클라이언트 통합과 트리거 및 바인딩 시스템 모두가 연결을 사용하도록 하려면, WithReference()와 WithEnvironment()를 구성할 수 있습니다.
일부 리소스의 경우 로컬에서 실행할 때와 Azure에 게시할 때의 연결 구조가 다를 수 있습니다. 이전 예에서 otherIntegration은 에뮬레이터로 실행되는 리소스일 수 있으므로 ConnectionStringExpression은 에뮬레이터 연결 문자열을 반환합니다. 그러나 리소스가 게시되면 Aspire는 ID 기반 연결을 ConnectionStringExpression 설정하고 서비스의 URI를 반환할 수 있습니다. 이 경우 Azure Functions에 대한 ID 기반 연결을 설정하려면 다른 환경 변수 이름을 제공해야 할 수 있습니다.
다음 예에서는 builder.ExecutionContext.IsPublishMode를 사용하여 필요한 접미사를 조건부로 추가합니다.
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithEnvironment("MyBindingConnection" + (builder.ExecutionContext.IsPublishMode ? "__serviceUri" : ""), otherIntegration.Resource.ConnectionStringExpression);
각 바인딩에서 지원하는 연결 형식 및 해당 형식에 필요한 사용 권한에 대한 자세한 내용은 바인딩의 참조 페이지를 참조하세요.
애플리케이션 호스팅
Aspire는 Azure에서 Functions 프로젝트를 호스트하는 두 가지 방법을 지원합니다.
- 컨테이너 앱으로 게시(기본값)
- 프리뷰 애플리케이션 서비스 통합을 사용하여 함수 앱으로 게시
두 경우 모두 프로젝트가 컨테이너로 배포됩니다. Aspire는 컨테이너 이미지를 빌드하고 Azure Container Registry에 푸시하는 작업을 처리합니다.
컨테이너 앱으로 게시
기본적으로 Azure에 Aspire 프로젝트를 게시하면 Azure Container Apps에 배포됩니다. 시스템은 KEDA를 사용하여 Functions 프로젝트에 대한 크기 조정 규칙을 설정합니다. Azure Container Apps를 사용하는 경우 함수 키에 대한 추가 설정이 필요합니다. 자세한 내용은 Azure Container Apps의 액세스 키를 참조하세요.
Azure Container Apps의 액세스 키
여러 Azure Functions 시나리오는 액세스 키를 사용하여 원치 않는 액세스에 대한 기본 완화를 제공합니다. 예를 들어 HTTP 트리거 함수는 기본적으로 액세스 키를 호출해야 하지만 이 요구 사항은 속성을 사용하여 AuthLevel사용하지 않도록 설정할 수 있습니다.
Azure Functions의 액세스 키 작업에서 키가 필요할 수 있는 시나리오를 참조하세요.
Azure Container Apps에 대한 Aspire를 사용하여 Functions 프로젝트를 배포하는 경우 시스템은 Functions 액세스 키를 자동으로 만들거나 관리하지 않습니다. 액세스 키를 사용해야 하는 경우 앱 호스트 설정의 일부로 관리할 수 있습니다. 이 섹션에서는 앱 호스트의 Program.cs 파일에서 호출하여 액세스 키를 만들고 관리할 수 있는 확장 메서드를 만드는 방법을 보여 줍니다. 이 방법은 Azure Key Vault를 사용하여 키를 저장하고 컨테이너 앱에 비밀로 탑재합니다.
비고
여기서 동작은 Functions ContainerApps 호스트 버전 4.1044.0부터만 사용할 수 있는 비밀 공급자를 사용합니다. 이 버전은 아직 모든 지역에서 사용할 수 없으며, Aspire 프로젝트를 게시할 때까지 Functions 프로젝트에 사용되는 기본 이미지에 필요한 변경 내용이 포함되지 않을 수 있습니다.
이러한 단계에는 Bicep 버전 0.38.3 이상이 필요합니다. 명령 프롬프트에서 실행 bicep --version 하여 Bicep 버전을 확인할 수 있습니다. Azure CLI가 설치된 경우 Bicep을 최신 버전으로 빠르게 업데이트하는 데 사용할 az bicep upgrade 수 있습니다.
앱 호스트 프로젝트에 다음 NuGet 패키지를 추가합니다.
앱 호스트 프로젝트에서 새 클래스를 만들고 다음 코드를 포함합니다.
using Aspire.Hosting.Azure;
using Azure.Provisioning.AppContainers;
namespace Aspire.Hosting;
internal static class Extensions
{
private record SecretMapping(string OriginalName, IAzureKeyVaultSecretReference Reference);
public static IResourceBuilder<T> PublishWithContainerAppSecrets<T>(
this IResourceBuilder<T> builder,
IResourceBuilder<AzureKeyVaultResource>? keyVault = null,
string[]? hostKeyNames = null,
string[]? systemKeyExtensionNames = null)
where T : AzureFunctionsProjectResource
{
if (!builder.ApplicationBuilder.ExecutionContext.IsPublishMode)
{
return builder;
}
keyVault ??= builder.ApplicationBuilder.AddAzureKeyVault("functions-keys");
var hostKeysToAdd = (hostKeyNames ?? []).Append("default").Select(k => $"host-function-{k}");
var systemKeysToAdd = systemKeyExtensionNames?.Select(k => $"host-systemKey-{k}_extension") ?? [];
var secrets = hostKeysToAdd.Union(systemKeysToAdd)
.Select(secretName => new SecretMapping(
secretName,
CreateSecretIfNotExists(builder.ApplicationBuilder, keyVault, secretName.Replace("_", "-"))
)).ToList();
return builder
.WithReference(keyVault)
.WithEnvironment("AzureWebJobsSecretStorageType", "ContainerApps")
.PublishAsAzureContainerApp((infra, app) => ConfigureFunctionsContainerApp(infra, app, builder.Resource, secrets));
}
private static void ConfigureFunctionsContainerApp(
AzureResourceInfrastructure infrastructure,
ContainerApp containerApp,
IResource resource,
List<SecretMapping> secrets)
{
const string volumeName = "functions-keys";
const string mountPath = "/run/secrets/functions-keys";
var appIdentityAnnotation = resource.Annotations.OfType<AppIdentityAnnotation>().Last();
var containerAppIdentityId = appIdentityAnnotation.IdentityResource.Id.AsProvisioningParameter(infrastructure);
var containerAppSecretsVolume = new ContainerAppVolume
{
Name = volumeName,
StorageType = ContainerAppStorageType.Secret
};
foreach (var mapping in secrets)
{
var secret = mapping.Reference.AsKeyVaultSecret(infrastructure);
containerApp.Configuration.Secrets.Add(new ContainerAppWritableSecret()
{
Name = mapping.Reference.SecretName.ToLowerInvariant(),
KeyVaultUri = secret.Properties.SecretUri,
Identity = containerAppIdentityId
});
containerAppSecretsVolume.Secrets.Add(new SecretVolumeItem
{
Path = mapping.OriginalName.Replace("-", "."),
SecretRef = mapping.Reference.SecretName.ToLowerInvariant()
});
}
containerApp.Template.Containers[0].Value!.VolumeMounts.Add(new ContainerAppVolumeMount
{
VolumeName = volumeName,
MountPath = mountPath
});
containerApp.Template.Volumes.Add(containerAppSecretsVolume);
}
public static IAzureKeyVaultSecretReference CreateSecretIfNotExists(
IDistributedApplicationBuilder builder,
IResourceBuilder<AzureKeyVaultResource> keyVault,
string secretName)
{
var secretParameter = ParameterResourceBuilderExtensions.CreateDefaultPasswordParameter(builder, $"param-{secretName}", special: false);
builder.AddBicepTemplateString($"key-vault-key-{secretName}", """
param location string = resourceGroup().location
param keyVaultName string
param secretName string
@secure()
param secretValue string
// Reference the existing Key Vault
resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' existing = {
name: keyVaultName
}
// Deploy the secret only if it does not already exist
@onlyIfNotExists()
resource newSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = {
parent: keyVault
name: secretName
properties: {
value: secretValue
}
}
""")
.WithParameter("keyVaultName", keyVault.GetOutput("name"))
.WithParameter("secretName", secretName)
.WithParameter("secretValue", secretParameter);
return keyVault.GetSecret(secretName);
}
}
그런 다음 앱 호스트의 Program.cs 파일에서 이 메서드를 사용할 수 있습니다.
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithHostStorage(storage)
.WithExternalHttpEndpoints()
.PublishWithContainerAppSecrets(systemKeyExtensionNames: ["mcp"]);
이 예제에서는 확장 메서드로 생성된 기본 키 볼트를 사용합니다. 그러면 모델 컨텍스트 프로토콜 확장에 사용할 기본 키와 시스템 키가 생성됩니다.
클라이언트에서 이러한 키를 사용하려면 키 보관소에서 해당 키를 검색해야 합니다.
함수 앱으로 게시
비고
함수 앱으로 게시하려면 현재 미리 보기 상태인 Aspire Azure App Service 통합이 필요합니다.
Aspire Azure App Service 통합을 사용하여 함수 앱에 배포하도록 Aspire를 구성할 수 있습니다. Aspire는 Functions 프로젝트를 컨테이너로 게시하므로 함수 앱에 대한 호스팅 계획은 컨테이너화된 애플리케이션 배포를 지원해야 합니다.
Aspire Functions 프로젝트를 함수 앱으로 게시하려면 다음 단계를 수행합니다.
- 앱 호스트 프로젝트에서 Aspire.Hosting.Azure.AppService NuGet 패키지에 대한 참조를 추가합니다.
-
AppHost.cs파일에서AddAzureAppServiceEnvironment()인스턴스에 대해IDistributedApplicationBuilder를 호출하여 App Service 요금제를 만듭니다. 이름에서 느껴지는 것과는 달리, App Service Environment라는 리소스를 실제로 제공하지 않습니다. - Functions 프로젝트 리소스에서
.WithExternalHttpEndpoints()을 호출합니다. 이는 Aspire Azure App Service 통합을 사용하여 배포하는 데 필요합니다. - Functions 프로젝트 리소스에서 해당 프로젝트를 계획에 게시하기 위해 호출
.PublishAsAzureAppServiceWebsite((infra, app) => app.Kind = "functionapp,linux")합니다.
중요합니다
app.Kind 속성을 "functionapp,linux"로 설정했는지 확인하세요. 이 설정을 사용하면 리소스가 함수 앱으로 생성되어 애플리케이션 작업에 대한 환경에 영향을 줍니다.
다음 예제에서는 Functions 프로젝트를 함수 앱으로 게시하는 앱 호스트 프로젝트에 대한 최소 AppHost.cs 파일을 보여 줍니다.
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureAppServiceEnvironment("functions-env");
builder.AddAzureFunctionsProject<Projects.MyFunctionsProject>("MyFunctionsProject")
.WithExternalHttpEndpoints()
.PublishAsAzureAppServiceWebsite((infra, app) => app.Kind = "functionapp,linux");
이 구성은 프리미엄 V3 계획을 만듭니다. 전용 App Service 계획 SKU를 사용하는 경우 크기 조정은 이벤트 기반이 아닙니다. 대신, 크기 조정은 App Service 계획 설정을 통해 관리됩니다.
고려 사항 및 모범 사례
Azure Functions와 Aspire의 통합을 평가할 때 다음 사항을 고려합니다.
Aspire를 통한 트리거 및 바인딩 구성은 현재 특정 통합으로 제한됩니다. 자세한 내용은 이 문서에서 Aspire를 사용한 연결 구성 을 참조하세요.
함수 프로젝트의 파일은
Program.csIHostApplicationBuilder버전을 사용해야 합니다.IHostApplicationBuilder를 사용하면builder.AddServiceDefaults()추가하도록 호출 할 수 있습니다.Aspire는 모니터링에 OpenTelemetry를 사용합니다. 서비스 기본 프로젝트를 통해 Azure Monitor로 데이터를 내보내도록 Aspire를 구성할 수 있습니다.
다른 많은 Azure Functions 컨텍스트에서는 작업자 서비스를 등록하여 Application Insights와의 직접 통합을 포함할 수 있습니다. 이러한 종류의 통합은 Aspire에서 권장하지 않습니다. 버전 2.22.0에서는
Microsoft.ApplicationInsights.WorkerService관련 런타임 오류가 발생할 수 있지만, 버전 2.23.0에서는 이 문제가 해결됩니다. Aspire를 사용하는 경우 Functions 프로젝트에서 직접 Application Insights 통합을 제거합니다.Aspire 오케스트레이션에 참여하는 Functions 프로젝트의 경우 애플리케이션 구성의 대부분은 Aspire 앱 호스트 프로젝트에서 제공됩니다.
local.settings.json설정을 제외하고FUNCTIONS_WORKER_RUNTIME설정은 피하십시오.local.settings.json와 Aspire에서 동일한 환경 변수를 설정하면, 시스템은 Aspire 버전을 사용합니다.local.settings.json에서 연결에 대해 Azure Storage 에뮬레이터를 구성하지 마세요. 많은 Functions 시작 템플릿에는AzureWebJobsStorage에 대한 기본값으로 에뮬레이터가 포함되어 있습니다. 그러나 에뮬레이터 구성은 일부 개발자 도구에서 Aspire에서 사용하는 버전과 충돌할 수 있는 에뮬레이터 버전을 시작하라는 메시지를 표시할 수 있습니다.