Using LocalStack with Microsoft Tye
LocalStack is a platform that facilitates the development of cloud-based applications by hosting locally a series of replicas of AWS services.
Since it uses containers behind the scenes, the documentation on their website explains how to use LocalStack with Docker, Docker Compose and Kubernetes.
In a previous post, I explained how to use Microsoft Tye to facilitate the local development of distributed .NET applications.
In this post we’ll see how to configure Tye to use LocalStack services and how to configure ASP.NET Core applications to consume those services when available.
Configuring LocalStack
The first step for using LocalStack in a Tye application is adding it to the tye.yaml
file.
- name: localstack
image: localstack/localstack:1.0
bindings:
- protocol: http
containerPort: 4566
port: 4566
volumes:
- source: /var/run/docker.sock
target: /var/run/docker.sock
This is nothing special from the typical configuration of a Docker container but for the special volume mounting.
I will not delve into what the /var/run/docker.sock
mount point is, but I suggest you go and read this blog post. Long story short, this mount point is used by containers to interact with the Docker API to manage other containers.
Since LocalStack uses this functionality to emulate services like Lambda, you can probably skip the volume mounting if you are not using any container-based service.
For this mount point to work in Windows, you need Docker to be using the WSL2 integration
Once we have configured LocalStack in the tye.yaml
file, we can start the service
$ dotnet tye run
As seen previously, this command will take care of starting up the services composing the application: in our case, the LocalStack container.
LocalStack offers many configuration options. You can check the related documentation page to see all available options.
Using LocalStack services
Once Tye is done initializing the application, we can test the emulated services as if they were normal AWS services.
Before we start, make sure to add a fake profile in your ~/.aws/credentials
file. I added a profile called LocalStack
with fake values for access and secret key.
[LocalStack]
aws_access_key_id = AKIA1234567890
aws_secret_access_key = abcdefghijklmnopqrstuvwxyz
Furthermore, LocalStack acts as if the services were deployed on the us-east-1
region. For convenience, we will modify the ~/.aws/config
file to add this preference.
[profile LocalStack]
region = us-east-1
AWS CLI
For this test, we will be using the S3 API.
I will assume the AWS CLI has been installed and is available via the PATH
variable.
Let’s start by fetching a list of buckets.
$ aws --endpoint-url=http://localhost:4566 --profile LocalStack s3api list-buckets
{
"Buckets": [],
"Owner": {
"DisplayName": "webfile",
"ID": "bcaf1ffd86f41161ca5fb16fd081034f"
}
}
Now, let’s create a bucket and test its existence
$ aws --endpoint-url=http://localhost:4566 --profile LocalStack s3api create-bucket --bucket test
$ aws --endpoint-url=http://localhost:4566 --profile LocalStack s3api list-buckets
{
"Buckets": [
{
"Name": "test",
"CreationDate": "2022-07-22T10:20:13+00:00"
}
],
"Owner": {
"DisplayName": "webfile",
"ID": "bcaf1ffd86f41161ca5fb16fd081034f"
}
}
Now that we have a bucket, let’s do some test operations with files.
In the snippet below, I create a file, I upload it to the LocalStack S3 and then I get a list of all the files available.
$ echo "Hello world" >> hello.txt
$ aws --endpoint-url=http://localhost:4566 --profile LocalStack s3 cp ./hello.txt s3://test/
upload: ./hello.txt to s3://test/hello.txt
$ aws --endpoint-url=http://localhost:4566 --profile LocalStack s3 ls s3://test/
2022-07-22 12:28:06 13 hello.txt
If you are tired of repeating the endpoint-url
parameter, you can install the awslocal
CLI application provided by LocalStack. More information here.
PowerShell toolkit
Like for AWS CLI, we can use the PowerShell toolkit to interact with the LocalStack services.
For this test, we will be using the SQS API.
First of all, we need to install the needed Powershell modules.
$ Install-Module -Name AWS.Tools.Installer
$ Install-AWSToolsModule SQS
Once the module is installed, we can use it to create a queue.
# Creates a new SQS queue
$ New-SQSQueue -QueueName test -EndpointUrl http://localhost:4566 -ProfileName LocalStack
http://localhost:4566/000000000000/test
# Lists all available SQS queues
$ Get-SQSQueue -EndpointUrl http://localhost:4566 -ProfileName LocalStack
http://localhost:4566/000000000000/test
# Gets the URL of the SQS queue we just created
$ Get-SQSQueueUrl -QueueName test -EndpointUrl http://localhost:4566 -ProfileName LocalStack
http://localhost:4566/000000000000/test
Next, we can send and receive a message.
# Sends a message to the SQS queue
$ Send-SQSMessage -QueueUrl http://localhost:4566/000000000000/test -EndpointUrl http://localhost:4566 -ProfileName LocalStack -MessageBody "Hello World"
MD5OfMessageAttributes :
MD5OfMessageBody : b10a8db164e0754105b7a99be72e3fe5
MD5OfMessageSystemAttributes :
MessageId : c9bf5e25-f16d-4767-b0f5-f4d9dfe1ce4a
SequenceNumber :
# Receives a message from the SQS queue
$ Receive-SQSMessage -QueueUrl http://localhost:4566/000000000000/test -EndpointUrl http://localhost:4566 -ProfileName LocalStack
Attributes : {}
Body : Hello World
MD5OfBody : b10a8db164e0754105b7a99be72e3fe5
MD5OfMessageAttributes :
MessageAttributes : {}
MessageId : c9bf5e25-f16d-4767-b0f5-f4d9dfe1ce4a
ReceiptHandle : a_very_long_string
This small example shows how easy is to use LocalStack with the PowerShell toolkit provided by AWS.
Did you know that PowerShell is crossplatform and you can use it on Linux and MacOS as well? More information here.
.NET SDK
Our next step is using LocalStack services in .NET applications using the AWS SDK.
I will assume that you have .NET SDK 6 installed and properly configured.
Let’s start creating a simple console application and add the SDK package to interact with AWS SQS.
$ dotnet new console
$ dotnet add package AWSSDK.SQS
$ dotnet run
Hello, World!
Now let’s replace the content of Program.cs
with the following snippet.
using Amazon.Runtime;
using Amazon.SQS;
var credentials = new BasicAWSCredentials("FAKE", "FAKE");
var config = new AmazonSQSConfig { ServiceURL = "http://localhost:4566" };
var sqs = new AmazonSQSClient(credentials, config);
await sqs.CreateQueueAsync("test");
var queue = await sqs.GetQueueUrlAsync("test");
await sqs.SendMessageAsync(queue.QueueUrl, "Hello world");
var messages = await sqs.ReceiveMessageAsync(queue.QueueUrl);
foreach (var message in messages.Messages)
{
Console.WriteLine(message.Body);
}
The small snippet above is doing the same steps as we did in the previous paragraph:
- Create a queue whose name is
test
- Query the SQS service for the URL of the queue we just created
- Send a message
- Receive messages
- Print the body of every message received
Integration with ASP.NET Core
In the examples above, we have simply used Tye as a way to start and configure the LocalStack application.
Truth be told, there are easier ways to achieve the same like using the LocalStack CLI.
The real advantage of coupling LocalStack with Microsoft Tye is to leverage the service discovery capabilities offered by Tye.
Like before, let’s start creating the application and the relevant additional packages.
$ dotnet new web -o web
$ dotnet add package Microsoft.Tye.Extensions.Configuration --version 0.10.0-alpha.21420.1
$ dotnet add package AWSSDK.Extensions.NETCore.Setup
$ dotnet add package AWSSDK.SQS
When the project is created and the packages added, let’s add it to the Tye application.
- name: web
project: web/web.csproj
bindings:
- protocol: http
Finally, let’s replace the content of Program.cs
with the following snippet.
using Amazon.SQS;
var settings = new Dictionary<string, string>
{
["AWS:Profile"] = "LocalStack",
["AWS:Region"] = "us-east-1"
};
var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddInMemoryCollection(settings);
var options = builder.Configuration.GetAWSOptions();
var localstack = builder.Configuration.GetServiceUri("localstack");
if (localstack is not null)
{
options.DefaultClientConfig.ServiceURL = localstack.ToString();
}
builder.Services.AddAWSService<IAmazonSQS>(options);
var app = builder.Build();
app.MapGet("/", async (IAmazonSQS sqs) =>
{
var queue = await sqs.GetQueueUrlAsync("test");
var messages = await sqs.ReceiveMessageAsync(queue.QueueUrl);
return Results.Ok(messages.Messages.Select(m => m.Body));
});
app.Run();
The snippet uses the new Minimal API to define the endpoint of the application.
The relevant part of the snippet is the following section
var options = builder.Configuration.GetAWSOptions();
var localstack = builder.Configuration.GetServiceUri("localstack");
if (localstack is not null)
{
options.DefaultClientConfig.ServiceURL = localstack.ToString();
}
builder.Services.AddAWSService<IAmazonSQS>(options);
In the snippet above, we’re getting the AWS setup from the configuration subsystem. Then, we check if the process was served the configuration of a service called localstack
: if so, we customize the AWS configuration so that it points to the URI we found.
Finally, we register the client for SQS with the customized configuration.
This approach allows us to use LocalStack when using Tye and the default AWS services when not.
When we start the application using the command dotnet tye run
, both the LocalStack container and our ASP.NET Core application will be started. Furthermore, Tye will take care of passing the address of the localstack
service using two environment variables: SERVICE__localstack__HOST
and SERVICE__localstack__PORT
. The GetServiceUri
function used earlier will take care of fetching the value of these variables and use them to compose a URI pointing to the localstack
service.
To test the service, create a SQS queue named test
and send messages to it by either using the PowerShell toolkit like shown earlier. Finally, open the browser to the Tye dashboard (typically http://127.0.0.1:8000) and from there navigate to the web application. Each visit will return the body of a message from the SQS queue. If no message is available, an empty JSON array is returned.
Alternatively, you can use command line utilities like curl
or Invoke-WebRequest
.
Recap
In this post we saw how we can configure Tye to spin a LocalStack container and how to use it from AWS CLI, the PowerShell toolkit and even a .NET console application. Finally, we leveraged the service discovery mechanisms built into Tye to create a simple ASP.NET Core application able to use LocalStack when launched by Tye.
Support this blog
If you liked this article, consider supporting this blog by buying me a pizza!