Jusqu’à récemment, je pensais que servir des sites Web statiques à partir de Docker était un gaspillage de bande passante et de stockage. L’intégration de nginx
ou de divers autres moteurs d’exécution lourds dans une image Docker dans le seul but de servir des fichiers statiques ne semblait pas être la meilleure idée – Netlify ou les pages Github peuvent gérer cela bien mieux. Mais mon serveur amateur était triste et pleurait des larmes numériques.
J’ai lu récemment un article de HackerNews sur redbean, un serveur de fichiers statiques à single-binary
et super minuscule, m’a fait réfléchir. C’est ainsi que commence mon voyage pour trouver l’image Docker la plus efficace en termes de temps et de stockage pour servir un site Web statique.
Après avoir évalué quelques serveurs de fichiers statiques aux caractéristiques similaires, j’ai opté pour thttpd, qui présente une empreinte similaire, mais qui semble un peu plus éprouvé.
L’exécution de thttpd
se déroule comme suit :
thttpd -D -h 0.0.0.0 -p 3000 -d /static-website -u static-user -l - -M 60
- Lancera le serveur en avant-plan (-D),
- en écoutant sur l’hôte 0.0.0.0 (-h),
- le port 3000 (-p),
- en servant tous les fichiers dans /static-website (-d)
- qui sont accessibles à static-user (-u).
- Il imprimera les journaux d’accès sur STDOUT (-l -)
- et fixera l’en-tête Cache-Control à 60 secondes (-M).
Il y a quelques autres fonctionnalités intéressantes, comme l’authentification de base, le throttling et les hôtes virtuels, que vous pouvez lire dans la documentation.
Les premiers tests
Ma première tentative utilise la petite image alpine, qui emballe déjà thttpd
:
FROM alpine:3.15.4 # Install thttpd RUN apk add thttpd # Create a non-root user to own the files and run our server RUN adduser -D static USER static WORKDIR /home/static # Copy the static website # Use the .dockerignore file to control what ends up inside the image! COPY . . # Run thttpd CMD ["thttpd", "-D", "-h", "0.0.0.0", "-p", "3000", "-d", "/home/static", "-u", "static", "-l", "-", "-M", "60"]
Vous pouvez construire et exécuter l’image en appelant :
docker build -t static:latest . docker run -it --rm -p 3000:3000 static:latest
…puis naviguer jusqu’à http://localhost:3000
.
L’image se construit rapidement et, à 7,77 Mo
, elle est assez petite :
> docker images | grep static static latest cb1750e32562 About an hour ago 7.77MB
Seconds tests
Nous pouvons aller plus loin en utilisant Docker scratch
, qui est en fait une image no-op, légère comme le vide. Le problème avec scratch
est que vous ne pouvez pas vraiment faire grand-chose à l’intérieur : vous ne pouvez pas créer de nouveaux utilisateurs, il n’y a pas de gestionnaire de paquets ni d’exécutable d’ailleurs – à part ceux que vous avez copiés vous-même.
L’utilisation de l’image scratch
nécessite généralement une approche en plusieurs étapes. Nous partons d’alpine
, téléchargeons et compilons thttpd
en tant que binaire statique, créons un utilisateur, puis copions ces actifs sur scratch et ajoutons nos fichiers statiques au mélange :
FROM alpine:3.15.4 AS builder ARG THTTPD_VERSION=2.29 # Install all dependencies required for compiling thttpd RUN apk add gcc musl-dev make # Download thttpd sources RUN wget http://www.acme.com/software/thttpd/thttpd-${THTTPD_VERSION}.tar.gz \ && tar xzf thttpd-${THTTPD_VERSION}.tar.gz \ && mv /thttpd-${THTTPD_VERSION} /thttpd # Compile thttpd to a static binary which we can copy around RUN cd /thttpd \ && ./configure \ && make CCOPT='-O2 -s -static' thttpd # Create a non-root user to own the files and run our server RUN adduser -D static # Switch to the scratch image FROM scratch EXPOSE 3000 # Copy over the user COPY --from=builder /etc/passwd /etc/passwd # Copy the thttpd static binary COPY --from=builder /thttpd/thttpd / # Use our non-root user USER static WORKDIR /home/static # Copy the static website # Use the .dockerignore file to control what ends up inside the image! COPY . . # Run thttpd CMD ["/thttpd", "-D", "-h", "0.0.0.0", "-p", "3000", "-d", "/home/static", "-u", "static", "-l", "-", "-M", "60"]
Jetons un autre coup d’œil à ces chiffres :
> docker images | grep static static latest ae708220dc8c About a minute ago 187kB
Les 187Ko qu’il nous reste correspondent à la taille du binaire statique thttpd
et des fichiers statiques qui ont été copiés, qui dans mon cas était juste un fichier contenant le texte hello world
. Notez que l’étape alpine de la construction en plusieurs étapes est en fait assez grande en taille (~130Mo), mais elle peut être réutilisée à travers les constructions et n’est pas poussée vers le registre.
À ce stade, vous pouvez convertir l’image que nous avons construite jusqu’à présent en une image de base pour tous vos sites Web statiques et la pousser vers un registre, de sorte que vous pouvez sauter l’étape alpine entièrement. Ou vous pouvez simplement utiliser via mon Docker Hub :
FROM alfreddagenais/small-docker-static-website:latest COPY . .
Cela produit une image mono-couche de 186KB + la taille de votre site web statique et rien d’autre. Si vous avez besoin de configurer thttpd
d’une manière différente, vous pouvez simplement remplacer la ligne CMD :
FROM alfreddagenais/small-docker-static-website:latest COPY . . CMD ["/thttpd", "-D", "-h", "0.0.0.0", "-p", "3000", "-d", "/home/static", "-u", "static", "-l", "-", "-M", "60"]
En conclusion
Docker peut être utilisé efficacement pour emballer et servir des sites web statiques.
Le code est disponible à l’adresse https://github.com/alfreddagenais/kilukru-dev-small-docker-static-website.