I recently worked on an improvement to the flask-admin extension to upgrade the Azure Blob Storage SDK from v2 (an old legacy SDK) to v12 (the latest). To make it easy for me to test out the change without touching a production Blob storage account, I used the Azurite server, the official local emulator. I could have installed that emulator on my Mac, but I was already working in GitHub Codespaces, so I wanted Azurite to be automatically set up inside that environment, for me and any future developers. I decided to create a dev container definition for the flask-admin repository, and used that to bring in Azurite.
To make it easy for *anyone* to make a dev container with Azurite, I've created a GitHub repository whose sole purpose is to set up Azurite:
https://github.com/pamelafox/azurite-python-playground
You can open that up in a GitHub Codespace or VS Code Dev Container immediately and start playing with it, or continue reading to learn how it works.
devcontainer.json
The entry point for a dev container is .devcontainer/devcontainer.json
, which tells the IDE how to set up the containerized environment.
For a container with Azurite, here's the devcontainer.json
:
{
"name": "azurite-python-playground",
"dockerComposeFile": "docker-compose.yaml",
"service": "app",
"workspaceFolder": "/workspace",
"forwardPorts": [10000, 10001],
"portsAttributes": {
"10000": {"label": "Azurite Blob Storage Emulator", "onAutoForward": "silent"},
"10001": {"label": "Azurite Blob Storage Emulator HTTPS", "onAutoForward": "silent"}
},
"customizations": {
"vscode": {
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python"
}
}
},
"remoteUser": "vscode"
}
That dev container tells the IDE to build a container using docker-compose.yaml
and to treat the "app" service as the main container for the editor to open. It also tells the IDE to forward the two ports exposed by Azurite (10000 for HTTP, 10001 for HTTPS) and to label them in the "Ports" tab. That's not strictly necessary, but it's a nice way to see that the server is running.
docker-compose.yaml
The docker-compose.yaml
file needs to describe first the "app" container that will be used for the IDE's editing environment,
and then define the "azurite" container for the local Azurite server.
version: '3'
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- ..:/workspace:cached
# Overrides default command so things don't shut down after the process ends.
command: sleep infinity
environment:
AZURE_STORAGE_CONNECTION_STRING: DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;
azurite:
container_name: azurite
image: mcr.microsoft.com/azure-storage/azurite:latest
restart: unless-stopped
volumes:
- azurite-data:/data
network_mode: service:app
volumes:
azurite-data:
A few things to note:
- The "app" service is based on a local
Dockerfile
with a base Python image. It also sets theAZURE_STORAGE_CONNECTION_STRING
for connecting with the local server. - The "azurite" service is based off the official azurite image and uses a volume for data persistance.
- The "azurite" service uses
network_mode: service:app
so that it is on the same network as the "app" service. This means that the app can access them at alocalhost
URL. The other approach is to usenetwork_mode: bridge
, the default, which would mean the Azurite service was only available at its service name, like "http://azurite:10000". Either approach works, as long as the connection string is set correctly.
Dockerfile
The Dockerfile
defines the environment for the code editing experience. In this case, I am bringing in a devcontainer-optimized Python image. You could adapt it for other languages, like Java, .NET, JavaScript, Go, etc.
FROM mcr.microsoft.com/devcontainers/python:3.12
pip install -r requirements.txt