banqUP tworzy nowoczesną platformę bankową w chmurze Microsoft Azure
Zaprojektowaliśmy i zaimplementowaliśmy platformę, która umożliwia stworzenie cyfrowego banku od podstaw, a także może pomóc istniejącym bankom wprowadzić innowacje z wybranych wertykałach. banqUP jest przykładem stworzenia banku SME, który jest wertykalnie/horyzontalnie-inteligentny. To nasze własny przykład użycia dla platformy.
Kluczowe technologie:
- Visual Studio Team Services - współdzielenie kody, śledzenie pracy oraz wydawanie oprogramowania dla dowolnej platformy - wszystko w jednym pakiecie
- Azure App Service - aplikacje chmurowe dla frontendu, Web Joby jako konektory i zadania rozproszone
- Azure Functions - konektory i webhooki dla łączenia z zewnętrznymi serwisami
- Azure Application Insights - wgląd w wydajność aplikacji, zarzadzanie i natychmiastowa analityka
- Azure Resource Manager Templates (ARM Templates) - zarzadzanie zasobami chmurowymi
- Azure SQL Database - przechowywanie danych relacyjnych
- Azure Notification Hubs - wysyłanie wiadomości SMS, e-mail i notyfikacji push
- Azure Redis Cache - przechowywanie informacji w cache oraz danych nierelacyjnych
- Azure Service Bus - centralny punkt systemu, który komunikuje ze soba wszystkie pozostałe komponenty w zarządzany i bezpieczny sposób poprzez wymianę wiadomości
Zespół projektowy
- Tomasz Wiśniewski - Technical Evangelist, Microsoft
- Dariusz Porowski - Senior Technical Evangelist, Microsoft
- Krzysztof Pulkiewicz - Chief Executive Officer, banqUP
- Anna Ciesielska - Board Member, banqUP
- Łukasz Chmielewski - Chief Technology Officer, banqUP
- Natalia Zienkowicz - Project Manager, banqUP
- Bartłomiej Zalewski - Software Developer, banqUP
Obrazek 1. Członkowie warsztatów
Profil firmy
banqUP jest cyfrowym bankiem fintech nakierowanym na SME. Dostarczamy jedno miejsce dla kombinacji najważniejszych produktów bankowych (konta biznesowe, MasterCard) i zintegrowane usługi fintech. banqUP to międzynarodowy zespół złożony z konsultantów oraz przedsiębiorców z doświadczeniem w cyfrowej bankowości, finctech i architekturze IT. Misją banqUP jest przekształcenie tego jak wygląda bankowość SME i usługi finansowe na terenie Europy. http://banqup.com/ banqUP jest przykładem stworzenia banku SME, który jest wertykalnie/horyzontalnie-inteligentny.
Zarys problemu
banqUP posiadał wiele problematycznych rejonów, które chciał zaadresować za pomoca Azure i innych technologii:
- Usprawnienie procesu developerskiego poprzez automatyzacje kompilacji oraz wdrażania aplikacji z jednego centralnego miejsca a nie z komputerów developerów
- Użycie Azure Web App do hostowania frontendu swojej aplikacji, co daje skalowalność, bezpieczeństwo i możliwość wdrażania do różnych regionów na świecie
- Aplikacja posiada i będzie posiadała konektory do wielu serwisów i dodatkowe funkcjonalności co sprawia iż Azure Functions lub Azure Web Jobs sa idealnym kandydatek dla tego komponentu. W zależności od wymagań konektora jedna badź druga technologia może zostać wybrana.
Rozwiązanie, kroki oraz dostarczenie
Kroki podjęte w celu dostarczenia rozwiązania korespondują bezpośrednio z tym co zostało opisane powyżej i były następujące:
- Architektura
- Value Stream Mapping
- Stworzenie procesu kompilacji i wdrożenia dla Azure Functions
- Wykorzystanie Azure Web Apps dla frontendu
- Monitorowanie aplikacji za pomocą Application Insights
Architektura
Prace rozpoczęliśmy od dyskusji na temat istniejącej architektury. Zespół banqUP opisuje jak działa ich rozwiązanie, jakie komponenty są wykorzystywane w platformie oraz jak wszystko jest ze sobą połączone.
Obrazek 2. Architektura
Ta aktywność była bardzo przydatna dla każdego z obecnych na warsztatach, ponieważ wszyscy wiedzieli dokładnie jak wygląda proces - wlicząjac w to członków banqUP.
Value Stream Mapping
Po przekazaniu wiedzy na temat architektury dokonaliśmy zadania zwanego Value Stream Mapping (VSM) dla obecnego procesu developmentu oraz wdrażania aplikacji.
Obrazek 3. Value Stream Mapping
Proces developerki w banqUP nie był zdefiniowany w żaden konkretny sposób. Dlatego VSM było bardzo trudnym ćwiczeniem do wykonania. W tym ćwiczeniu znaleźliśmy kilka punktów straty i postanowiliśmy skupić się na jednym z najważniejszych problemów dla zespołu banqUP - CI/CD dla Azure Functions. Podsumowując zdecydowaliśmy się zaimplementować kilka praktyk DevOps:
- Infrastructure as Code (IaC) dla zarzadzania infrastruktura w deklaratywny sposób, używajac tego samego systemu wersjonowania, które używa zespół developerski.
- Continous Integration (CI) dla automatyzacji procesu kompilacji i testowania kodu za każdym razem kiedy członek zespołu wgra zmiany do repozytorium.
- Continous Deployment (CD) dla każdej kompilacji konfiguracja i wdrożenie tej kompilacji na różne środowiska.
Proces kompilacji i wdrażania dla Azure Functions
Zespół banqUP tworzył Azure Functions w portalu App Service Editor bezpośrednio przez każdego developera bez przechowywania go w repozytorium kodu. Po stworzeniu jakiejś funkcji w środowisku developerskim, programista kopiował i wklejał nowy kod do drugiego środowiska. Aby uniknać sytuacji ręcznych zadań i niezarządzanego procesu przygotowaliśmy całe rozwiązanie używąjac kilku praktyk DevOps, takich jak Continous Integration, Continous Deployment oraz Infrastructure as Code.
Continuous Integration
Proces kompilacji dla CI nie był zbyt skomplikowany, a poniżej znajduj się kroki oraz szczegóły.
Obrazek 4. VSTS Build - Tasks
- Pobierz źródła z repozytorium Git
Task: Get sources Title: Get sources Repository: banqUP Branch: master
- Skopiuj wszystkie szablony ARM Templates
Task: Copy Files Display name: Prepare ARM Templates Source Folder: AzureFunctions/AzureResourceGroup1/Templates Contents: *.json Target Folder: $(Build.ArtifactStagingDirectory)\Templates
- Skopiuj wszystkie skrypty
Task: Copy Files Display name: Prepare Scripts Source Folder: AzureFunctions/AzureResourceGroup1/Scripts Contents: ** Target Folder: $(Build.ArtifactStagingDirectory)\Scripts
- Skopiuj wszystkie pliki Azure Function wykluczają pliki projektu, takie jak .local.json, appsettings.json i .fanproj
Task: Copy Files Display name: Prepare temporary folder with Azure Functions Source Folder: AzureFunctions/FunctionApp1 Contents: **\!(*.locak.json|appsettings.json|*.funproj) Target Folder: $(System.DefaultWorkingDirectory)\Functions-Temp
- Utwórz archiwum ZIP z aplikacją Azure Functions
Task: Archive Files Display name: Archive Azure Functions from temporary folder Archive Azure Function from temporary folder: $(System.DefaultWorkingDirectory)\Functions-Temp Prefix root folder name to archive paths: false Archive type: zip Archive file to create: $(Build.ArtifactStagingDirectory)\AzureFunctions.zip
- Publikuj artefakty
Task: Publish Build Artifacts Display name: Publish Artifact: drop Publish Build Artifacts: $(Build.ArtifactStagingDirectory) Artifact Name: drop Artifact Type: Server
Repozytorium Git trzyma kod źródłowy nie tylko dla Azure Functions, ale w przypadku procesu kompilacje powinien on być uruchamiany tylko w momencie zmian w którejś z Azure Functions. Aby to osiągnać wykorzystaliśmy filtry dla ścieżek (path filters). Wszystkie Azure Functions są umieszone w folderze AzureFunctions.
Obrazek 5. VSTS Continuous Integration - Path filters
Continuous Deployment
Proces wdrażania jest automatycznie uruchamianiu po udanym procesie kompilacji (Continous Deployment) i jest rozłożony na dwa środowiska. W tym wypadku zespół banqUP chce proces CI/CD tylko dla tych środowisk, ponieważ środowisko produkcyjnie nie zostało jeszcze wydane.
- Dev - dedykowane środowisko dla podstawowej weryfikacji prac zespołu programistów
- QA - dedykowane dla testerów w celu wykonywania planów testowych
Application monitoring
Jednym z najważniejszych aspektów pełnego cyklu DevOps i wdrażania na jakiekolwiek środowisko - w tym także Azure - jest monitorowanie aplikacji na produkcji. banqUP w pierwszej kolejności wykorzystywał rozwiązanie firmy trzeciej do monitorowania Web Apps oraz zintegrowania monitorowania dla Azure Functions. To podejścia posiadało dwie podstawowe wady:
- Potrzeba wykorzystania dwóch narzędzi do monitorowania.
- Zintegrowany monitoring dla Azure Functions nie dostarczał wszystkich wymaganych elementów.
Application Insights umożliwiają monitorowanie zarówno Web Apps jak i Azure Functions i są bardzo łatwe w konfiguracji.
- Aby dodać Application Insights do aplikacji www wystarczy otworzyć solucję w Visual Studio, kliknąć prawym przyciskiem myszy na projekt i wybrać opcję Configure Application Insights… i wykonać kroki w kreatorze.
Obrazek 6. Visual Studio - ConObrazek Application Insights
-
Dodanie Application Insights do Azure Functions jest w chwili pisania tego dokumentu trochę bardziej skomplikowane a samo rozwiązanie nie jest jeszcze w pełni dostępne produkcyjnie, ale posiada tyle zalet, że przewyższają one problemy, które mogą czasami wystąpić. Aby dodać monitorowanie do Azure Functions należy:
- Stworzenie nowej instancji Application Insights
- Pobrać instrumentation key z portalu Azure z sekcji Application Insights
Obrazek 7. Visual Studio - Application Insights instrumentation key
- Dodać nowa zmienna w ustawieniach Azure Functions w formacie
APPINSIGHTS_INSTRUMENTATIONKEY = {Instrumentation Key}
Zmienne
Definicja wdrożenia używa wielu zmiennych zdefiniowanych dla wszystkich środowisk i dla każdego ze środowisk z osobna.
Obrazek 8. VSTS Release Management - Variables for whole definition
Obrazek 9. VSTS Release Management - Variables for Dev environment
Zmienne dla środowiska QA sa praktycznie takie same. Rożnią się tylko wartościami.
Środowiska Dev i QA
Środowiska Dev i QA maja takie same procesy. Poniżej znajdują się kroki dla tych procesów.
Obrazek 10. VSTS Release Management - Definicja dla środowisk Dev i QA
- Utwórz lub zaktualizuj grupę zasobów opartą na szablonach ARM Templates (Infrastructure as Code).
Task: Azure Resource Group Deployemnt Title: Create or Update Azure Resources Action: Create or update resource group Resource group: $(ResourceGroupName) Location: $(ResourceGroupLocation) Template location: Linked artifact Template: $(System.DefaultWorkingDirectory)/CI.AzureFunctions/drop/Templates/banqupAzureFunctions.json Template parameters: $(System.DefaultWorkingDirectory)/CI.AzureFunctions/drop/Templates/banqupAzureFunctions.parameters.json Override template parameters: -functionAppName $(AppServiceName) Deployment mode: Incremental
- Wdróż Azure Functions poprzez Web Deploy.
Task: Azure App Service Deployment Title: Deploy Azure Functions to Azure App Service App Service name: $(AppServiceName) Package or Folder: $(System.DefaultWorkingDirectory)/CI.AzureFunctions/drop/AzureFunctions.zip Publish using Web Deploy: true Remove additional files at destination: true
Infrastructure as Code
W celu uniknięcia ręcznego tworzenia zasobów w Azure dla środowisk napisaliśmy szablony ARM dla Azure Functions w celu utrzymania spójności pomiędzy środowiskami i developerami. Ponieważ Azure Functions oparte sa na Azuer App Swervice szablon ARM jest bardzo podobny do standardowego zasobu Azure Web App. Jest tylko kilka elementów, które musza zostać zmienione jak np. kind parametry to w tym wypadku functionapp oraz sekcja z appsettings.
banqupAzureFunctions.json
{
"$schema":"http://schemas.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion":"1.0.0.0",
"parameters":{
"functionAppName":{
"type":"string",
"minLength":3,
"maxLength":19,
"metadata":{
"description":"The name of the function app that you wish to create."
}
}
},
"variables":{
"functionAppName":"[toLower(parameters('functionAppName'))]",
"hostingPlanName":"[variables('functionAppName')]",
"storageAccountName":"[concat(variables('functionAppName'), 'storage')]",
"storageAccountType":"Standard_LRS"
},
"resources":[
{
"type":"Microsoft.Storage/storageAccounts",
"name":"[variables('storageAccountName')]",
"apiVersion":"2016-12-01",
"sku":{
"name":"[variables('storageAccountType')]"
},
"location":"[resourceGroup().location]",
"kind":"Storage"
},
{
"type":"Microsoft.Web/serverfarms",
"apiVersion":"2016-09-01",
"kind":"functionapp",
"name":"[variables('hostingPlanName')]",
"location":"[resourceGroup().location]",
"sku":{
"name":"Y1",
"tier":"Dynamic",
"size":"Y1",
"family":"Y",
"capacity":0
},
"properties":{
"name":"[variables('hostingPlanName')]",
"numberOfWorkers":0
}
},
{
"apiVersion":"2016-08-01",
"type":"Microsoft.Web/sites",
"name":"[variables('functionAppName')]",
"location":"[resourceGroup().location]",
"kind":"functionapp",
"properties":{
"name":"[variables('functionAppName')]",
"serverFarmId":"[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"clientAffinityEnabled":false
},
"resources":[
{
"apiVersion":"2016-03-01",
"name":"appsettings",
"type":"config",
"dependsOn":[
"[resourceId('Microsoft.Web/sites', variables('functionAppName'))]"
],
"properties":{
"AzureWebJobsStorage":"[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2016-12-01').keys[0].value,';')]",
"AzureWebJobsDashboard":"[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2016-12-01').keys[0].value,';')]",
"FUNCTIONS_EXTENSION_VERSION":"latest",
"WEBSITE_CONTENTAZUREFILECONNECTIONSTRING":"[concat('DefaultEndpointsProtocol=https;AccountName=',variables('storageAccountName'),';AccountKey=',listkeys(resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName')), '2016-12-01').keys[0].value,';')]",
"WEBSITE_CONTENTSHARE":"[concat(variables('functionAppName'), 'share')]"
}
}
],
"dependsOn":[
"[resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName'))]",
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
]
}
],
"outputs":{
"functionAppDefaultHostName":{
"type":"string",
"value":"[reference(resourceId('Microsoft.Web/sites', variables('functionAppName'))).defaultHostName]"
},
"functionAppOutboundIpAddresses":{
"type":"string",
"value":"[reference(resourceId('Microsoft.Web/sites', variables('functionAppName'))).outboundIpAddresses]"
},
"functionApp":{
"type":"object",
"value":"[reference(resourceId('Microsoft.Web/sites', variables('functionAppName')))]"
},
"functionAppHostingPlan":{
"type":"object",
"value":"[reference(resourceId('Microsoft.Web/serverfarms', variables('hostingPlanName')))]"
}
}
}
Pełen szablon ARM można znaleźć w tym repozytorium GitHub: banqupAzureFunctions.json
Podsumowanie i kroki na przyszłość
Obecnie banqUP pracuje nad doprowadzeniem aplikacji do statusu produkcyjnego wraz ze wszystkimi wymaganymi funkcjonalnościami mając na uwadze architekturę, praktyki DevOps i technologie takie jak Azure Functions w centrum. W przyszłości banqUP będzie tworzył aplikacje mobilna, która będzie wykorzystywała Sztuczna Inteligencje w celu dokonywania predykcji na różnych poziomach systemu, conversation as a platform oraz big data.
Fakty i usprawnienia
Kilka interesujących faktów i usprawnień po hackfeście:
- Zaprojektowaliśmy podstawowy proces developerski od podstaw dzięki czemu każdy z członków zespołu wie za co jest odpowiedzialny oraz jak wszystko działa od A do Z. Wyeliminowało to przekazywanie zadań i usprawniło wydajność.
- Usprawniliśmy proces wdrożenia Azure App Service co umożliwiło developerom na wdrażanie i testowanie ich rozwiazań w bardzije zarzadzalny i przewidywalny sposób.
- Zautomatyzowaliśmy proces walidacji nowych pull request co zredukowało ogólny czas (praca ręczna + oczekiwanie) z około 4-8 godzin do 15-30 minut.
- Zoptymalizowaliśmy monitorowanie rozwiązania poprzez migracje z zbudowane monitorowania Azure Functions do Application Insights co daje developerom dużo lepszy wgląd w kondycję ich aplikacji.
banqUP - własnymi słowami
“Zdecydowaliśmy się zbudować nasza platformę w oparciu o chmurę Microsoft Azure, aby wykorzystać bogaty zestaw usług i zapewnić skalowalność i bezpieczeństwo. Dla nas warsztat był idealną możliwością na przegląd architektury, sprawdzeniem czy wykorzystujemy usługi w najbardziej optymalny sposób oraz aby zbudować techniczna roadmape dla dynamicznego wzrostu banqUP.”
Krzysztof Pulkiewicz, CEO firmy banqUP
“Projekt był bardzo przydatnym doświadczeniem. Pozwolił nam nie tylko lepiej poznać Microsoft Azure, ale także usprawnić nasz proces DevOps i wprowadził go na właściwe tory. Praca z inżynierami Microsoft, którzy odpowiadali na pytania zespołu programistów oraz ich bliska współpraca z nami rozwiązała wiele problemów, które napotkaliśmy budując nowoczesna platformę bankowości w chmurze Microsoft Azure.”
Łukasz Chmielewski, CTO firmy banqUP
Dodatkowe zasoby
Więcej informacji na temat DevOps:
- Guide through the theory and implementation of DevOps
- DevOps at Microsoft
- Microsoft - Our DevOps Journey
Punkt startowy na temat technologii wykorzystywanych w projekcie: