If just like me you made a Ghost blog using an Azure File Share, we will see how we can backup and restore our precious files in two ways.

Sources files are available here.

Built-in backups

The easiest way is to activate the backup option in the file share like so :

azure-backup

Backup costs will apply. But what if we want to export the data outside of Azure?

AzCopy

A utility has been made to manually copy to or from Azure. It will be usefull to bypass the limited options available in the portal right now.

Install the utility

  • Download the executable inside a folder on your machine.
  • Edit the environment system variables on Windows.
  • Inside the Path variable, add the location to your AzCopy.exe's folder.
  • Restart your shell or Visual Studio Code for the setting to take effect.

Create a backup script

We will use powershell for this, as it is cross platform.

Juste fill-in the variables and your almost done!

$storageSubscription = ""
$storageAccountName = ""
$storageAccountKey = ""
$storageRessourceGroup = ""
$storageFileShareName = ""

$expiry = (Get-Date).AddHours(12).ToString("yyyy-MM-ddTHH:mmZ")

$sasToken = az storage share generate-sas `
    --subscription $storageSubscription `
    --account-key $storageAccountKey `
    --account-name $storageAccountName `
    --name $storageFileShareName `
    --expiry $expiry `
    --permissions lr

Remove-Item -LiteralPath "./${storageFileShareName}" -Force -Recurse 
azcopy copy "https://${storageAccountName}.file.core.windows.net/${storageFileShareName}?${sasToken}" './' --recursive

az storage account revoke-delegation-keys `
    --subscription $storageSubscription `
    --name $storageAccountName `
    --resource-group $storageRessourceGroup

Before executing it, you need to login first.

azcopy login --tenant-id <tenantId>

If everything worked fine, you should have a folder created with your files!

Create a restore script

This is kinda the same thing but be aware that the script DELETES all files before restoring so no scrap is preserved.

$storageSubscription = ""
$storageAccountName = ""
$storageAccountKey = ""
$storageRessourceGroup = ""
$storageFileShareName = ""

$expiry = (Get-Date).AddHours(12).ToString("yyyy-MM-ddTHH:mmZ")

$sasToken = az storage share generate-sas `
    --subscription $storageSubscription `
    --account-key $storageAccountKey `
    --account-name $storageAccountName `
    --name $storageFileShareName `
    --expiry $expiry `
    --permissions dlrw

kubectl scale deployment.v1.apps/nginx-deployment --replicas=0
azcopy rm "https://${storageAccountName}.file.core.windows.net/${storageFileShareName}?${sasToken}" --recursive=true
azcopy copy "./$storageFileShareName/*" "https://${storageAccountName}.file.core.windows.net/${storageFileShareName}/?${sasToken}" --recursive 

az storage account revoke-delegation-keys `
    --subscription $storageSubscription `
    --name $storageAccountName `
    --resource-group $storageRessourceGroup

Release holds

If you created the file share to be mounted inside Kubernetes, make sure to scale down the deployment to 0 to release holds on files before restoring.

Get the deployment name :

kubectl get deployments --namespace=blog

Scale down the deployment using the API group apps in version 1 :

kubectl scale deployment.v1.apps/blog --replicas=0 --namespace=blog

Scale it back after and you're done!

Going furter

With thoses scripts you can opt for a more strict workflow.

Code first

I very much like the idea that everything that I write is backed in the source control like Git. If you choose to, you can :

  • Setup a local Ghost Docker with a volume to the source control.
  • Use the Ghost's admin portal to write your publications.
  • Commit.
  • With a pipeline like Azure DevOps, deploy your files using the restore script.

Database first

This way is a little more versatile as you can write your posts on the web using any devices. It goes like this :

  • Write a post on your production blog.
  • When you're ready, execute the backup script and point it to your source control.
  • Commit the files.

If you have a better way, feel free to comment!