Sync Between Azure File Share and Azure Blob Container

| ,

Published on | Updated on April 14, 2021

8 Min. Read

In this article, I will share with you how to sync and copy between an Azure file share and an Azure blob container.

Introduction

A while ago, I wrote about how to copy data from one Azure storage account in one subscription to another storage account in a different Azure subscription. And I also shared, how to sync between Azure Blob Storage and between Azure File Share(s).

You are storing data in Azure file share, and you have a line of business application (LOB) that can read only from a blob container and not from SMB file share. In another scenario, you are leveraging Azure File Sync (AFS) which synced to Azure file share and you need to have the data stored in an Azure blob container. You might also have other scenarios, please leave a comment below.

For these kinds of scenarios, you have a couple of options, at the time of this writing, you could use Azure Databox Gateway which can sync with Blobs. There are also other tools that you could use like AzCopy, Azure Batch, and Azure Data Factory that can help you move data back and forth. However, using these tools comes with some fidelity loss that you want to be aware of such as (permissions and timestamps like last modified time will be lost/changed).

For the purpose of this article, I will make use of the AzCopy tool which is a command-line utility that you can use to copy/sync blobs or files to or from a storage account, and I will use Azure Container Instances to simplify and automate the AzCopy in Runbook which will run as part of the container. In this way, we can run the container on a simple schedule to copy the data and only get billed for the time the container was used.

If you are new to the AzCopy tool, then make sure to check the get started document from Microsoft here. The good news is, Microsoft added sync support for AzCopy starting with version 10.3.0 and later. However, at the time of this writing, sync must happen between source and destination of the same type, e.g. either file <-> file, or directory/container <-> directory/container, but not between file share and blob container. Thus, I will leverage the copy support for AzCopy to copy data from an Azure file share to an Azure blob container.

Prerequisites

To follow this article, you need to have the following:

  1. Azure subscription – If you don’t have an Azure subscription, you can create a free one here.
  2. You need to have one or two different storage accounts either in the same region, same subscription or in different regions and subscriptions.
  3. You also need to create at least one container in the blob storage, and one Azure file share in the same storage account, or across two different storage accounts.
  4. Last, you need to have some files in Azure file share, or you can sync on-premises servers with Azure File Sync to Azure file share.

Get started

First, we need to create an Azure automation account that will help you to automate the synchronization and the copy process without user interaction. This will also make sure to respect the security access of your storage account without exposing access keys to users.

Create Automation Account

In this step, I will create an Azure automation resource with a Run As account. Run As accounts in Azure Automation are used to provide authentication for managing resources in Azure with the Azure cmdlets. When you create a Run As account, it creates a new service principal user in Azure Active Directory (Azure AD) and assigns the Contributor role to the service principal at the subscription level.

Open the Azure portal, click All services found in the upper left-hand corner. In the list of resources, type Automation. As you begin typing, the list filters based on your input. Select Automation Accounts.

Click +Add. Enter the automation account name, choose the right subscription, resource group, location, and then click Create.

Sync Between Azure File Share and Azure Blob Container 1

Import modules from Gallery

In the next step, you need to import the required modules from the Modules gallery. In your list of Automation Accounts, select the account that you created in the previous step. Then from your automation account, select Modules under Shared Resources. Click the Browse Gallery button to open the Browse Gallery page. You need to import the following modules from the Modules gallery in the order given below:

  1. Az.Accounts
  2. Az.ContainerInstance
  3. Az.Storage

Sync Between Azure File Share and Azure Blob Container 2

At the time of this writing, AzCopy is still not part of the Azure Automation Runbook. For this reason, I will be creating an Azure Container instance with AzCopy as part of the container so we can automate the entire synchronization and copy process.

Create PowerShell Runbook

In this step, you can create multiple Runbooks based on which set of Azure file shares you want to sync/copy to the Azure blob container. PowerShell Runbooks are based on Windows PowerShell. You directly edit the code of the Runbook using the text editor in the Azure portal. You can also use any offline text editor such as Visual Studio Code and import the Runbook into Azure Automation.

From your automation account, select Runbooks under Process Automation. Click the ‘+ Create a runbook‘ button to open the Create a runbook blade.

Sync Between Azure File Share and Azure Blob Container 3

In this example, I will create a Runbook to copy all the files and directories changes from a specific Azure file share to a specific blob container. You can also be creative as much as you want and cover multiple Azure File Shares / Blob Containers / Directories, etc.

Edit the Runbook

Once you have the Runbook created, you need to edit the Runbook, then write or add the script to choose which Azure File Share you want to sync and copy data to the Azure blob container. Of course, you can create scripts that suit your environment.

As mentioned earlier, in this example, I will create a Runbook to read and check all the files and directories in a specific Azure File Share Name, and then copy the data over to a specific blob container. And to maintain a high level of security, I will NOT use the storage account keys, instead, I will create a time limit SAS token URI for each service individually (file share and blob container), the SAS token will expire automatically after 30 minutes. So, if you regenerate your storage account keys in the future, the automation process won’t break.

Please note that you can also update the parameter section and copy between storage accounts across different subscriptions.

The script as follows:

<#
.DESCRIPTION
A Runbook example which continuously check for files and directories changes in recursive mode
for a specific Azure File Share and then copy data to blob container by leveraging AzCopy tool
which is running in a Container inside an Azure Container Instances using Service Principal in Azure AD.

.NOTES
Filename : Copy-FileShareToBlobContainer
Author   : Charbel Nemnom
Version  : 1.1
Date     : 13-January-2021
Updated  : 13-April-2021

.LINK
To provide feedback or for further assistance please visit:
https://charbelnemnom.com 
#>

Param (
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()]
    [String] $AzureSubscriptionId,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()]
    [String] $storageAccountRG,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()]
    [String] $storageAccountName,    
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()]
    [String] $storageContainerName,
    [Parameter(Mandatory = $true)][ValidateNotNullOrEmpty()]
    [String] $storageFileShareName
)

$connectionName = "AzureRunAsConnection"

Try {
    #! Get the connection "AzureRunAsConnection "
    $servicePrincipalConnection = Get-AutomationConnection -Name $connectionName
    Write-Output "Logging in to Azure..."
    Connect-AzAccount -ServicePrincipal `
        -TenantId $servicePrincipalConnection.TenantId `
        -ApplicationId $servicePrincipalConnection.ApplicationId `
        -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
Catch {
    If (!$servicePrincipalConnection) {
        $ErrorMessage = "Connection $connectionName not found..."
        throw $ErrorMessage
    }
    Else {
        Write-Error -Message $_.Exception
        throw $_.Exception
    }
}

Select-AzSubscription -SubscriptionId $AzureSubscriptionId

# Get Storage Account Key
$storageAccountKey = (Get-AzStorageAccountKey -ResourceGroupName $storageAccountRG -AccountName $storageAccountName).Value[0]

# Set AzStorageContext
$destinationContext = New-AzStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageAccountKey

# Generate Container SAS URI Token which is valid for 30 minutes ONLY with read and write permission
$blobContainerSASURI = New-AzStorageContainerSASToken -Context $destinationContext `
 -ExpiryTime(get-date).AddSeconds(1800) -FullUri -Name $storageContainerName -Permission rw

# Generate File Share SAS URI Token which is valid for 30 minutes ONLY with read and list permission
$fileShareSASURI = New-AzStorageShareSASToken -Context $destinationContext `
 -ExpiryTime(get-date).AddSeconds(1800) -FullUri -ShareName $storageFileShareName -Permission rl

# Create azCopy syntax command
$ContainerSASURI = "'" + $blobContainerSASURI + "'"
$shareSASURI = "'" + $fileShareSASURI + "'"
$command = "azcopy " + "copy " + $ShareSASURI + " " + $ContainerSASURI + " --recursive"

# Create Azure Container Instance and run the AzCopy job
# The container image (peterdavehello/azcopy:latest) is publicly available on Docker Hub and has the latest AzCopy version installed
# You could also create your own private container image and use it instead
# When you create a new container instance, the default compute resources are set to 1vCPU and 1.5GB RAM
# We recommend starting with 2 vCPU and 4 GB memory for large file shares (E.g. 3TB)
# You may need to adjust the CPU and memory based on the size and churn of your file share
New-AzContainerGroup -ResourceGroupName $storageAccountRG `
    -Name azcopyjob -image peterdavehello/azcopy:latest -OsType Linux `
    -Cpu 2 -MemoryInGB 4 -Command $command `
    -RestartPolicy never

Write-Output ("")

Save the script in the CMDLETS pane as shown in the figure below.

Sync Between Azure File Share and Azure Blob Container 4

Then test the script using the “Test pane” to verify it’s working as intended before you publish it.

Once the test is completed successfully, publish the Runbook by clicking Publish. This is a very important step.

Schedule the Runbook

In the final step, you need to schedule the Runbook to run based on your desired time to copy the changes from Azure file share to Azure blob container.

Within the same Runbook that you created in the previous step, select Schedules and then click + Add schedule.

So, if you need to schedule the Runbook to run every hour, then you need to create the following schedule with Recur every 3 Hours with Set expiration to No. You can also run it on-demand if you wish to do so.

Sync Between Azure File Share and Azure Blob Container 5

While scheduling the Runbook, you can pass on the parameters required for the PowerShell Script. In my example, I need to specify the Azure Subscription ID, Resource Group Name, Storage Account Name, Azure Blob Container Name, and the Azure File Share Name that I want to copy over. The sample script takes those parameters as input.

Sync Between Azure File Share and Azure Blob Container 6

Once done, click OK twice.

Test the Runbook

In this quick demo, I will test the Runbook and request on-demand storage sync to copy the data from an Azure file share to an Azure blob container. This scenario simulates when a user adds or modifies files directly in Azure File Share and/or Azure File Sync, and then copy the data to the Azure blob container automatically.

Monitor the Runbook

You can monitor the success or failure of these schedules using the “Jobs” tab of Runbooks under Resources. You can also see the next run schedule, in my example, the Runbook will run every 3 hours, and so forth…

Sync Between Azure File Share and Azure Blob Container 7

That’s it there you have it!

This is still version 1.0, if you have any feedback or changes that everyone should receive, please feel free to leave a comment below.

How it works…

When the runbook runs for the first time, a new container will be created and then terminated. The container will perform the copy batch job, which is not meant to run for a long time. So this container runs to complete the copy command and then stops. To prevent constant restart on completion, I have added the “-RestartPolicy Never” on the container which means it doesn’t restart when finished. This is a great way to run a batch copy job.

When the runbook runs for the second time and so on, it will start the existing container instead of creating a new container, and then run the command which includes the updated file share and blob container SAS URI Token which is valid for 30 minutes only. In this way, you get billed for the time the container was used, and to make sure you don’t expose your storage account access keys.

Please note that you may need to increase the SAS URI Token expiry time based on the amount of data you have to copy. The SAS must be valid throughout the whole job duration since we need it to interact with the service. I would suggest padding the expiration a bit just to be safe.

Summary

In this article, I showed you how to sync and copy from an Azure file share to an Azure blob container using the AzCopy tool running in a container. In this way, we can the run container with sync and copy jobs on a simple schedule and only get billed for the time the container is used.

At the time of this writing, if you deleted some files from the Azure file share, they won’t be deleted from the blob container automatically. This is a copy job and not a synchronization solution. I hope that Microsoft will update the AzCopy tool to include sync functionality so we can maintain the status between file share and blob container.

The sync command differs from the copy command in several ways as follows:

  • By default, the recursive flag is true and sync copies all subdirectories. Sync only copies the top-level files inside a directory if the recursive flag is false.
  • If the deleteDestination flag is set to true or prompt, then the sync will delete files and blobs at the destination that are not present at the source.

I hope you find this guide useful. To learn more about Azure Files, please check the following articles.

__
Thank you for reading my blog.

If you have any questions or feedback, please leave a comment.

-Charbel Nemnom-

Related Posts

Previous

How To Export and Backup Azure Policy Definitions

How to Back up and Restore Azure Managed Disks

Next

11 thoughts on “Sync Between Azure File Share and Azure Blob Container”

Leave a comment...

  1. Thank you for the great article. To clarify for myself, are you saying that there is currently no way to create a live sync from a File Share to a Blob Container? My use case – I have a single File Share with a folder that I need to be replicated automatically in a Blob Container. If I read your solution correctly, you said AzCopy does not support this kind of synchronization? If not, is it possible to achieve this through other methods?

  2. Hello Justin, thanks for your comment. Yes, you are right, at the time of this writing, there is currently no way to Sync from a File Share to a Blob Container. You can only Copy. If your file share with this particular folder is not so large, then you can follow the method described in this article and copy the data based on your desired schedule (maybe 3 times per week). Unfortunately, there are no other methods to synchronize yet. Hope this helps!

  3. Yes, that helped me. Thank you!

  4. Hello, I’ve tried your solution. It’s ok for me except that the container is launched with a public IP address I guess.
    So we need to do an “allow all” in the firewall of the storage account.

  5. Thank you Sébastien for the feedback, much appreciated! Yes, in your case you don’t need a public IP for the Azure Container Instance (ACI). You could launch ACI inside a virtual network, and then use a Service Endpoint on your Storage Account(s) down to the ACI subnet. Or you could assign a Private Endpoint for the Storage Account in the same vNet as the ACI and connect via that.
    Hope this helps! Cheers,

  6. Hi, great article!!!

    I get the error below when running a test

    Not sure where to troubleshoot this?

    ResourceGroupName : HN-AZURE-FILESYNC-UKSOUTH
    Id : /subscriptions/xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx/resourceGroups/HN-AZURE-FILESYNC-UKSOUTH/
    providers/Microsoft.ContainerInstance/containerGroups/azcopyjob
    Name : azcopyjob
    Type : Microsoft.ContainerInstance/containerGroups
    Location : uksouth
    Tags :
    ProvisioningState : Succeeded
    Containers : {azcopyjob}
    ImageRegistryCredentials :
    RestartPolicy : Never
    IpAddress :
    DnsNameLabel :
    Fqdn :
    Ports :
    OsType : Linux
    Volumes :
    State : Failed
    Events : {}
    Identity :

  7. Hello Adnan, thanks for your feedback! There could be multiple reasons for this error. It’s difficult to troubleshoot without having more details about your environment. Please check the monitoring section that I wrote in this article here and check if you can see something in the container logs.

  8. Hi Charbel, thanks for sharing! I wanted to run this modification by you, which uses a Microsoft image with az cli. For some users, an unvetted image is not an option (no disrepect meant to whoever maintains the peterdavehello images). I’ve posted the modified script here: https://gist.github.com/SvenAelterman/9bd5a1ae41399b812c0a67fb5ae92be8

    There are also a few extra parameters because I had a need to copy between different subscriptions.

  9. Thank you Sven for the comment and the respect for this work!
    I have seen your modified script, I noticed that you are using (microsoft/azure-cli) instead of (peterdavehello/azcopy:latest) image. I totally agree about using Microsoft image instead. I have a question, could you please confirm that the Microsoft container image has the AzCopy Tool version 10.8.0 installed in it and not only Azure CLI 2.0? This script requires AzCopy version 10 to work.
    As you know that you can also build your own private image and not use any public community.
    Thanks for maintaining the copyright of this script.

  10. Charbel,
    so I left a rather incomplete comment. I don’t actually know if the microsoft/azure-cli image has AzCopy installed. However, I also modified the actual copy command to use the preview “az storage copy” command instead of azcopy.

  11. Thanks Sven, it’s clear now. You are purely using Azure CLI commands. Yes, this would work for this particular scenario. It would be interesting to test the performance copy between “az storage copy” and “AzCopy copy” commands. From my personal experience, AzCopy is faster. However, if you need to sync between two file shares, then you need to use “AzCopy” tool instead, Azure CLI does not have this capability. Here is a detailed guide to sync between two Azure File Shares for Disaster Recovery. Thanks!

Let me know what you think, or ask a question...

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Subscribe to Charbel Nemnom’s Blog

Get the latest posts delivered right to your inbox

The content of this website is copyrighted from being plagiarized! You can copy from the 'Code Blocks' in Black.

Please send your feedback to the author using this form for any 'Code' you like.

Thank you for visiting!