Container sicuri e leggeri con RedHat
Perché
Il rilascio di applicazioni tramite container leggeri presenta dei vantaggi pratici, dal momento che le immagini contengono tutte le dipendenze necessarie per il corretto funzionamento dell’applicazione. Tuttavia, si possono perdere i vantaggi della containerizzazione se queste immagini sono troppo grandi e quindi richiedono diversi minuti per l’avvio dell’applicazione.
In questo post vediamo come utilizzare le Universal Base Images (aka UBI) di Red Hat come base per costruire delle immagini per i vostri container che siano leggere e sicure per le vostre applicazioni.
Creare applicazioni
Red Hat fornisce delle immagini di base per la creazione di applicazioni cloud-based e applicazioni web in container. Con queste immagini, l’affidabilità, la sicurezza, le prestazioni e le caratteristiche del ciclo di vita delle immagini sono caratteristiche già integrate e verificate dalle persone che lavorano in quest’azienda, per cui è possibile creare un’applicazione containerizzata tramite un’immagine UBI, pusharla sul proprio registry preferito, condividerla facilmente e distribuirla anche su piattaforme che non siano Red Hat.
Cosa sono
Ogni immagine UBI è basata su Red Hat Enterprise Linux (alias RHEL), la distribuzione Linux di livello enterprise più diffusa degli ultimi due decenni. Costruire l’immagine del container su una base di software RHEL garantisce che l’immagine sia affidabile, sicura e liberamente distribuibile. Non è necessario essere clienti Red Hat per utilizzare o ridistribuire le immagini UBI: basta usarle e lasciare che Red Hat gestisca le immagini di base per voi senza alcun costo.
Dove trovarle
Sono facilmente disponibili sia sul Red Hat Container Catalog che sul repository ufficiale di Red Hat di Docker Hub.
Se dovessimo scegliere tra le due opzioni, si dovrebbe preferire l’utilizzo della console del catalogo Red Hat, perché mostra diverse informazioni come la dimensione dell’immagine, la versione, i controlli sulla sicurezza, l’elenco dei pacchetti presenti, il Dockerfile e le diverse opzioni disponibili per il pull dell’immagine.
Quale immagine utilizzare
Le Universal Base Images di Red Hat sono offerte in diversi formati:
- Micro: si tratta di un’immagine ridotta che utilizza il gestore di pacchetti dell’host sottostante per installare i pacchetti, tipicamente utilizzando Buildah o una build multi-stage con Podman.
- Minimal: definisce un’immagine ridotta che utilizza microdnf come gestore di pacchetti.
- Standard: immagine pensata e progettata per essere il livello di base per tutte le applicazioni, il middleware e le utility containerizzate.
- Init: progettata per eseguire un sistema con ID processo pari a 1 (che corrisponde al processo di init di Linux) per l’esecuzione di più servizi all’interno di un container.
Esempio
Vediamo un piccolo use case per Python: utilizzeremo un’applicazione di esempio che andremo a impacchettare in un’immagine UBI.
Il codice delle applicazioni di esempio, compreso il Dockerfile, è disponibile su questo repository GitHub.
Di seguito il Dockerfile:
FROM registry.access.redhat.com/ubi8/ubi
RUN yum install -y python3.11-pip-wheel python3.11-wheel python3.11-pip;
WORKDIR /app
COPY ./requirements.txt ./app ./
RUN mkdir -p /.local; \
chown -R 1001:0 /.local; \
chmod -R ug+rwX /.local; \
pip3 install -r requirements.txt;
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Per l’esempio di Python abbiamo come immagine di base utilizzata quella standard ufficiale di Red Hat UBI, nella versione 8.
Il comando yum installa l’eseguibile di Python, mentre il comando WORKDIR specifica la directory in cui si trova l’applicazione all’interno dell’immagine del container e il comando RUN esegue l’installazione delle dipendenze.
Il comando COPY copia il file dei requisiti di Python nell’immagine UBI, che sarà poi utilizzato dal comando RUN per installare le dipendenze.
Il comando EXPOSE specifica la porta su cui l’applicazione si metterà in ascolto, che solitamente è la 8000 per FastAPI.
Infine, il comando CMD specifica il comando che verrà eseguito quando il container verrà eseguito.
Di seguito, riportiamo i comandi per eseguire la build e il run dell’immagine:
docker build -t python-ubi8 .
docker images | grep -i python-ubi8
docker run -it -p 8000:8000 -d python-ubi8
Il comando cURL dovrebbe restituire la seguente risposta:
curl -vk http://localhost:8000
>>>
* Trying ::1:8000...
* TCP_NODELAY set
* Connected to localhost (::1) port 8000 (#0)
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< date: Mon, 19 Jun 2023 09:22:48 GMT
< server: uvicorn
< content-length: 18
< content-type: application/json
<
* Connection #0 to host localhost left intact
{"Hello":"World!"}
La dimensione finale dell’immagine è di soli 320 MB:
$ docker images
>>>
REPOSITORY TAG IMAGE ID CREATED SIZE
python-ubi8 latest 50c12e1ca549 55 minutes ago 320MB
Chiaramente, queste dimensioni potrebbero essere ridotte ulteriormente, utilizzando un’immagine UBI in versione minimal, magari con Python pre-installato, come nell’esempio seguente:
FROM registry.access.redhat.com/ubi8/ubi-minimal
RUN microdnf install -y python3
WORKDIR /app
COPY ./requirements.txt ./app ./
RUN python3 -m pip install -r /app/requirements.txt
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
In questo caso, le dimensioni vengono dimezzate, dal momento che i pacchetti non necessari sono già stati rimossi:
$ docker images
>>>
REPOSITORY TAG IMAGE ID CREATED SIZE
python-ubi8 latest c4f0d7e3049c 8 minutes ago 161MB
Conclusioni
L’utilizzo delle UBI offre maggiore affidabilità, sicurezza e tranquillità per le vostre applicazioni containerizzate.
Inoltre, è possibile distribuire liberamente le applicazioni containerizzate basate su UBI ai vostri amici (e nemici) sia su piattaforme Red Hat che non Red Hat, avvalendosi dei controlli di sicurezza che vengono effettuati periodicamente.
Nell’esempio visto in precedenza abbiamo usato una semplice UBI8, ma in realtà ne esistono di già pronte con Python e altri linguaggi già installati e configurati di default: perché non provare?
Risorse utili
- Repository GitHub
- UBI: documentazione ufficiale
- RHEL: cos’è
- Docker - per cominciare bene con Docker e Kubernetes
- Kubernetes - Guida per gestire e orchestrare i container