MS Certificering: AZ-204, overnieuw beginnen, deel 03

Ingediend door Dirk Hornstra op 21-dec-2021 15:10

Na het 1e blok: Azure App Service web apps (link) en het 2e blok: Implement Azure Functions (link) is het nu tijd voor het 3e learning-block: Develop solutions that use Blob storage, link.

Module 1: Explore Azure Blob storage, link.

Azure Blob storage is de oplossing van Microsoft om grote hoeveelheden ongestructureerde data op te slaan.

Zo wordt het gebruikt om afbeeldingen aan de browser te leveren, bestanden opslaan zodat die vanaf die plek verspreid kunnen worden, streamen van video en auto, data in logbestanden schrijven, opslaan van data voor backup en restore, recovery naar rampen en voor het archiveren van data.
Of voor het opslaan van data voor analyse door een service die on-premise of in Azure draait.

Objecten zijn via Azure Storage REST API, Azure PowerShell, Azure CLI of Azure Storage client library te benaderen.

Je hebt 2 type storage accounts. Standard: general purpose v2, aanbevolen. Premium: hogere performance door SSD schijven. Met premium kies je vervolgens voor block blobs, page blobs of file shares (als je NFS file-shares in Azure Files wilt gebruiken). Een standard v2 kan blob, queue, table storage en azure files.

Je hebt de verschillende type abonnementen, Hot voor snelle en herhalende toegang tot data, opslag is duurder, Cool voor grote datahoeveelheden opslaan die niet erg vaak benaderd worden, opslag voor 30 dagen. Toegang is duurder, opslag goedkoper. Archive is alleen beschikbaar voor individuele block blobs. Data ophalen kan soms een paar uur duren. Blijft staan voor 180 dagen. Als er iets in je specs verandert, kun je een tier aanpassen (dus als je nu Cool hebt, kun je dat omzetten naar Hot als je vaker toegang nodig hebt).

Als je blob storage hebt, dan kun je kiezen uit bijvoorbeeld een Storage account. Elk object heeft een adres, dus op https://jouwnaam.blob.core.windows.net

Of je gaat voor containers, vergelijkbaar met een bestandssysteem. Een storage account kan een ontelbare hoeveelheid containers bevatten en een container kan een ontelbaar aantal blobs hebben. De naam van de container moet lower-case zijn.

Of je gaat voor de blobs, block blob: tekst en binaire data, tot 4.7 GB. De blokken kunnen los bewerkt worden. append blob: lijkt op block blobs, maar is geoptimaliseerd voor toevoegen, ideaal voor het loggen van data. page blobs: random data opslaan, tot 8TB. Opslag voor virtuele harde schijven VHD en als disks voor virtuele machines.

Alle data (ook metadata) wordt encrypted opgeslagen met Storage Service Encryption (SSE).
Je kunt Azure Active Directory en RBAC (role-based access control) gebruiken om data te benaderen.
RBAC rollen krijgen een scope op het storage account aan een security principal en Azure AD om key management te beheren.
Maar ook Azure AD integratie voor blob en queue data acties. De scope kan zich beperken tot abonnement, resource groep, storage account of losse container of queue.
Data die over de lijn gaat kan beveiligd worden, via client side encryption, HTTPS of SMB 3.0.
OS en data disks die die virtuele machines gebruikt worden kunnen geëncrypt worden met Azure Disk Encryption
Toegang verlenen kan met een shared access signature.

Encryptie in rust wordt met 256-bit AES encryptie gedaan, FIPS 140-2 compliant, vergelijkbaar met BitLocker encryptie op WIndows.
Encryptie staat standaard aan.

Je kunt Microsoft het key-beheer laten doen, maar je kunt ook zelf je keys beheren. Met je eigen keys heb je 2 keuzes, of customer-managed key die je gebruikt voor encryptie en decryptie. Deze encrypt alle data in je storage account. Of je hebt een customer-provided key voor blob storage acties. Een client die een read of write actie wil uitvoeren kan een encryptie-key bevatten en daarmee controle hebben over encryptie en decryptie.

Hier nog even de verschillen:

  Microsoft-managed keys Customer-managed keys Customer-provided keys
Encryption/decryption operations Azure Azure Azure
Azure Storage services supported All Blob storage, Azure Files Blob storage
Key storage Microsoft key store Azure Key Vault Azure Key Vault or any other key store
Key rotation responsibility Microsoft Customer Customer
Key usage Microsoft Azure portal, Storage Resource Provider REST API, Azure Storage management libraries, PowerShell, CLI Azure Storage REST API (Blob storage), Azure Storage client libraries
Key access Microsoft only Microsoft, Customer Customer only


Data wordt redundant opgeslagen, zodat bij een probleem je data niet weg is.

Je hebt Locally redundant storage (LRS): 3x kopie binnen een enkele fysieke locatie in de primaire regio. Goedkoopste variant, niet aan te raden als er hoge beschikbaarheid of data langdurig beschikbaar moet zijn.
Zone-redundant storage (ZRS), kopieert je data synchroon tussen 3 availability zones in de primaire regio.

Wil je echt zekerheid, dan laat je de data ook redundant zijn in een secundaire regio.
Geo-redundant storage (GRS): kopie 3x synchroon in een enkele fysieke locatie. Kopieer asynchroon naar een secundaire regio. Daar wordt het weer 3x synchroon LRS gekopieerd.
Geo-zone-redundant storage (GZRS): kopieer data synchroon naar 3 availability zones in de primaire regio met ZRS. Kopie asynchroon naar een enkele locatie in de secundaire regio. Daar weer 3x gekopieerd via LRS.

Vervolgens wordt een oefening gedaan om een block blob storage account aan te maken. Ook hier, geen sandbox meer.

Aanmaken van een resource group:


az group create --name az204-blob-rg --location <myLocation>

Aanmaken van een block storage account:


az storage account create --resource-group az204-blob-rg --name \
<myStorageAcct> --location <myLocation> \
--kind BlockBlobStorage --sku Premium_LRS

Boel weer opruimen:


az group delete --name az204-blob-rg --no-wait


Module 2: Manage the Azure Blob storage lifecycle, link.

Dit deel gaat over de lifecycle van blob storage. We hebben de hot, cool en archive varianten al besproken. Daarbij was nog niet gezegd dat hot en cool ingesteld kunnen worden op accountniveau. Archive geef je per blob aan. Archive data is ook echt "offline" opgeslagen, daarom de langere duur om iets terug te zetten. Met een lifecycle policy kun je zaken automatisch laten uitvoeren:

  • zet blobs over naar cool of archive om te optimaliseren voor performance en kosten
  • verwijder blobs als de levensduur voorbij is
  • definieer regels om 1x per dag op het niveau van storage account uitgevoerd te worden
  • voer regels uit op containers of op subsets van blobs (met het gebruik van prefixes als filter)


Sommige data wordt alleen de eerste dagen vaak bekeken (aanbiedingen week 17 december), maar na 2 weken al bijna niet meer. Het is dan logischer om de eerste week de blob in hot te zetten en daarna in cool.

Zo'n lifecycle policy is een aantal regels in een JSON bestand.

Voorbeeld:


{
  "rules": [
    {
      "name": "ruleFoo",
      "enabled": true,
      "type": "Lifecycle",
      "definition": {
        "filters": {
          "blobTypes": [ "blockBlob" ],
          "prefixMatch": [ "container1/foo" ]
        },
        "actions": {
          "baseBlob": {
            "tierToCool": { "daysAfterModificationGreaterThan": 30 },
            "tierToArchive": { "daysAfterModificationGreaterThan": 90 },
            "delete": { "daysAfterModificationGreaterThan": 2555 }
          },
          "snapshot": {
            "delete": { "daysAfterCreationGreaterThan": 90 }
          }
        }
      }
    }
  ]
}

Je kunt maximaal 100 rules in een policy plaatsen.
Name: string, max 256 alfanumerieke tekens, uniek binnen een policy, hoofdletter-gevoelig
Enabled: optionele waarde, standaard true
Type: op dit moment is "Lifecycle" de enige geldige waarde
Definition: filter set en action set

Als je meerdere filters hebt, dan wordt die als een AND uitgevoerd (moet dus allemaal waar zijn).

blobType: array van enum waardes: verplicht
prefixMatch: array van strings voor prefixes, per regel maximaal 10 stuks, prefix moet starten met containernaam: optioneel
blobIndexMatch: array van dictionary waardes bestaande uit blob index tag key en waarde die moet voldoen aan de match. Elke rule kan tot 10 blob index tag conditions hebben.

Als er 2 voorwaardes voldoen, wordt de goedkoopste actie gekozen. Dus een "delete" is goedkoper dan een "archive".
Voorwaardes vergelijken op basis van leeftijd. Bij blobs is dat de last modified time, bij snapshots de snapshot creation time.

tierToCool en tierToArchive zijn zowel voor een blockBlob als snapshot en "versie" mogelijk. Een enableAutoTierToHotFromCool, dat kan alleen een blockBlob. delete kan uitgevoerd worden op blockBlob, appendBlob en snapshot en "versie".

Daarna volgt een voorbeeld waar je in je resource group, blob service, lifecycle management je eigen rules aan gaat maken.

Als je met de CLI wilt werken, moet je zelf eerst de policy.json aanmaken en die met het volgende statement doorvoeren:


az storage account management-policy create \
    --account-name <storage-account> \
    --policy @policy.json \
    --resource-group <resource-group>

Als je data uit een archived tier wilt ophalen, moet je dit "rehydraten" naar een hot of cool tier. Je kunt een gearchiveerde blob kopiëren naar een online tier, dat kan met Copy Blob of Copy Blob from URL actie. Volgens Microsoft in 9 van de 10 gevallen is dit "dé" manier.
Of wijzig de access tier naar een online tier: dit kan door de Set Blob Tier actie uit te voeren. Omdat het lang duurt om de boel terug te zetten het advies van Microsoft om het per groot aantal blobs te doen. Doe je steeds een paar kleine blobs, dan kun je lang bezig zijn.

Met die Set Blob Tier of Copy Blob from URL kun je nog een header meegeven: x-ms-rehydrate-priority
Hiermee kun je de standard priority meegeven, maximaal 15 uur wachten, of high priority, hiermee is het mogelijk dat je restore binnen een uur klaar is (objecten moeten dan wel kleiner dan 10GB zijn).

Een copy blob actie kan alleen binnen hetzelfde storage account. Je kunt altijd van hot naar hot, hot naar cool en hot naar archive. Ook van cool naar hot, cool naar cool en cool naar archive. Archive kun je naar cool en hot sturen, binnen hetzelfde account en vereist dus "hydration". Je kunt niet van archive naar archive.

Als je een archive blob terugzet naar een hot of coole tier, dan kun je het verzoek niet annuleren. Uitleg hoe je dit doet kun je hier nalezen: link.

En let op, de modification time blijft gelijk. Dus een policy die uitgevoerd wordt kan zorgen dat je nieuwe hot of cool tier automatisch weer omgezet wordt naar een archive. Pas dat eerst aan (schakel het uit oid).

Module 3: Work with Azure Blob storage, link.

Azure client libraries voor .NET maakt het werken in code weer wat makkelijker. De nieuwste versie is 12.x, welke door Microsoft wordt aangeraden om te gebruiken.

  • BlobClient: manipuleer Azure Storage blobs.
  • BlobClientOptions: client-configuratie.
  • BlobContainerClient: manipuleer Azure Storage Containers en de blobs die daarin zitten.
  • BlobServiceClient: manipuleer Azure Storage service resources en blob containers.
  • BlobUriBuilder: handige manier om de inhoud van een Uri naar een andere Azure Storage acount te laten verwijzen, zoals account, container of blob.


Vervolgens beginnen we met een voorbeeld. We gaan dit in Visual Studio Code doen. Daarvoor heb je de Azure CLI nodig: link.


az login

az group create --location <myLocation> --name az204-blob-rg

// een storage account heeft minimaal 3 en maximaal 24 tekens, bestaande uit letters en cijfers

az storage account create --resource-group az204-blob-rg --name <myStorageAcct> --location <myLocation> --sku Standard_LRS

// .NET project aanmaken

dotnet new console -n az204-blob

cd az204-blob
dotnet build

mkdir data

dotnet add package Azure.Storage.Blobs

// inhoud program.cs

using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using System;
using System.IO;
using System.Threading.Tasks;

namespace az204_blob
{
    class Program
    {
        public static void Main()
        {
            Console.WriteLine("Azure Blob Storage exercise\n");

            // Run the examples asynchronously, wait for the results before proceeding
            ProcessAsync().GetAwaiter().GetResult();

            Console.WriteLine("Press enter to exit the sample application.");
            Console.ReadLine();

        }

        private static async Task ProcessAsync()
        {
            // Copy the connection string from the portal in the variable below.
            string storageConnectionString = "CONNECTION STRING";

            // Create a client that can authenticate with a connection string
            BlobServiceClient blobServiceClient = new BlobServiceClient(storageConnectionString);

            // EXAMPLE CODE STARTS BELOW HERE


        }
    }
}

// maak een container aan

//Create a unique name for the container
string containerName = "wtblob" + Guid.NewGuid().ToString();

// Create the container and return a container client object
BlobContainerClient containerClient = await blobServiceClient.CreateBlobContainerAsync(containerName);
Console.WriteLine("A container named '" + containerName + "' has been created. " +
    "\nTake a minute and verify in the portal." +
    "\nNext a file will be created and uploaded to the container.");
Console.WriteLine("Press 'Enter' to continue.");
Console.ReadLine();

// upload blobs naar de container

// Create a local file in the ./data/ directory for uploading and downloading
string localPath = "./data/";
string fileName = "wtfile" + Guid.NewGuid().ToString() + ".txt";
string localFilePath = Path.Combine(localPath, fileName);

// Write text to the file
await File.WriteAllTextAsync(localFilePath, "Hello, World!");

// Get a reference to the blob
BlobClient blobClient = containerClient.GetBlobClient(fileName);

Console.WriteLine("Uploading to Blob storage as blob:\n\t {0}\n", blobClient.Uri);

// Open the file and upload its data
using FileStream uploadFileStream = File.OpenRead(localFilePath);
await blobClient.UploadAsync(uploadFileStream, true);
uploadFileStream.Close();

Console.WriteLine("\nThe file was uploaded. We'll verify by listing" +
        " the blobs next.");
Console.WriteLine("Press 'Enter' to continue.");
Console.ReadLine();

// toon de blobs in een container

// List blobs in the container
Console.WriteLine("Listing blobs...");
await foreach (BlobItem blobItem in containerClient.GetBlobsAsync())
{
    Console.WriteLine("\t" + blobItem.Name);
}

Console.WriteLine("\nYou can also verify by looking inside the " +
        "container in the portal." +
        "\nNext the blob will be downloaded with an altered file name.");
Console.WriteLine("Press 'Enter' to continue.");
Console.ReadLine();

// download blobs

// Download the blob to a local file
// Append the string "DOWNLOADED" before the .txt extension
string downloadFilePath = localFilePath.Replace(".txt", "DOWNLOADED.txt");

Console.WriteLine("\nDownloading blob to\n\t{0}\n", downloadFilePath);

// Download the blob's contents and save it to a file
BlobDownloadInfo download = await blobClient.DownloadAsync();

using (FileStream downloadFileStream = File.OpenWrite(downloadFilePath))
{
    await download.Content.CopyToAsync(downloadFileStream);
    downloadFileStream.Close();
}
Console.WriteLine("\nLocate the local file to verify it was downloaded.");
Console.WriteLine("The next step is to delete the container and local files.");
Console.WriteLine("Press 'Enter' to continue.");
Console.ReadLine();

// verwijder container

// Delete the container and clean up local files created
Console.WriteLine("\n\nDeleting blob container...");
await containerClient.DeleteAsync();

Console.WriteLine("Deleting the local source and downloaded files...");
File.Delete(localFilePath);
File.Delete(downloadFilePath);

Console.WriteLine("Finished cleaning up.");

// runnen van de app
dotnet build
dotnet run

// opruimen

az group delete --name az204-blob-rg --no-wait

Blob containers hebben systeem eigenschappen en gebruiker-gedefinieerde data (de meta-data).

De BlobContainerClient class heeft een GetProperties en GetPropertiesAsync.

Voorbeeld:


private static async Task ReadContainerPropertiesAsync(BlobContainerClient container)
{
    try
    {
        // Fetch some container properties and write out their values.
        var properties = await container.GetPropertiesAsync();
        Console.WriteLine($"Properties for container {container.Uri}");
        Console.WriteLine($"Public access level: {properties.Value.PublicAccess}");
        Console.WriteLine($"Last modified time in UTC: {properties.Value.LastModified}");
    }
    catch (RequestFailedException e)
    {
        Console.WriteLine($"HTTP error code {e.Status}: {e.ErrorCode}");
        Console.WriteLine(e.Message);
        Console.ReadLine();
    }
}

Ook zijn er de SetMetadata en SetMetadataAsync, die roep je met een IDictionary aan om de waardes in te stellen.

Je kunt ook meta-data instellen via REST. Dit gaat via de header x-ms-meta-name:string-value

Totale grootte van metadata (per paar) is 8KB.

Opvragen data:


GET/HEAD https://myaccount.blob.core.windows.net/mycontainer?restype=container

GET/HEAD https://myaccount.blob.core.windows.net/mycontainer/myblob?comp=metadata

Instellen data:


PUT https://myaccount.blob.core.windows.net/mycontainer?comp=metadata&restype=container

PUT https://myaccount.blob.core.windows.net/mycontainer/myblob?comp=metadata

De standaard HTTP headers die gelden voor containers: ETag en Last-Modified.

De lijst op blobs is wat langer: ETag, Last-Modified, Content-Length, Content-Type, Content-MD5, Content-Encoding, Content-Language, Cache-Control, Origin, Range.