Pubblicazione di un’applicazione web su Azure Kubernetes Service

WebApp su AKS

In questa guida verrà mostrata la procedura di pubblicazione di un’applicazione Web su Azure utilizzando il servizio AKS (Azure Kubernetes Service).

Verrà fatta inoltre la distinzione sulla tecnica di pubblicazione nel caso in cui l’applicazione venga sviluppata utilizzando .NET Framework, oppure dotNET Core.

Le applicazioni Web verranno containerizzate utilizzando Docker.

Premessa

A seconda della tecnologia utilizzata per lo sviluppo dell’applicazione Web, .NET Framework o dotNET Core, è necessario scegliere un sistema operativo compatibile da utilizzare all’interno del contenitore Docker: Windows Server Core per applicazioni .NET Framework, oppure Windows Nano Server o Linux per applicazioni dotNET Core.

Di seguito uno schema con le differenze per una scelta adeguata allo scopo.

WebApp su AKS Schema

Caso 1: Applicazione sviluppata in .NET Framework

Come anticipato all’interno della premessa, nel caso in cui vogliamo pubblicare un’applicazione sviluppata utilizzando .NET Framework, è necessario creare un’immagine Docker con sistema operativo Windows Server Core.

Vediamo nello specifico i vari passaggi:

  1. Scaricare ed installare Docker Desktop for Windows sulla macchina locale (link);
  2. Una volta installato, impostare il contenitore sulla piattaforma Windows dall’icona di Docker presente all’interno della barra delle notifiche;

WebApp su AKS Switch Contenitore

  1. Aprire il progetto della WebApp che si intende pubblicare con Visual Studio ed effettuare la compilazione della soluzione;
  2. Aggiungere il supporto per Docker Compose alla WebApp appena compilata: tasto destro del mouse sul progetto della WebApp, Aggiungi, Supporto per l’agente di orchestrazione del container e selezionare Docker Compose;

WebApp su AKS Select Docker Compose

  1. All’interno del Dockerfile modificare la riga:
    FROM mcr.microsoft.com/dotnet/framework/aspnet:4.7.2-windowsservercore-ltsc2019
    

    con la seguente riga:

    FROM microsoft/aspnet:4.7.1-windowsservercore-10.0.14393.1884
    

    Questa operazione è necessaria perché gli ACI (Azure Container Instance) non supportano una versione di Windows superiore alla 10.0.14393 nel caso di applicazione .NET Framework;

  2. Aggiungere quindi un nuovo profilo di pubblicazione: tasto destro del mouse sul progetto della WebApp, Pubblica, selezionare come target Cartella, impostare il percorso di output ed effettuare la pubblicazione della soluzione;
  3. Editare il file docker-compose.yml modificando il valore del campo image con uno a proprio piacimento, per esempio:
    image: webapp452
    

    Il nome scelto verrà salvato all’interno della variabile $DOCKER_IMAGE;

  4. Avviare Windows PowerShell e, una volta posizionati al percorso in cui è contenuto il file docker-compose.yml, lanciare il seguente comando:
    docker-compose build
    
  5. Accedere al Portale Azure ed aggiungere un nuovo gruppo risorse: Resource Groups, Add e successivamente impostare un nome (nel nostro caso “RG_Webapp4.5.2”). Il nome della risorsa verrà salvato nella variabile $RESOURCE_GROUP;
  6. Sempre dal Portale Azure, aggiungere un nuovo contenitore impostando un nome, il gruppo risorse creato in precedenza, ed abilitando l’utente amministratore.Ad esempio: Container registries, Add ed impostare come segue:
    Name:containerwebapp452” ($CONTAINER_NAME)
    Resource Group: $RESOURCE_GROUP
    Admin User: Enable
  7. Restando sul Portale Azure, entrare all’interno del contenitore appena creato ed accedere alla sezione Access keys. Qui prelevare le informazioni dei campi Username e Password;
  8. Tornare alla finestra PowerShell e digitare il comando:
    docker login <$CONTAINER_NAME>.azurecr.io -u <$CONTAINER_USERNAME> -p <$CONTAINER_PASSWORD>
    

    Dove <$CONTAINER_USERNAME> e <$CONTAINER_PASSWORD> sono i campi prelevati dal Portale Azure nel punto precedente;

  9. Lanciare quindi il comando:
    docker tag <$DOCKER_IMAGE> <$CONTAINER_NAME>.azurecr.io/<$DOCKER_IMAGE>
    

    per applicare il TAG all’immagine, e successivamente:

    docker push <$CONTAINER_NAME>.azurecr.io/<$DOCKER_IMAGE>
    

    per effettuare il PUSH dell’immagine su Docker;

  10. Al termine dell’operazione di PUSH, è necessario procedere con la creazione di un utente di servizio che avrà accesso al cluster AKS (Azure Kubernetes Service) che andremo a creare successivamente. Lanciare quindi il comando:
    az ad sp create-for-rbac --skip-assignment
    

    e, dal risultato ottenuto appuntarsi i valori di appId e password;

  11. A questo punto bisogna assegnare il ruolo di Reader all’utente appena creato per permettergli di effettuare l’operazione di PULL, della risorsa oggetto dell’operazione di PUSH precedente. In sequenza ecco i due comandi necessari:
    az acr show --resource-group <$RESOURCE_GROUP> --name <$CONTAINER_NAME> --query "id" --output tsv
    

    Appuntarsi quindi il parametro <$acrId> ed utilizzarlo all’interno del seguente comando:

    az role assignment create --assignee <$appId> --scope <$acrId> --role Reader
    
  12. Ora si può procedere con la creazione del cluster AKS mediante il seguente comando:
    az aks create --resource-group <$RESOURCE_GROUP> --name <$CLUSTER_NAME> --node-count 1 --service-principal <$appId> --client-secret <$password> --generate-ssh-keys --kubernetes-version 1.11.5
    

    In questo caso verrà creato un cluster con singolo nodo. La configurazione rimane comunque editabile anche in un secondo momento e si può inoltre cambiare il numero di nodi iniziali agendo sul valore del parametro “–node-count“.

    N.B. Nel caso venga riscontrato l’errore:

    az aks create: error: Incorrect padding
    

    all’interno della PowerShell, è possibile lanciare il comando di creazione del cluster direttamente dal Portale Azure mediante l’uso della Cloud Shell.

    Se all’interno della Kubernates services del Portale Azure appare il cluster appena creato con lo stato “Succeeded“, l’operazione è terminata con successo ed è possibile continuare con la pubblicazione.

  13. Lanciare il comando:
    az aks install-cli
    

    e successivamente effettuare la connessione al cluster:

    az aks get-credentials --resource-group <$RESOURCE_GROUP> --name <$CLUSTER_NAME>
    

Installazione Virtual Kubelet

AKS (Azure Kubernetes Service) riesce a gestire in modo automatico dei nodi virtuali verso delle ACI (Azure Container Instance) solamente se il contenitore usa un’immagine Linux. Per Windows invece, è necessario l’utilizzo di uno strumento chiamato Virtual Kubelet.

N.B. Per installare Virtual Kubelet bisogna installare anche Helm.

WebApp AKS Schema Nodi

    1. Creare un file di testo vuoto chiamato rbac-virtual-kubelet.yaml e copiarci il seguente testo:
      apiVersion: v1
      kind: ServiceAccount
      metadata:
          name: tiller
          namespace: kube-system
      ---
      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRoleBinding
      metadata:
          name: tiller
      roleRef:
          apiGroup: rbac.authorization.k8s.io
          kind: ClusterRole
          name: cluster-admin
      subjects:
          - kind: ServiceAccount
            name: tiller
            namespace: kube-system
      
    2. Posizionarsi all’interno della cartella nel quale è stato creato il file e lanciare i seguenti comandi:
      kubectl apply -f rbac-virtual-kubelet.yaml
      helm init --service-account tiller
      az aks install-connector --resource-group <$RESOURCE_GROUP> --name <$CLUSTER_NAME> --connector-name virtual-kubelet --os-type Windows
      

      A questo punto, mediante il comando:

      kubectl get nodes
      

      si dovrebbero vedere due nodi: l’agent, creato al momento della creazione del cluster AKS, e il nuovo nodo virtual-kubelet appena creato, da utilizzare come connettore verso i contenitori Windows;

    3. L’utilizzo dei Virtual Kubelet rende necessaria la creazione di una chiave segreta, questo per poter effettuare il PULL dell’immagine. Tramite PowerShell, usare quindi la seguente sequenza di comandi, sostituendo le variabili con i valori assegnati precedentemente:
      $ACR_NAME="<$CONTAINER_NAME>"
      $SERVICE_PRINCIPAL_NAME="<$CONTAINER_USERNAME>"
      $ACR_LOGIN_SERVER=$(az acr show --name $ACR_NAME --query loginServer --output tsv)
      $ACR_REGISTRY_ID=$(az acr show --name $ACR_NAME --query id --output tsv)
      $SP_PASSWD=$(az ad sp create-for-rbac --name $SERVICE_PRINCIPAL_NAME --role acrpull --scopes $ACR_REGISTRY_ID --query password --output tsv)
      $CLIENT_ID=$(az ad sp show --id http://$SERVICE_PRINCIPAL_NAME --query appId --output tsv)
      kubectl create secret docker-registry acr-auth --docker-server $ACR_LOGIN_SERVER --docker-username $SERVICE_PRINCIPAL_NAME --docker-password <$CONTAINER_PASSWORD> --docker-email <$ACCOUNT_EMAIL>
      

Pubblicazione dell’immagine

A questo punto siamo pronti per la pubblicazione, sul cluster, dell’immagine caricata all’interno del contenitore ACI (Azure Container Instance).

  1. Per procedere, va creato un file di testo vuoto chiamato, ad esempio, virtual-kubelet-windows.yaml contenente:
    apiVersion: apps/v1
    kind: Deployment
    metadata:
        name: <$DOCKER_IMAGE>
    spec:
        replicas: <$PODS_NUMBER>
        selector:
            matchLabels:
                app: <$DOCKER_IMAGE>
        template:
            metadata:
                labels:
                    app: <$DOCKER_IMAGE>
            spec:
                containers:
                - name: <$DOCKER_IMAGE>
                  image: <$CONTAINER_NAME>.azurecr.io/<$DOCKER_IMAGE>
                  ports:
                  - containerPort: 80
                  imagePullPolicy: Always
                imagePullSecrets:
                - name: acr-auth
                nodeSelector:
                    beta.kubernetes.io/os: windows
                    kubernetes.io/role: agent
                    type: virtual-kubelet
                tolerations:
                - key: virtual-kubelet.io/provider
                  operator: Equal
                  value: azure
                  effect: NoSchedule
    ---
    apiVersion: v1
    kind: Service
    metadata:
        name: <$DOCKER_IMAGE>
    spec:
        type: LoadBalancer
        ports:
        - port: 80
        selector:
            app: <$DOCKER_IMAGE>
    

    Le variabili: <$DOCKER_IMAGE>, <$PODS_NUMBER> e <$CONTAINER_NAME> vanno sostituite con i parametri di configurazione assegnati precedentemente;

  2. Tramite PowerShell, posizionarsi all’interno del percorso che contiene il file appena creato e lanciare il seguente comando:
    kubectl apply -f virtual-kubelet-windows.yaml
    

    Così facendo, verranno originati diversi POD, ognuno dei quali punterà ad una ACI, e saranno tutti gestiti dal Virtual Kubelet creato in precedenza.

    Il completamento dell’operazione dura in genere alcuni minuti, anche in base al numero di POD che deve generare.

    Per monitorarne lo stato di creazione è possibile accedere alla sezione Container Instances del Portale Azure. Lo stato “Creating” indica che l’operazione è ancora in corso.

Dal Portale Azure è anche possibile conoscere l’IP pubblico con cui accedere al set di POD appena creato. Per farlo:

  1. Cliccare su uno dei POD appena creato;
  2. Tramite il link Resource Group si apriranno gli elementi associati al gruppo di risorse, selezionare quello con il parametro Type assegnato come Load Balancer;
  3. Tra le molteplici informazioni mostrate, vi è anche Public IP address, l’indirizzo pubblico con cui accedere al cluster creato.

Caso 2: Applicazione sviluppata in .NET Core

Nel caso avessimo a che fare con un applicazione sviluppata con tecnologia .NET Core, all’interno del contenitore Docker è possibile utilizzare sia il sistema operativo Windows Nano Server, oppure Linux.

Vediamo anche per questo caso i vari passaggi:

  1.  Seguire i passaggi 1 e 2 descritti nel Caso 1, per scaricare ed installare Docker Desktop for Windows;
  2. Aprire il progetto WebApp su Visual Studio ed aggiungere un file di nome Dockerfile all’interno della root;
  3. All’interno del Dockerfile aggiungere il seguente testo:
    FROM microsoft/dotnet:2.2-aspnetcore-runtime
    ARG source=.
    WORKDIR /app
    EXPOSE 80
    COPY $source .
    ENTRYPOINT ["dotnet", "<$DLL_STARTUP_PROJECT>"]
    

    Dove il parametro <$DLL_STARTUP_PROJECT> dovrà essere sostituito con il nome della dll del progetto di partenza.

    Inoltre il Dockerfile deve sempre essere copiato all’interno della directory di output (Copy Always” nelle proprietà del file);

  4. Creare un profilo di pubblicazione della WebApp, impostare l’output su FileSystem e chiamarlo DockerProfile.
    Come impostazioni di pubblicazione usare le seguenti:
    Configurazione: Release
    Modalità destinazione: Dipendente del framework
    Runtime: Linux-64
    Opzioni pubblicazione: Elimina tutti i file esistenti
  5. Avviare quindi la pubblicazione ed attendere l’esito;
  6. Aprire PowerShell e creare l’immagine Docker tramite il seguente comando:
    docker build <$PUBLISH_FOLDER> -t <$CONTAINER_NAME>.azurecr.io/<$DOCKER_IMAGE>:0
    
  7. Al termine della creazione dell’immagine, effettuarne il PUSH verso ACI (Azure Container Instance) con il comando:
    docker push <$CONTAINER_NAME>.azurecr.io/<$DOCKER_IMAGE>:0
    
  8. Seguire dal punto 14 al 17 mostrati all’interno del Caso 1;
  9. A questo punto l’immagine caricata sul contenitore ACI è pronta per la pubblicazione.Creare quindi un nuovo file chiamato webapp.yaml e copiarci al suo interno il seguente testo:
    apiVersion: apps/v1
    kind: Deployment
    metadata:
        name: <$DOCKER_IMAGE>
    spec:
        replicas: <$PODS_NUMBER>
        selector:
            matchLabels:
                app: <$DOCKER_IMAGE>
        template:
            metadata:
                labels:
                    app: <$DOCKER_IMAGE>
            spec:
                containers:
                - name: <$DOCKER_IMAGE>
                  image: <$CONTAINER_NAME>.azurecr.io/<$DOCKER_IMAGE>
                  ports:
                  - containerPort: 80
                  imagePullPolicy: Always
                imagePullSecrets:
                - name: acr-auth
    ---
    apiVersion: v1
    kind: Service
    metadata:
        name: <$DOCKER_IMAGE>
    spec:
        type: LoadBalancer
        ports:
        - port: 80
        selector:
            app: <$DOCKER_IMAGE>
    

    Sostituire le variabili: <$DOCKER_IMAGE>, <$PODS_NUMBER> e <$CONTAINER_NAME> con i parametri opportuni di configurazione;

  10. Tramite PowerShell posizionarsi al percorso nel quale è stato creato il file webapp.yaml e lanciare il seguente comando per procedere con la pubblicazione finale:
    kubectl apply -f webapp.yaml
    

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *