How to Set Up Windows Server 2019 Container Storage

Container storage in Windows Server 2019 covers the mechanisms for persisting data beyond a container’s lifecycle, sharing data between containers, and providing high-performance storage for containerized applications. By default, container storage is ephemeral — all data written inside a container is lost when the container is removed. Windows Server 2019 supports several storage options including bind mounts, named volumes, the windowsfilter storage driver, and SMB shares for persistent storage. This guide covers configuring each option for production container workloads.

Understanding Windows Container Storage Layers

Windows containers use a layered filesystem based on the windowsfilter storage driver. Each container image consists of read-only layers, and each running container adds a writable layer on top. When a container is deleted, its writable layer is discarded. The base image layers are cached on the host in C:ProgramDatadockerwindowsfilter. Check current storage driver information:

docker info --format "{{json .Driver}}"
docker system df

View the size of each image and its layers:

docker images --format "table {{.Repository}}t{{.Tag}}t{{.Size}}"
docker history mcr.microsoft.com/windows/servercore:ltsc2019

Using Named Volumes for Persistent Data

Named volumes are the recommended method for persisting container data on Windows Server 2019. Docker manages named volumes and stores them at C:ProgramDatadockervolumes. Create and use a named volume:

docker volume create --name AppDatabase

docker run -d `
    --name sql_container `
    -v AppDatabase:C:/var/opt/mssql `
    -e ACCEPT_EULA=Y `
    -e SA_PASSWORD=Str0ngP@ss2019 `
    mcr.microsoft.com/mssql/server:2019-latest

Inspect the volume to find its physical location and metadata:

docker volume inspect AppDatabase

Create a volume with specific driver options:

docker volume create `
    --driver local `
    --opt type=none `
    --opt device="C:ContainerDataAppDB" `
    --opt o=bind `
    AppDatabaseBind

Bind Mounts for Host Directory Access

Bind mounts map a specific host directory directly into the container. They are useful for sharing configuration files or log directories between the host and container. Use forward slashes or escaped backslashes in the path:

New-Item -ItemType Directory -Path "C:ContainerLogswebapp" -Force
New-Item -ItemType Directory -Path "C:ContainerConfigwebapp" -Force

docker run -d `
    --name webapp `
    -v "C:ContainerLogswebapp:C:inetpublogsLogFiles" `
    -v "C:ContainerConfigwebapp:C:appconfig:ro" `
    -p 80:80 `
    mcr.microsoft.com/windows/servercore/iis:windowsservercore-ltsc2019

The :ro suffix makes the bind mount read-only inside the container, preventing the container from modifying host configuration files.

Configuring SMB Global Mapping for Shared Storage

SMB Global Mapping allows Windows containers to access SMB shares directly. This is particularly useful for accessing shared storage like Azure Files or a Windows Server file share. Create an SMB Global Mapping on the host:

$cred = Get-Credential -Message "Enter SMB credentials for \fileserversharename"

New-SmbGlobalMapping `
    -RemotePath "\fileserver.contoso.localAppData" `
    -Credential $cred `
    -LocalPath "G:" `
    -Persistent $true `
    -RequireIntegrity $true

Verify the mapping is active:

Get-SmbGlobalMapping

Mount the SMB share into a container using a bind mount to the mapped drive:

docker run -d `
    --name app_with_smb `
    -v "G::C:AppData" `
    contoso/myapp:v1

Using Azure Files for Container Storage

Azure Files provides a cloud SMB share that can be mounted into Windows containers. Create an Azure Storage account and file share, then mount it:

az storage account create `
    --name sacontainerstorage `
    --resource-group rg-containers `
    --sku Standard_LRS `
    --kind StorageV2

az storage share create `
    --name containerdata `
    --account-name sacontainerstorage `
    --quota 100

$storageKey = az storage account keys list `
    --account-name sacontainerstorage `
    --query "[0].value" -o tsv

New-SmbGlobalMapping `
    -RemotePath "\sacontainerstorage.file.core.windows.netcontainerdata" `
    -Credential (New-Object PSCredential("Azuresacontainerstorage", (ConvertTo-SecureString $storageKey -AsPlainText -Force))) `
    -LocalPath "Z:" `
    -Persistent $true

Storage in Kubernetes with Windows Nodes

In Kubernetes, persistent storage for Windows containers is managed through PersistentVolumes and PersistentVolumeClaims. Create a StorageClass backed by Azure Disk for Windows pods:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: azure-disk-windows
provisioner: disk.csi.azure.com
parameters:
  skuName: Premium_LRS
  kind: Managed
reclaimPolicy: Retain
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer

Create a PersistentVolumeClaim using this storage class:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: windows-app-pvc
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: azure-disk-windows
  resources:
    requests:
      storage: 100Gi

Managing Container Storage Cleanup

Regularly prune unused container storage to reclaim disk space. Remove all stopped containers, dangling images, unused networks, and unused volumes:

docker system prune -f
docker volume prune -f
docker image prune -a -f --filter "until=720h"

Schedule automated cleanup with a scheduled task:

$action = New-ScheduledTaskAction `
    -Execute "docker.exe" `
    -Argument "system prune -f --volumes"
$trigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek Saturday -At "03:00"
Register-ScheduledTask -TaskName "DockerCleanup" -Action $action -Trigger $trigger -RunLevel Highest

Container storage on Windows Server 2019 requires careful planning, especially for stateful applications like databases. Named volumes provide the simplest persistence model, while SMB Global Mapping enables access to existing enterprise storage. For Kubernetes deployments, leveraging cloud-native storage providers like Azure Disk or Azure Files through CSI drivers provides the scalability and manageability needed in production environments.