Azure Storage Emulator with Docker on Windows

If you are on the road a lot, this might be a great option for you to keep working with Azure Tables even when on road(or on a flight) with Docker on Windows. I will walk you through the process on setting up your system to use Azure Storage Emulator from your local Docker containers.

If you have not yet started with Docker on Windows, you can download it here.
To get the latest Azure Storage Emulator, click here.

I am using the below product versions but this guide should be good for other versions too. (if not give me shout out at @rgwork and will update this guide)

Windows 10 Version
Windows 10
Docker and Azure Storage Emulator Version
Docker and Azure Storage Emulator Version

Also, download the Azure Storage Explorer so that you can easily verify and view the changes made from your code in the container, from here.

Once all of the above are installed, start the Docker on windows (Linux Containers) and the Azure Storage Emulator from “Start” Menu.

Open a command prompt and then follow the below steps to make sure that Docker and azure storage emulator are running.
For Docker:
Type in

docker version

— If the output lists the version details of the server and client then it is up and running.
For Azure Storage Emulator

cd "C:\Program Files (x86)\Microsoft SDKs\Azure\Storage Emulator"
AzureStorageEmulator.exe status

— The output should list the endpoints and status of the emulator.

The output from above commands should be similar to the image above showing versions for both.

Once the services are up, go to Docker settings from the notification area in the task bar.

Docker Settings
Docker Settings

Switch to Network tab and verify the Subnet address configured for the Internal Virtual Switch.

Docker Network Settings
Docker Network Settings

It should be 10.0.75.0 by default but can be different if there was a network conflict. Moving forward I will assume the subnet is 10.0.75.0 but please update it with your subnet as needed.

Before moving to the next step, I will outline the process by which we will connect the Docker container with the storage emulator on the localhost.

The internal virtual switch create by Docker is the network on which it will create the Linux virtual machine to host containers and it will assign the IP 10.0.75.2 to it. It will also create a network interface on the windows machine and assign it the IP 10.0.75.1 and this is the network which allows you to manage the Docker server running on the Linux virtual machine and interact with it.

The storage emulator endpoints listen on http://127.0.0.1:10000-2 and are not accessible by default from external networks including the Docker network.

The plan is to provide a bridge from the Docker network to the localhost IP so that the containers can have uninhibited access to the storage emulator. We will do this by using the port proxy option of netsh command. It acts as the proxy and maps the ports and IPs as required.

We will create v4tov4 mappings so that the Docker network adapter will listen to the requests to storage emulator and will forward it to the 127.0.0.1 and vice versa.

Before we do the mapping, open a command prompt as administrator and run:

netstat -a

The output will be similar to this.

The azure emulator should also be in this list:

Azure Storage Emulator EndPoints
Azure Storage Emulator Endpoints

Choose 3 adjacent ports which are not listed in the output (Column 2 from left) to use for the mapping, from my system I identified 40000-40002 which are not being used. I will use these 3 ports to map from 10.0.75.1 to 127.0.0.1.

In the same command prompt(should be run as administrator), run the below commands to configure the network:

netsh interface portproxy add v4tov4 listenport=40000 listenaddress=10.0.75.1 connectaddress=127.0.0.1 connectport=10000  protocol=tcp
netsh interface portproxy add v4tov4 listenport=40001 listenaddress=10.0.75.1 connectaddress=127.0.0.1 connectport=10001  protocol=tcp
netsh interface portproxy add v4tov4 listenport=40002 listenaddress=10.0.75.1 connectaddress=127.0.0.1 connectport=10002  protocol=tcp

To confirm the changes run netstat again and confirm that the system is now listening on the configured ports.

netstat -a

It should look like for 10.0.75.1:

Updated Ports
Port Proxy Mapping

The first one is created by docker for the SMB mapping(445) and the rest are our mappings. Now the only thing between containers and storage emulator is windows firewall.

Run “wf.msc” from run to directly open the Windows Firewall with Advanced Security. Browse to Inbound Rules and select the rule DockerSmbMount (created by docker).

Firewall Inbound Rules
Firewall Inbound Rules DockerSmbMount

Right click and copy the rule.

Then Paste it back.

Now you should have 2 rules.

Right Click the newly created rule(top one) and click on Properties.  Rename the rule to DockerAzureStorage.

Switch to Protocols and Ports and update the Local Port from 445 to “40000-40002”.

The required configuration is done, before you click on apply check out the scope tab as this will give you the idea on what the rule does as it is opening up the network ports only from the Linux VM to the localhost. Once you are done looking around, click on apply and close the rule.

We are all set with the configuration and now to test it. I will use a MVC 6 web app to run a test but you should be able to use your choice of application or language if you will use the connection string listed in the below steps.

Open Visual Studio 2017, I am using this and will recommend to get this due to its integrated support for Docker.  If you are not using VS 2017 then the steps I am taking will differ with the steps you need to build and run the docker container image on your system.

In VS 2017, create a new project and choose the ASP.NET Core Web App:

Make sure support for Docker is enabled .

Goto Manage Nuget Packages for the web project and install the package WindowsAzure.Storage:

Add a new class to the project – NewEntity and update its contents from below:

using Microsoft.WindowsAzure.Storage.Table;
namespace TestCoreEmulator.Model
{
    public class NewEntity : TableEntity
    {
        public string RandomText { get; set; }
    }
}

We will use this test class to enter data in the local Azure Table.

Add the below function to the home controller resolve the references so there are no more errors:

private static void TestStorage()
{
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://10.0.75.1:40000/devstoreaccount1;TableEndpoint=http://10.0.75.1:40002/devstoreaccount1;QueueEndpoint=http://10.0.75.1:40001/devstoreaccount1;");

    CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

    // Retrieve a reference to the table.
    CloudTable table = tableClient.GetTableReference("myTable");


    // Create the table if it doesn't exist.
    table.CreateIfNotExistsAsync().Wait();



    NewEntity en = new NewEntity();
    en.RowKey = "Check" + Guid.NewGuid();
    en.PartitionKey = "P";
    en.RandomText = DateTime.Now.ToString();


    TableOperation insertOperation = TableOperation.Insert(en);

    // Execute the insert operation.
    table.ExecuteAsync(insertOperation).Wait();
}

I have just embedded the connection string in the code itself as this a test but ideally it should reside in either user secrets or the config file.

The connection string is derived from the connection string referenced here, which is the default connection string for the azure storage emulator. I have only updated the endpoints so that it points to the right IP and port.

DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;
AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;
BlobEndpoint=http://10.0.75.1:10000/devstoreaccount1;
TableEndpoint=http://10.0.75.1:10002/devstoreaccount1;
QueueEndpoint=http://10.0.75.1:10001/devstoreaccount1;

The function above adds random entity to the myTable which we can verify easily with the Azure Storage Explorer. Add the function call to the Contact function of the HomeController so it will be called each time you visit the Contact page.  It should look like this:

public IActionResult Contact()
{
    ViewData["Message"] = "Your contact page.";
    TestStorage();
    return View();
}

Now let’s run the application in VS. Once the site is up and running, click on the Contact link in the header. Once the contact page loads, open the Azure Storage Explorer and browse to the local Tables.

There should be a new table and the entity.

All done, you are all set to use the storage emulator from docker 🙂

NOTE: the netsh proxy mappings are removed if the system is rebooted, my advise is to store the commands in a bat file and either run as needed or automate via task scheduler.