1. Introduction

In cloud environments, application storage behaves differently from traditional on-premise servers. Containers and platform services such as Azure App Service use ephemeral (temporary) storage by default. This means:

  • Files written inside the container may disappear after restart.
  • Scaling the application to multiple instances does not automatically share local disk content.
  • Container redeployments may wipe locally stored files.

To solve this problem, Azure provides Azure File Shares, which offer persistent, shared storage that can be mounted into App Service containers.

In this lab, you will:

  • Deploy a Flask web application
  • Create an Azure Storage Account
  • Create an Azure File Share
  • Upload files using Azure CLI
  • Mount the file share inside the App Service container
  • Verify persistent shared storage behavior

Before starting, ensure:

  • Azure CLI is installed
  • You have an active Azure subscription
  • You are logged in — verify with:
az account show
  • You have a working Flask app from the previous exercise

2. Architecture Overview

At the end of this lab, your architecture will look like this:

User → Azure App Service (Flask App)
                 │
                 │ mounted path (/mountfiles)
                 ↓
        Azure Storage Account
                 ↓
           Azure File Share

The App Service container will access persistent storage through a mounted directory.

3. Create Infrastructure

We will first create the required Azure infrastructure step by step.

To avoid repeating long names and reduce typing errors, we define variables.

RESOURCE_GROUP=rg-appservice-lab
LOCATION=westeurope
APP_NAME=flaskapp$RANDOM
PLAN_NAME=flask-plan
STORAGE_NAME=storage$RANDOM
FILE_SHARE=sharedfiles

Explanation:

  • $RANDOM ensures globally unique names (required for storage accounts and web apps).
  • Keeping all resources in one resource group simplifies cleanup.

⚠️ These variables are only valid for the current terminal session. If you close your terminal, re-run this block before continuing. You can also save them for reference:

echo "APP_NAME=$APP_NAME" >> lab-vars.env
echo "STORAGE_NAME=$STORAGE_NAME" >> lab-vars.env

Create Resource Group

A Resource Group is a logical container for Azure resources.

az group create \
  --name $RESOURCE_GROUP \
  --location $LOCATION

This command prepares a dedicated environment for our lab.

Create App Service Plan

The App Service Plan defines:

  • Compute resources
  • Pricing tier
  • Operating system
az appservice plan create \
  --name $PLAN_NAME \
  --resource-group $RESOURCE_GROUP \
  --sku B1 \
  --is-linux

Explanation:

  • --sku B1 = Basic tier (sufficient for lab)
  • --is-linux = Required for Python runtime

4. Deploy the Web App (Python Runtime)

Now we create and deploy the web application.

Navigate to your Flask project directory, then deploy:

az webapp up \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --plan $PLAN_NAME \
  --runtime "PYTHON:3.10"

This creates the web app and deploys your code in a single step.

Verify it works:

echo https://$APP_NAME.azurewebsites.net

Open the URL in your browser.

At this stage:

  • Your app is running
  • It uses only container-local storage
  • No persistent shared disk exists yet

5. Create Azure Storage

Now we create persistent storage that will survive restarts and scaling.

Create Storage Account

az storage account create \
  --name $STORAGE_NAME \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --sku Standard_LRS

Explanation:

  • Storage accounts must have globally unique names.
  • Standard_LRS is cost-efficient and sufficient for labs.

Retrieve Storage Access Key

Azure File Share authentication requires an access key.

⚠️ Store the access key securely. Do not commit it to source control. For production workloads, prefer Entra ID (Azure AD) authentication with --auth-mode login.

STORAGE_KEY=$(az storage account keys list \
  --resource-group $RESOURCE_GROUP \
  --account-name $STORAGE_NAME \
  --query "[0].value" \
  --output tsv)

We store it in a variable for later use.

Create File Share

az storage share create \
  --name $FILE_SHARE \
  --account-name $STORAGE_NAME \
  --account-key $STORAGE_KEY \
  --quota 5

Explanation:

  • --quota 5 means 5 GB maximum size.
  • This share behaves like a network file system inside Azure.

Create a test file:

echo "Hello from Azure File Share" > testfile.txt

Upload it:

az storage file upload \
  --share-name $FILE_SHARE \
  --source testfile.txt \
  --path testfile.txt \
  --account-name $STORAGE_NAME \
  --account-key $STORAGE_KEY

Verify upload:

az storage file list \
  --share-name $FILE_SHARE \
  --account-name $STORAGE_NAME \
  --account-key $STORAGE_KEY \
  --output table

Now the file exists in persistent cloud storage.

6. Mount File Share to App Service

Now we connect the Web App to the File Share.

This creates a mapping between the container and Azure storage.

Configure Mount

az webapp config storage-account add \
  --resource-group $RESOURCE_GROUP \
  --name $APP_NAME \
  --custom-id fileshareconnection \
  --storage-type AzureFiles \
  --account-name $STORAGE_NAME \
  --share-name $FILE_SHARE \
  --access-key $STORAGE_KEY \
  --mount-path /mountfiles

Explanation:

  • /mountfiles will appear inside the container
  • Anything written there is stored in Azure File Share
  • The storage is persistent and shared

Verify the mount was registered:

az webapp config storage-account list \
  --resource-group $RESOURCE_GROUP \
  --name $APP_NAME \
  --output table

Restart the app:

az webapp restart \
  --resource-group $RESOURCE_GROUP \
  --name $APP_NAME

Update your app:

import os
from flask import Flask, Response

app = Flask(__name__)

@app.route("/files")
def list_files():
    path = "/mountfiles"
    if not os.path.exists(path):
        return Response("Mount path not found", status=404, mimetype="text/plain")
    files = sorted(os.listdir(path))
    if not files:
        return Response("(empty)", mimetype="text/plain")
    return Response("\n".join(files), mimetype="text/plain")

if __name__ == "__main__":
    app.run()

Redeploy:

az webapp up \
  --name $APP_NAME \
  --resource-group $RESOURCE_GROUP

Test:

echo https://$APP_NAME.azurewebsites.net/files

Open the printed URL in your browser.

You should see:

testfile.txt

This confirms the container can access shared storage.

7. Persistence Test

Restart the web app:

az webapp restart \
  --resource-group $RESOURCE_GROUP \
  --name $APP_NAME

Check /files again.

If the file is still there → persistent storage works.

Cleanup

Always clean up cloud resources to avoid charges:

az group delete \
  --name $RESOURCE_GROUP \
  --yes \
  --no-wait

Final Result

You now understand:

  • How Azure App Service handles disk storage
  • Why local container storage is not reliable
  • How to mount Azure File Share
  • How to build persistent cloud-native applications

Previous Post

Disk space for App Service