Mobile, Praca w IT

Jak zarządzać feature flags w aplikacjach ASP.NET Core przy użyciu Azure?

laptop na tle ściany z cegieł

Niezależnie od tego czy aplikacja jest prosta, czy bardziej złożona, wybór właściwego dostawcy konfiguracji na samym początku ułatwi późniejsze zarządzanie feature flags i dodawanie odpowiednich filtrów. 

W moich artykułach dostępnych na blogu Predica Group opisałem, czym są feature flags i jak je implementować w aplikacjach .NET. Jeśli potrzebujesz więcej informacji, to polecam zacząć od tych dwóch wpisów.

Gdy feature flags zostaną zaimplementowane, trzeba zdecydować, gdzie je przechowywać. Jeśli chcesz się dowiedzieć, jakie narzędzie jest przeze mnie preferowane i dlaczego, przeczytaj poniższy artykuł.

Gdzie najlepiej przechowywać konfigurację feature flags? 

W artykule wprowadzającym opisałem bibliotekę Microsoft.FeatureManagement jako pomocne narzędzie w implementacji feature flags. Co więcej, jest ono użyteczne również w przypadku przechowywania feature flags. 

Biblioteka Microsoft.FeatureManagement działa na standardowej konfiguracji ASP.NET Core, dzięki czemu można wybrać dowolnego dostawcę konfiguracji. 

Przykładem mogą być zmienne środowiskowe lub pliki appsettings.json:

"FeatureManagement": {
    "UseExtremeScaling": false,
    "UsePromotionCoupons": {
        "EnabledFor": [
            {
                "Name": "Microsoft.Targeting",
                "Parameters": {
                    "DefaultRolloutPercentage": 1
                },
            },
        ],
    },
  },

Wybór najlepszego dostawcy konfiguracji dla zarządzania funkcjami zależy głównie od stopnia złożoności aplikacji. 

W przypadku bardzo prostych aplikacji, pliki JSON i zmienne środowiskowe będą prawdopodobnie wystarczające. 

Jednak gdy w projekcie zaimplementowano wiele różnych feature flags i chcesz mieć przyjazny dla użytkownika portal do ich przeglądania i edycji, warto skorzystać z Azure App Configuration.

Czym jest Azure App Configuration? 

Jest to usługa przechowywania konfiguracji w chmurze Azure, która umożliwia zespołom deweloperskim zarządzanie parametrami aplikacji w czasie rzeczywistym, bez konieczności wdrażania kodu. Rozwiązanie to jest szybkie, skalowalne i bezpieczne. 

Z perspektywy feature flags, kluczową możliwością jest wbudowane wsparcie dla nich. 

Ponadto panel administracyjny dla feature flags jest funkcjonalny i atrakcyjny wizualnie:

W panelu możesz włączać/wyłączać proste feature flags, a także korzystać z wbudowanego edytora dla filtrów, takich jak:

  • Okno czasowe 
  • Kierowanie do określonych odbiorców 
  • Niestandardowe (własne filtry)

Jeśli nie jesteś zaznajomiony z filtrami funkcji, gorąco zachęcam do zapoznania się z moim artykułem, w którym bardziej szczegółowo je opisuję.

Inną wielką korzyścią jest scentralizowane przechowywanie konfiguracji zarządzania funkcjami. Na pewno się to przyda, jeśli masz do czynienia z wieloma (mikro)usługami, które korzystają z tych samych feature flags.

Na koniec, integracja z biblioteką Microsoft.FeatureManagement to prawdziwa bułka z masłem.

Azure App Configuration to po prostu kolejny dostawca konfiguracji .NET, więc po podłączeniu aplikacji do niego, feature flags są automatycznie skonfigurowane.

Jak utworzyć Azure App Configuration? 

Najłatwiejszym sposobem na uruchomienie Azure App Configuration jest użycie Azure Portal.

Oto co musisz zrobić:

1. Najpierw otwórz Azure Portal i kliknij przycisk „Create a resource”:

2. Następnie wybierz „App Configuration” z paska wyszukiwania:

3. Następnie kliknij przycisk „Create”:

4. Teraz musimy podać wszystkie niezbędne szczegóły, takie jak resource group, lokalizacja, nazwa zasobu, opcje odzyskiwania i poziom cenowy.

Jeśli nie jesteś pewien, co wybrać, sprawdź poziomy cenowe w dokumentacji Azure, aby wybrać plan odpowiadający Twoim potrzebom.

5. Następnie możesz dodać tagi i skonfigurować sieć dla Azure App Configuration (np. aby umożliwić dostęp tylko dla określonej sieci wirtualnej Azure).

Dla zwięzłości pomińmy ten krok i kliknij “Review + Create”.

Po zakończeniu poprawnej walidacji możemy utworzyć Azure App Configuration, korzystając z przycisku “Create”:

6. Po kilku minutach Azure App Configuration powinno być gotowe do użycia.

7. Na koniec możemy przejść do strony zasobu, aby zobaczyć podsumowanie naszego Azure App Configuration:

Przydatne podstrony, z którymi warto się zapoznać to:

  • Access Keys – gdzie możesz uzyskać klucz dostępu potrzebny do połączenia aplikacji z zasobem,
  • Feature Manager – ekran zarządzania feature flags, który pokazałem na początku tego artykułu. 

Na chwilę teraz opuśćmy Azure Portal i przejdźmy do kodu źródłowego aplikacji, gdzie połączymy ją z Azure App Configuration.

Jak dodać Azure App Configuration do projektu? 

W tym momencie przypuszczam, że już dodał*ś bibliotekę Microsoft.FeatureManagement do swojej aplikacji.

Jeśli nie jesteś pewien/na, jak to zrobić, możesz znaleźć więcej instrukcji i postępować zgodnie z krokami opisanymi w moim poprzednim artykule.

Jak zwykle, zaczniemy od zainstalowania pakietu NuGet:

dotnet add package Microsoft.Azure.AppConfiguration.AspNetCore

Następnie możemy zarejestrować Azure App Configuration jako dostawcę konfiguracji za pomocą poniższego kodu:

// Program.cs
Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
        webBuilder.ConfigureAppConfiguration(config =>
        {
            var settings = config.Build();
            config.AddAzureAppConfiguration(appConfig =>
                appConfig.Connect(settings["AppConfig:ConnectionString"].UseFeatureFlags())
        }).UseStartup());

Polega to na pobraniu connection string do Azure App Configuration z bieżącej konfiguracji, a następnie zarejestrowaniu Azure App Configuration jako nowego dostawcy konfiguracji.

Metoda UseFeatureFlags umożliwia przechowywanie feature flags Azure App Configuration w sekcji konfiguracji FeatureManagement, co jest potrzebne dla Microsoft.FeatureManagement.

To zachowanie można skonfigurować, i niedługo powrócimy do tego fragmentu kodu.

Kolejnym krokiem jest zarejestrowanie Azure App Configuration w kontenerze DI (Dependency Injection) i dodanie odpowiedniego middleware request pipeline.

using Microsoft.Extensions.Configuration;


public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // ...
        services.AddAzureAppConfiguration(); // <- Add this line
        // ...
    }
    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        
        app.UseAzureAppConfiguration(); // <- Add this line
        app.UseHttpsRedirection();
        app.UseRouting();


       // ...
    }
}

Przed uruchomieniem aplikacji musimy podać connection string do Azure App Configuration. Możemy go znaleźć w Azure Portal na podstronie klucze dostępu (Access Keys).

Możliwe jest również skonfigurowanie połączenia bez użycia kluczy dostępu, ale z użyciem tożsamości zarządzanych przez Azure Active Directory do uwierzytelnienia.

Jest to bezpieczniejsze niż używanie connection string, więc na środowisku produkcyjnym jest to lepsze rozwiązanie. Polecam sprawdzenie tej strony, aby dowiedzieć się więcej.

Skopiujmy connection string do użycia w aplikacji.

Podczas inicjalizacji aplikacji otrzymujemy wartość dla klucza AppConfig:ConnectionString.W pliku appsettings.json wyglądałoby to tak:

{
    "AppConfig" : {
        "ConnectionString" : "SECRET",
    }
}

Umieszczenie ciągu połączenia w pliku appsettings.json jest kuszące, ale jeśli chodzi o bezpieczeństwo, stworzyłoby to potencjalne ryzyko. Co jak co ale są to wrażliwe dane, dlatego należy je przechowywać ostrożnie.

Lokalnie możesz skorzystać z ASP.NET. Core user secrets oraz App Service Configuration w portalu Azure na produkcji lub, co lepsze, Azure Key Vault.

I to wszystko. Aplikacja może teraz korzystać z Azure App Configuration jako magazynu feature flags, a Ty możesz zmieniać konfigurację w czasie rzeczywistym.

Dodajmy więc pierwszą feature flag do Azure App Configuration.

Jak zarządzać feature flags w Azure App Configuration? 

Najpierw dodamy feature flag UsePromotionCoupons do App Configuration.

W artykule zaznamiającym z feature flags wyjaśniałem, jak ją dodać do aplikacji, więc jeśli jest Ci to obce, przejdź najpierw tam. 

Zaczniemy od przejścia do podstrony menedżera funkcji w portalu Azure. Następnie kliknij przycisk “Create”, aby dodać nową feature flag i nadaj jej nazwę.

Klucz zostanie automatycznie uzupełniony na podstawie nazwy, ale wrócimy do tego później.

Możemy również dodać etykietę oraz opis, włączyć feature flag i skonfigurować filtry funkcji.

Na koniec klikamy przycisk “Apply”. Feature flag zostanie utworzona i będzie widoczna na podstronie menedżera funkcji.

Kiedy teraz uruchomisz aplikację, powinna ona odczytać wartość feature flag z Azure App Configuration, a wartość można zmieniać z podstrony menedżera funkcji. Nie musisz ponownie uruchamiać aplikacji!

Pamiętaj jednak, że wartości z Azure App Configuration są przechowywane w pamięci podręcznej aplikacji.

Domyślnie feature flags są buforowane przez 30 sekund. W dalszej części artykułu pokażę Ci, jak to zmienić.

Jak skonfigurować filtry funkcji? 

Już wiesz, jak włączać/wyłączać flagi funkcji w Azure App Configuration.

Jednak jeśli czytałeś mój artykuł wprowadzający, prawdopodobnie pamiętasz, że możemy również używać filtrów funkcji, aby włączać feature flag, gdy spełniony jest określony warunek.

Biblioteka Microsoft.FeatureManagement ma dwa wbudowane filtry:

  • Targeting – umożliwia włączanie funkcji dla określonej grupy lub udziału wszystkich użytkowników aplikacji (np. tylko 1% wszystkich użytkowników będzie miało dostęp do funkcji),
  • Time window – umożliwia włączanie feature flags dla wszystkich użytkowników w określonym czasie (np. tylko w ten weekend).

Oba z nich są obsługiwane przez Azure App Configuration i można je skonfigurować na podstronie menedżera funkcji.

Oto przegląd filtra funkcji Targeting:

Poniżej widać jak skonfigurować drugi rodzaj filtru, czyli Time window:

Po zapisaniu zmian filtr zostanie zsynchronizowany z aplikacją. Jeśli jest poprawnie zarejestrowany, powinien działać bez konieczności restartowania aplikacji (ale zwróć uwagę na pamięć podręczną!).

Jeśli z jakiegoś powodu wbudowane filtry nie spełniają Twoich oczekiwań, istnieje jeszcze jedna opcja: dodanie niestandardowych filtrów cech.

W artykule wprowadzającym z tej serii pokazałem Ci, jak zbudować ClaimsCheckFeatureFilter, i będziemy postępować tak samo i tutaj:

using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.FeatureManagement;
namespace Predica.FeatureFlagsExample;


[FilterAlias("ClaimsCheck")]
public class ClaimsCheckFeatureFilter : IFeatureFilter
{
    private readonly IHttpContextAccessor _httpContextAccessor;


    public ClaimsCheckFeatureFilter(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }


    public Task EvaluateAsync(FeatureFilterEvaluationContext context)
    {
        var settings = context.Parameters.Get()
                       ?? new ClaimsCheckFeatureFilterSettings();
        var strValue = _httpContextAccessor.HttpContext?.User.FindFirstValue(
            settings.ClaimType);
        var parsed = bool.TryParse(strValue, out var claimValue);
        var isFeatureOn = parsed && claimValue;
        return Task.FromResult(isFeatureOn);
    }
}

Tutaj będzie trzeba dostosować ustawienia dla ClaimType.

namespace Predica.FeatureFlagsExample;


public class ClaimsCheckFeatureFilterSettings
{
    public string ClaimType { get; set; }
}

Możesz przechowywać go w konfiguracji Azure App Configuration.

Podczas edycji strony, wybierz "Custom" i nadaj mu nazwę. Pamiętaj, aby dopasować go do typu lub aliasu:

Następnie, dodaj parametr dla filtru, wybierając "edit filter parameters" z menu rozwijanego:

Na koniec, podaj nazwę parametru i jego wartość:

I to wszystko! Pomyślnie skonfigurowałeś niestandardowy filtr.

Podobnie jak w przypadku innych wbudowanych filtrów, nie musisz restartować aplikacji, jeśli filtr jest w niej zarejestrowany.

Jak skonfigurować pamięć podręczną dla feature flags przechowywanych w Azure App Configuration?

Jak wspomniałem wcześniej, feature flags są ukryte przez Azure App Configuration, aby uniknąć niepotrzebnego zużycia zasobów, takich jak CPU czy przepustowość sieciowa.

Domyślnie feature flags są przechowywane w pamięci podręcznej przez 30 sekund, ale łatwo możemy to zmienić podczas inicjalizacji aplikacji:

// Program.cs
Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
        webBuilder
            .ConfigureAppConfiguration(config =>
            {
                var settings = config.Build();
                config.AddAzureAppConfiguration(appConfig =>
                    appConfig.Connect(settings["AppConfig:ConnectionString"])
                        .UseFeatureFlags(featureFlagsConfig =>
                        {
                            // Add this config
                            featureFlagsConfig.CacheExpirationInterval =
                                TimeSpan.FromSeconds(5);
                        }));
            })
            .UseStartup());

Właściwość CacheExpirationInterval kontroluje czas, jaki musi upłynąć przed aktualizacją feature flags z App Configuration. Nie może być mniejsza niż jedna sekunda, ale nie ma maksymalnej wartości wygaśnięcia zmian.

Zgodnie z powyższym przykładem kodu, aplikacja jest skonfigurowana tak, aby odświeżać pamięć podręczną co pięć sekund.

Jak filtrować feature flags? 

Jeśli mamy aplikację z kilkoma feature flags i tylko jednym środowiskiem, zarządzanie feature flags jest dość proste.

Ale co w przypadku bardziej złożonych scenariuszy? Załóżmy, że aplikacja ma dwa środowiska:

  • środowisko deweloperskie - używane tylko do celów deweloperskich,
  • środowisko produkcyjne - działająca aplikacja obsługująca rzeczywistych użytkowników. 

Wyobraźmy sobie, że chcemy ustawić feature flags z różnymi wartościami dla każdego środowiska. Na przykład, włączamy funkcję w środowisku deweloperskim, ale wyłączamy ją w drugim.

Oczywiście, możemy mieć dedykowany App Configuration dla każdego środowiska. Jednak byłoby to dość kosztowne, więc aby zmniejszyć rachunek za usługi chmurowe, mamy tylko jedną instancję obejmującą oba środowiska aplikacji.

Na szczęście Azure App Configuration oferuje przydatną opcję o nazwie etykiety (labels), która idealnie pasuje do tego scenariusza.

W skrócie możemy mieć wiele feature flags o tej samej nazwie, ale różnych etykietach, dzięki czemu nasza aplikacja będzie pobierać tylko feature flags z odpowiednimi etykietami.

Oto jak można je utworzyć:

Następnie można je włączyć dla określonego środowiska:

Aby włączyć tę opcję, musimy jednak zmienić inicjalizację aplikacji, aby mogła pobierać flagi ze zdefiniowanymi etykietami:

// Program.cs
Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
        webBuilder
            .ConfigureAppConfiguration(config =>
            {
                var settings = config.Build();
                config.AddAzureAppConfiguration(appConfig =>
                    appConfig.Connect(settings["AppConfig:ConnectionString"])
                        .UseFeatureFlags(featureFlagsConfig =>
                        {
                            featureFlagsConfig.CacheExpirationInterval = 
                                TimeSpan.FromSeconds(5);
                            
                            // Add this line
                            featureFlagsConfig.Label = settings["AppConfig:Label"];
                        }));
            })
            .UseStartup());

Kod powyżej filtruje feature flags o tych samych etykietach, które są podane w ustawieniach aplikacji w sekcji AppConfig, we właściwości Label.

Możesz przechowywać je u dowolnego dostawcy konfiguracji obsługiwanego przez Twoją aplikację, na przykład w pliku appsettings.json lub zmiennych środowiskowych.

Jeśli ustawisz etykietę na "dev" dla środowiska developerskiego i "prod" dla środowiska produkcyjnego, Twoja aplikacja będzie wybierać tylko odpowiednie feature flags dla odpowiedniego środowiska.

Podsumowanie 

Mam nadzieję, że przedstawiłem wystarczająco dużo dowodów na to, że Azure App Configuration to dobre rozwiązanie do przechowywania feature flags. Może okazać się to bardzo pomocne, gdy będziesz mieć wiele aplikacji (może mikroserwisów), które korzystają z tych samych feature flags.

Ponadto posiada ona wygodny interfejs użytkownika do zarządzania funkcjami, który pomaga w przeglądzie wszystkich przełączników funkcji w Twoim systemie.

I na koniec, łatwo integruje się z popularną biblioteką Microsoft.FeatureManagement.

Jeśli chcesz wdrażać podobne rozwiązania dla naszych klientów, zajrzyj na stronę Join us i zostań Predicanem.

Zdjęcie główne pochodzi z Unsplash.com.

Modern Apps Senior Consultant w Predica

Tworzy i wspiera oprogramowanie od 2017 roku, aktualnie jako Modern Apps Senior Consultant w Predica, a SoftwareOne company. Pracował nad małymi i dużymi projektami, zwykle przy użyciu .NET i uwielbia poznawać nowe technologie i dzielić się nimi ze światem.

Podobne artykuły

[wpdevart_facebook_comment curent_url="https://geek.justjoin.it/jak-zarzadzac-feature-flags-w-aplikacjach-asp-net-core-przy-uzyciu-azure/" order_type="social" width="100%" count_of_comments="8" ]