8. Sviluppo ed esecuzione in container

Ci sono molti modi per utilizzare applicazioni containerizzate, dai più semplici (semplici immagini Docker) ai più sofisticati (Kubernetes e così via).

Nota

Questo tipo di sviluppo ha bisogno che l’applicazione docker sia installata e funzionante. Guarda questo tutorial.

Suggerimento

Docker esegue applicazioni preconfezionate (alias immagini) che possono essere recuperate come sorgenti (Dockerfile e risorse) da costruire o già costruite da registri (privati o pubblici).

Nota

I download dei package QGIS Debian-Ubuntu necessitano di una chiave di autenticazione gpg valida. Fare riferimento a installation pages per aggiornare il seguente file Docker.

8.1. Semplici immagini docker

Poiché l’immagine docker non esiste in un registro pubblico, dovrai crearla. Per farlo, crea una cartella qgis-server e all’interno di essa:

  • crea un file Dockerfile con questo contenuto:

FROM debian:bullseye-slim

ENV LANG=en_EN.UTF-8


RUN apt-get update \
    && apt-get install --no-install-recommends --no-install-suggests --allow-unauthenticated -y \
        gnupg \
        ca-certificates \
        wget \
        locales \
    && localedef -i en_US -f UTF-8 en_US.UTF-8 \
    # Add the current key for package downloading
    # Please refer to QGIS install documentation (https://www.qgis.org/fr/site/forusers/alldownloads.html#debian-ubuntu)
    && mkdir -m755 -p /etc/apt/keyrings \
    && wget -O /etc/apt/keyrings/qgis-archive-keyring.gpg https://download.qgis.org/downloads/qgis-archive-keyring.gpg \
    # Add repository for latest version of qgis-server
    # Please refer to QGIS repositories documentation if you want other version (https://qgis.org/en/site/forusers/alldownloads.html#repositories)
    && echo "deb [signed-by=/etc/apt/keyrings/qgis-archive-keyring.gpg] https://qgis.org/debian bullseye main" | tee /etc/apt/sources.list.d/qgis.list \
    && apt-get update \
    && apt-get install --no-install-recommends --no-install-suggests --allow-unauthenticated -y \
        qgis-server \
        spawn-fcgi \
        xauth \
        xvfb \
    && apt-get remove --purge -y \
        gnupg \
        wget \
    && rm -rf /var/lib/apt/lists/*

RUN useradd -m qgis

ENV TINI_VERSION v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini

ENV QGIS_PREFIX_PATH /usr
ENV QGIS_SERVER_LOG_STDERR 1
ENV QGIS_SERVER_LOG_LEVEL 2

COPY cmd.sh /home/qgis/cmd.sh
RUN chmod -R 777 /home/qgis/cmd.sh
RUN chown qgis:qgis /home/qgis/cmd.sh

USER qgis
WORKDIR /home/qgis

ENTRYPOINT ["/tini", "--"]

CMD ["/home/qgis/cmd.sh"]
  • crea un file cmd.sh con questo contenuto:

#!/bin/bash

[[ $DEBUG == "1" ]] && env

exec /usr/bin/xvfb-run --auto-servernum --server-num=1 /usr/bin/spawn-fcgi -p 5555 -n -d /home/qgis -- /usr/lib/cgi-bin/qgis_mapserv.fcgi
  • costruisci l’immagine con:

docker build -f Dockerfile -t qgis-server ./

8.1.1. Prima esecuzione

Per eseguire il server è necessario un file di progetto QGIS. Puoi utilizzare uno tuo o scegliere questo esempio <https://gitlab.com/Oslandia/qgis/docker-qgis/-/blob/cc1798074d4a66a472721352f3984bb318777a5a/qgis-exec/data/osm.qgs>`_.

Per farlo, crea una cartella data all’interno della cartella qgis-server e copia il tuo file al suo interno. Per rispettare le istruzioni seguenti, rinominalo in osm.qgs.

Nota

Potresti dover aggiungere gli URL consigliati nella scheda QGIS Server della :menuselection: Progetto –> Proprietà se le GetCapabilites sono interrotte. Ad esempio, se il server è esposto sulla porta 8080, si inserirà l’URL pubblicizzato http://localhost:8080/qgis-server/. Ulteriori informazioni sono disponibili nella sezione Configura il tuo progetto e successive.

Ora, puoi avviare il server con:

docker network create qgis
docker run -d --rm --name qgis-server --net=qgis --hostname=qgis-server \
              -v $(pwd)/data:/data:ro -p 5555:5555 \
              -e "QGIS_PROJECT_FILE=/data/osm.qgs" \
              qgis-server

Opzioni utilizzate:

  • -d: esecuzione in background

  • –rm: rimuovere il contenitore quando viene arrestato

  • –nome: nome del contenitore da creare

  • –net: (precedentemente creata) sottorete

  • –hostname: nome host del contenitore, per riferimenti successivi

  • -v: cartella dati locale da installare nel contenitore

  • -p: mappatura porte host/contenitore

  • -e: variabile d’ambiente da utilizzare nel contenitore

Per verificare, digita docker ps | grep qgis-server e si dovresti vedere una linea con qgis-server:

CONTAINER ID   IMAGE         COMMAND                  CREATED         STATUS         PORTS                    NAMES
4de8192da76e   qgis-server   "/tini -- /home/qgis…"   3 seconds ago   Up 2 seconds   0.0.0.0:5555->5555/tcp   qgis-server

8.1.2. Esempio utilizzabile

Poiché il server accetta solo connessioni fastcgi, hai bisogno di un server HTTP che gestisca questo protocollo. Per farlo, dobbiamo creare un semplice file di configurazione di Nginx e avviare un’immagine di Nginx.

Crea un file nginx.conf nella cartella corrente con questo contenuto:

server {
  listen 80;
  server_name _;
  location / {
    root  /usr/share/nginx/html;
    index index.html index.htm;
  }
  location /qgis-server {
    proxy_buffers 16 16k;
    proxy_buffer_size 16k;
    gzip off;
    include fastcgi_params;
    fastcgi_pass qgis-server:5555;
  }
}

E digita questo comando:

docker run -d --rm --name nginx --net=qgis --hostname=nginx \
              -v $(pwd)/nginx.conf:/etc/nginx/conf.d/default.conf:ro -p 8080:80 \
              nginx:1.13

Per verificare le capabilities disponibili, digita nel browser http://localhost:8080/qgis-server/?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities.

8.1.3. Pulizia

Per rimuovere le immagini in esecuzione, digita:

docker stop qgis-server nginx

8.2. Stack Docker

Il metodo precedente è eseguibile tramite script, ma non è facilmente confezionabile, né standardizzabile o facilmente gestibile.

Per lavorare con un insieme di immagini docker si può usare uno stack docker gestito da un orchestratore. In uno stack, le immagini lavorano nella stessa rete privata ed è possibile avviare/arrestare l’intero stack o distribuirlo ad altri worker. Esistono molti orchestratori, ad esempio Swarm, Kubernetes e Mesos.

Di seguito presenteremo semplici configurazioni a scopo di test. Non sono adatte alla produzione.

8.2.1. Swarm/docker-compose

Docker ha ora un proprio orchestratore: Swarm (compatibile con i file docker-compose). Devi enable it (la versione per Mac funziona anche con Linux).

Descrizione stack

Ora che Swarm funziona, crea il file di servizio (vedi Deploy to Swarm) qgis-stack.yaml:

version: '3.7'

services:
  qgis-server:
    # Should use version with utf-8 locale support:
    image: qgis-server:latest
    volumes:
    - REPLACE_WITH_FULL_PATH/data:/data:ro
    environment:
    - LANG=en_EN.UTF-8
    - QGIS_PROJECT_FILE=/data/osm.qgs
    - QGIS_SERVER_LOG_LEVEL=0  # INFO (log all requests)
    - DEBUG=1                  # display env before spawning QGIS Server

  nginx:
    image: nginx:1.13
    ports:
    - 8080:80
    volumes:
    - REPLACE_WITH_FULL_PATH/nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
    - qgis-server

Per distribuire (o aggiornare) lo stack, digita:

docker stack deploy -c qgis-stack.yaml qgis-stack

Controlla lo stato di distribuzione dello stack fino a ottenere 1/1 nella colonna replicas:

docker stack services qgis-stack

Qualcosa come:

ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
gmx7ewlvwsqt        qgis_nginx          replicated          1/1                 nginx:1.13          *:8080->80/tcp
l0v2e7cl43u3        qgis_qgis-server    replicated          1/1                 qgis-server:latest

Per verificare le capabilities del WMS, digita in un browser web http://localhost:8080/qgis-server/?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities.

Pulizia

Per pulire, digita:

docker stack rm qgis-stack

8.2.2. Kubernetes

Installazione

Se hai un’installazione di Docker Desktop, l’uso di Kubernetes (alias k8s) è piuttosto semplice: enable k8s.

In caso contrario, segui minikube tutorial o microk8s for Ubuntu.

Poiché l’installazione di Kubernetes può essere molto complessa, ci concentreremo solo sugli aspetti utilizzati in questa demo. Per ulteriori informazioni, consulta official documentation.

microk8s

microk8s necessita di ulteriori passaggi: devi abilitare il registro e etichettare l’immagine qgis-server per far sì che Kubernetes trovi le immagini create.

Per prima cosa, abilita il registro:

microk8s enable dashboard dns registry

Quindi, etichetta e inoltra l’immagine al registro appena creato:

docker tag qgis-server 127.0.0.1:32000/qgis-server && docker push 127.0.0.1:32000/qgis-server

Infine, aggiungi o completa il /etc/docker/daemon.json per avere il registro 127.0.0.1:32000 elencato nel campo insecure-registries:

{
  "insecure-registries": ["127.0.0.1:32000"]
}

Creare manifesti

Kubernetes descrive gli oggetti da distribuire in manifesti yaml. Ne esistono di diversi tipi, ma noi useremo solo i deploy (gestire i pod, cioè le immagini docker) e i servizi per esporre i deploy a scopi interni o esterni.

Manifesti di distribuzione

Crea un file deployments.yaml con questo contenuto:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: qgis-server
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      myLabel: qgis-server
  template:
    metadata:
      labels:
        myLabel: qgis-server
    spec:
      containers:
        - name: qgis-server
          image: localhost:32000/qgis-server:latest
          imagePullPolicy: IfNotPresent
          env:
            - name: LANG
              value: en_EN.UTF-8
            - name: QGIS_PROJECT_FILE
              value: /data/osm.qgs
            - name: QGIS_SERVER_LOG_LEVEL
              value: "0"
            - name: DEBUG
              value: "1"
          ports:
            - containerPort: 5555
          volumeMounts:
            - name: qgis-data
              mountPath: /data/
      volumes:
        - name: qgis-data
          hostPath:
            path: REPLACE_WITH_FULL_PATH/data

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: qgis-nginx
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      myLabel: qgis-nginx
  template:
    metadata:
      labels:
        myLabel: qgis-nginx
    spec:
      containers:
        - name: qgis-nginx
          image: nginx:1.13
          ports:
            - containerPort: 80
          volumeMounts:
            - name: nginx-conf
              mountPath: /etc/nginx/conf.d/default.conf
      volumes:
        - name: nginx-conf
          hostPath:
            path: REPLACE_WITH_FULL_PATH/nginx.conf
Manifesti di servizio

Crea un file services.yaml con questo contenuto:

apiVersion: v1
kind: Service
metadata:
  name: qgis-server
  namespace: default
spec:
  type: ClusterIP
  selector:
    myLabel: qgis-server
  ports:
    - port: 5555
      targetPort: 5555
---
apiVersion: v1
kind: Service
metadata:
  name: qgis-nginx
  namespace: default
spec:
  type: NodePort
  selector:
    myLabel: qgis-nginx
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30080

Distribuzione manifesti

Per distribuire le immagini e i servizi in Kubernetes, si può usare la dashboard (fai clic su + in alto a destra) o la linea di comando.

Nota

Quando utilizzi la linea di comando con microk8s dovrai anteporre a ogni comando il prefisso microk8s.

Per distribuire o aggiornare i manifesti:

kubectl apply -k ./

Per verificare cosa è attualmente distribuito:

kubectl get pods,services,deployment

Dovresti ottenere qualcosa di simile a:

NAME                               READY   STATUS    RESTARTS   AGE
pod/qgis-nginx-54845ff6f6-8skp9    1/1     Running   0          27m
pod/qgis-server-75df8ddd89-c7t7s   1/1     Running   0          27m

NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/Kubernetes         ClusterIP   10.152.183.1     <none>        443/TCP        5h51m
service/qgis-exec-server   ClusterIP   10.152.183.218   <none>        5555/TCP       35m
service/qgis-nginx         NodePort    10.152.183.234   <none>        80:30080/TCP   27m
service/qgis-server        ClusterIP   10.152.183.132   <none>        5555/TCP       27m

NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/qgis-nginx    1/1     1            1           27m
deployment.apps/qgis-server   1/1     1            1           27m

Per leggere i log di nginx/qgis, digita:

kubectl logs -f POD_NAME

Per verificare le capabilities del WMS, digita in un browser web http://localhost:30080/qgis-server/?SERVICE=WMS&VERSION=1.3.0&REQUEST=GetCapabilities.

Pulizia

Per ripulire, digita:

kubectl delete -n default service/qgis-server service/qgis-nginx deployment/qgis-nginx deployment/qgis-server

8.3. Distribuzione in cloud

Gestire il tuo cluster di server per gestire la distribuzione di applicazioni containerizzate è un lavoro complesso. Devi gestire diversi problemi, come l’hardware, la larghezza di banda e la sicurezza a diversi livelli.

Le soluzioni di distribuzione in cloud possono essere una buona alternativa quando non ci si vuole concentrare sulla gestione dell’infrastruttura.

Una distribuzione nel cloud può utilizzare meccanismi proprietari, ma anche compatibili con le fasi spiegate in precedenza (docker images e stack management).

8.3.1. Caso d’uso AWS

Con Amazon AWS, grazie alle funzionalità di ECS (Elastic Container Service), puoi utilizzare docker-compose o wrapper compatibili con Kubernetes per gestire il tuo stack. Dovrai creare un image registry per rendere accessibili le tue immagini personalizzate.

Per utilizzare funzionalità simili a quelle di docker-compose, devi installare il client ecs-cli e disporre di proper permissions / roles. Poi, con l’aiuto dei comandi ecs-cli compose (vedi il manuale ecs-cli compose e il tutorial ecs-cli), puoi riutilizzare la stack description.

Per utilizzare Kubernetes, puoi utilizzare la console web di AWS o lo strumento a linea di comando eksctl e disporre dei permessi/ruoli appropriati. Quindi, con un ambiente kubectl ben configurato, puoi riutilizzare il Kubernetes manifests.