TSM - Asp.NetCore App - de la Docker la Azure

Gabriel Pop - .NET developer @ Siemens

Avantajele de a rula aplicațiile web izolate în "containere" și publicate pe urmă în cloud sunt multe. Voi aminti câteva dintre ele, deși internetul abundă azi de informații despre avantajele și dezavantajele rulării aplicațiilor în cloud. Dar în acest articol doresc să prezint un tutorial scurt, cât mai simplificat, cu pașii minimi pentru ca o aplicație creată cu ajutorul ASP.Net Core să fie transformată într-un container Docker în cloud. Apoi acest container este publicat și rulat pe platforma Azure.

Când vorbim despre aplicații ce rulează în cloud, vorbim, de fapt, despre cloud-computing și implicit Docker. Acesta, din urmă, este un produs software PaaS (Platform as a Service) inițiat în 2010 ce poate rula așa numitele software-containers. A început ca un proiect proprietar, apoi a trecut în lumea open-source în prima parte a anului 2013, crescând în popularitate în anii ce au urmat. Docker a devenit popular pentru că a făcut ca funcționalitatea containerelor să fie ușor de utilizat, furnizând tooluri pentru a crea și administra imagini din care sunt formate containere care pot fi astfel clusterizate împreună (swarm). În acest fel se pot scala aplicațiile care se folosesc de această tehnologie, acesta fiind unul dintre marile avantaje. Un alt mare avantaj oferit de containerizarea aplicațiilor este portabilitatea. De exemplu, o aplicație poate fi containerizată și rulată în izolare cu tot ce are ea nevoie să ruleze. Astfel, aplicația poate rula pe orice sistem de operare unde rulează și Docker, fără a fi necesar să se mai instaleze alte librării sau alte aplicații adiționale.

De ce este nevoie pentru a urma pașii din articol

Trebuie să aveți instalat .Net core SDK, Docker CE și Visual Studio 2019 Community Edition și, de asemenea, aveți nevoie de cont în DockerHub și Azure. Pentru început vom crea o aplicație Asp.Net core MVC. Pentru aceasta, am creat un folder cu numele ExampleApp, apoi din linia de comandă din consola PowerShell scriem:

dotnet new mvc 
  --language C# 
  --auth None 
  --framework netcoreapp3.1

Navigați în folderul ExampleApp și apelând la ExampleApp.csproj puteți deschide aplicația MVC în Visual Studio, pe care, dacă o executați (meniul Debug-Run), ar trebui să obțineți ceva asemănător cu imaginea de mai jos, ceea ce înseamnă că aplicația s-a creat și rulează cu succes:

După ce ați instalat Docker CE pentru Windows, el putându-se instala gratuit de la linkul de mai jos, aplicația pornind imediat după instalare. Pentru a rula Docker este necesar ca Hyper-V să fie activat, lucru care se poate face din Windows Features.

Pentru a evalua dacă Docker funcționează corect, rulăm următoarea comandă în consolă:

docker run --rm hello-world

După rularea comenzii, putem să listăm imaginile existente cu ajutorul comenzii:

docker images

Ca răspuns, vom primi o listă cu imaginile disponibile local:

REPOSITORY TAG IMAGE ID CREATED SIZE

hello-world latest bf756fb1ae65 moments ago 1.848 kB

Acum că am verificat dacă aplicația Asp.net core MVC rulează și că totul este în regulă cu Docker, putem să creăm o imagine adăugând un Dockerfile din Solution Explorer. Această imagine va conține aplicația și pe baza ei se va instanția un container doar prin simplul fapt că rulăm aplicația din Visual Studio și că am ales Docker din drop-down-ul de start, Docker construind imaginea pe baza Dockerfile-ului adăugat din Solution Explorer:

Vom șterge, însă, acum din Docker imaginea și containerul create automat atunci când am rulat aplicația, apoi, le vom recrea din linia de comandă. Pentru a înțelege cum se creează imaginile și containerele folosind linia de comandă din folderul ExampleApp, rulați următoarele comenzi în consolă, în urma cărora se vor crea imaginea cu aplicația și două containere pe baza ei, -p fiind o mapare a portului 80 din containere la portul 3000 respectiv, 4000 din sistemul host, iar -t este tagul asociat cu imaginea, o convenție fiind ca eticheta să fie de forma CompanyName/AppName:

docker build . -t g4hsds/exampleapp -f Dockerfile
docker create -p 3000:80 --name exampleApp3000 g4hsds/exampleapp
docker create -p 4000:80 --name exampleApp4000 g4hsds/exampleapp

Am recreat imaginea, iar pe baza imaginii am reușit să creăm două containere pe care le putem porni acum din Docker și putem să le vedem și din consolă:

PS C:DEVDockerExampleApp> docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
013c44229ba9 g4hsds/exampleapp "dotnet ExampleApp.d…" 6 minutes ago Up 3 minutes 443/tcp, 0.0.0.0:4000->80/tcp exampleApp4000
c36d33e52b9e g4hsds/exampleapp "dotnet ExampleApp.d…" 8 minutes ago Up 3 minutes 443/tcp, 0.0.0.0:3000->80/tcp exampleApp3000

Aplicația creată la început, rulează acum în cele două containere nou create și aveam acces la cele două instanțe ale aplicației din browser, navigând la http://localhost:3000/ și http://localhost:4000/

Acum avem o imagine cu aplicația, o putem publica în Docker Hub. Pentru aceasta este nevoie să aveți un cont in https://hub.docker.com/ și să creați un repository, unde să putem să publica imaginea. Creăm o etichetă cu numele repository-ului din hub și o aplicăm imaginii cu ajutorul comenzii de mai jos, unde în "d21" reprezintă primele 3 cifre ale id-ul imaginii, Docker știind în acest fel la ce imagine ne referim și unde anume trebuie să aplice eticheta cu același nume ca în repository:

docker tag d21 g4hsds/g4freerepository
PS C:Usersgabri> docker images
REPOSITORY TAG IMAGE ID
g4hsds/exampleapp latest d213efcf0a41
g4hsds/g4freerepository latest d213efcf0a41

Observați că eticheta are același id ca și imaginea, practic ea referențiază același lucru. Putem publica imaginea acum în Docker hub cu ajutorul comenzii:

docker push g4hsds/g4freerepository:latest

Am obținut imaginea în Docker hub, o putem publica și rula în Azure, conectându-ne în Azure, unde putem crea o nouă resursă de tipul Web App for Containers și configura Single container și completa Docker tag name cu numele din repository-ul din Docker hub:

Putem configura acum și continuous deployment. Această operație ne ajută atunci când vom publica o nouă imagine în Docker Hub. Azure va fi notificat și își va lua imaginea automat din Docker hub, nemaifiind necesară o altă intervenție în Azure la fiecare modificare/republicare a imaginii, va fi destul doar să o republicăm în Docker hub. Pentru aceasta, copiem Webhooks URL din Docker hub în Container settings din Azure:

Docker hub va apela acest hook de fiecare dată când vom face push la o nouă imagine, având astfel configurat un pipeline de continuous integration.

Putem acum să vedem rezultatul final și anume o aplicație Asp.Net Core care rulează acum în Azure, într-un container Linux creat cu Docker și având configurat un pipeline de continuous integration:

Concluzie

Imaginile reprezintă baza din care se creează containerele. Dintr-o singură imagine se pot forma mai multe containere care execută multiple instanțe ale aplicației conținute, în izolare. Imaginea reprezintă punctul de start al aplicației pe care îl furnizăm unui repository așa cum este cel din Docker hub , iar, de acolo, dacă definim un webhook, va fi preluată și rulată automat în Azure.

Evident, cu Docker și Azure putem face mult mai multe decât cele expuse în aceste rânduri. De exemplu, o aplicație care salvează date într-o bază de date se poate conecta la un alt container în care rulează un server de date, una dintre convenții fiind ca fiecare componentă a aplicației să fie într-un container separat și izolat. Aceasta face să fie ușor de înlocuit sau adăugat părți componente ale aplicației într-un mod flexibil, astfel încât aplicațiile se pot scala în funcție de nevoi.

Bibliografie

  1. https://app.pluralsight.com/library/courses/microsoft-azure-dotnet-secure-services-applications-update
  2. https://docs.microsoft.com/en-us/windows-server/virtualization/virtualization
  3. https://www.docker.com/blog/running-a-container-in-aci-with-docker-desktop-edge/