Comment déployer un site statique à la demande via Docker (CaaS) et votre propre image

Quelques commandes suffisent
Comment déployer un site statique à la demande via Docker (CaaS) et votre propre image
Crédits : bugphai/iStock

Après avoir évoqué les bases de Docker et la création de vos propres images, il est temps d'utiliser vos nouvelles connaissances pour déployer un premier site (statique). Nous en profiterons pour évoquer la manière de stocker vos images dans un registre privé ou public.

Comme nous l'avons vu dans notre précédent article, Docker permet de gérer des conteneurs mais aussi de créer des images et de les déployer. Vous pouvez ainsi rendre facilement accessible un site, application ou service depuis un serveur local. Mais comment faire lorsque vous voulez le proposer en ligne, via un serveur tiers ?

Pour cela, il existe différentes méthodes et outils. L'un d'entre eux est le registre qui stocke les images et permet de les distribuer en ligne, de manière publique ou privée. Docker propose son hub, mais bien d'autres existent. Ils fonctionnent parfois de pair avec des outils de déploiement spécifique, pour vous faciliter la vie.

Faisons un premier essai en cherchant à déployer un petit site statique.

Notre dossier sur les conteneurs :

Vous préparer avant de commencer

Jusque-là, nous avions travaillé avec un Raspberry Pi, ce ne sera pas le cas ici. Pourquoi ? Parce qu'il génère des images pour une architecture ARM similaire à la sienne. Docker gère bien la création d'images multi-architectures, mais il faut pour cela utiliser Docker Desktop et buildx, que nous évoquerons dans un prochain article.

Pour ne pas avoir à dépendre d'une machine en particulier, nous utiliserons donc une instance sous la forme d'un serveur x86-64 pour générer notre image, qui sera déployée sur un serveur exploitant une architecture similaire. Notez que dans le cas d'un déploiement en production, ce sont les outils de CI/CD qui ont à gérer ces questions.

Commençons donc par créer et nous connecter à une instance avec Docker préinstallée. Nous avons opté pour une DEV1-S de Scaleway, chez qui nous déploierons également notre site par la suite :

Docker Scaleway DEV1-S

Récupération du code, déploiement d'une image de base

Une fois connecté, nous mettons le serveur à jour et y installons git pour récupérer le code du site :

sudo apt update && sudo apt full-upgrade && sudo apt autoremove
sudo apt install git

Le code du site est celui d'un précédent projet que nous avons dû adapter du fait de modifications depuis sa création. Il consiste à lister les applications disponibles via winget pour en faire le compte et la liste. Nous récupérons le code via son dépôt GitHub, le plaçons dans un dossier src/ et lançons un conteneur de test :

mkdir -p psw/src
cd psw/src
git clone https://github.com/davlgd/pwa-static-winget .

cd..
docker run --rm -v $PWD/src:/usr/share/nginx/html/ -p 8080:80 nginx:alpine

Si vous vous rendez l'URL suivante, votre site devrait être visible en ligne :

http://ip_publique_du_serveur:8080

Création et déploiement de votre propre image

Imaginons maintenant que vous vouliez utiliser une image que vous avez adaptée à vos besoins. Dans notre cas, nous nous contenterons de mettre à jour Alpine Linux pendant la phase de build. Nous éditons le dockerfile :

nano dockerfile

Pour y placer le contenu suivant :

FROM nginx:alpine
RUN apk update && apk upgrade

COPY src/ /usr/share/nginx/html/

EXPOSE 80

Notez que nous plaçons cette fois le contenu du site directement dans l'image, afin qu'il y soit ajouté dans la phase de build. Cela permet d'avoir une image prête à l'emploi, d'autant qu'il n'est pas toujours possible d'indiquer un volume à monter lorsqu'on lance un conteneur, comme nous le verrons un peu plus loin.

Une fois le fichier enregistré et l'éditeur quitté (CTRL+X), on lance la création de l'image qui sera nommée « psw » :

docker build -t psw .

Puis on lance un conteneur de test pour vérifier que tout fonctionne : 

docker run --rm -p 8080:80 psw

Normalement, tout fonctionne comme précédemment. L'image ainsi créée pèse 25,7 Mo (docker images).

Stockez vos images et distribuez-les via un registre

Mettons maintenant cette image à disposition de tous. Pour cela nous utiliserons un registre. Suite à un changement de politique du Docker Hub, plusieurs services ont créé le leur. AWS propose le sien, tout comme GitHub ou OVHcloud. Ici, nous utiliserons celui de Scaleway gratuit pour des images publiques jusqu'à 75 Go. Vous pouvez également y stocker vos images privées pour 0,025 euro HT par Go (0,03 euro HT par Go de trafic sortant).

La première chose à faire est de créer une clé API dans la console puis un espace de noms dans le registre :

Namespace Conteneur Scaleway

Il sert à regrouper plusieurs images entre elles afin de les organiser. Il faut lui choisir un nom, une description (facultative), une région (Amsterdam, Paris ou Varsovie) et une politique de confidentialité (publique ou privée). Chaque espace de noms dispose d'un identifiant. Vous pouvez modifier la confidentialité par la suite, pour l'ensemble des images ou certaines en particulier. Mais pas la région, qui est fixe.

Après la création, les instructions de connexion via Docker sont affichées. Mais privilégiez plutôt cette forme qui évite d'avoir à indiquer le mot de passe dans une commande du terminal (elles sont historisées) :

docker login rg.fr-par.scw.cloud/nom_du_namespace -u nologin

La partie secrète de votre clé API vous sera alors demandée et, si elle est correcte, la connexion sera confirmée :

# docker login rg.fr-par.scw.cloud/davlgd-public -u nologin
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

Comme indiqué dans le message ci-dessus, il est recommandé d'utiliser un store externe spécifique pour les données de connexion, afin qu'elles ne soient pas stockées en clair sur la machine. Leur documentation se trouve ici. Une fois connecté, il est simple d'ajouter votre image, il suffit de la taguer puis de la « pousser » :

docker tag psw:latest rg.fr-par.scw.cloud/davlgd-public/psw:latest
docker push rg.fr-par.scw.cloud/davlgd-public/psw:latest

Ces deux étapes sont à recommencer à chaque reconstruction de l'image (build). Vous pouvez également pousser différentes versions d'une même image pour les utiliser selon les différents besoins. Si tout s'est bien passé vous devriez voir votre image apparaître dans votre espace de noms. Puis l'utiliser pour créer un conteneur :

docker run --rm -p 8080:80 url_de_votre_image

Soit dans notre cas (cette image est publique, vous pouvez l'utiliser) :

docker run --rm -p 8080:80 rg.fr-par.scw.cloud/davlgd-public/psw:latest

Notez que cette procédure n'est pas propre à Scaleway. Elle est identique à celle appliquée pour le Docker Hub ainsi que d'autres registres similaires. Ce registre peut stocker toute image compatible OCI (Docker, Helm Charts).

Déploiement et usage à la demande (CaaS)

Notez que Scaleway propose, comme d'autres, un déploiement des images stockées dans son service de registre via son offre dite « serverless ». Ainsi, votre site peut être mis en place non pas sur une instance constamment en ligne, mais accessible (et donc facturée) uniquement lorsqu'elle est demandée, avec la possibilité de s'adapter à la charge avec une distribution via plusieurs instances si vous le désirez. 

Container as a Service Scaleway FacturationContainer as a Service Scaleway Facturation

Cela demande une modification dans l'exposition des ports de notre image, un point évoqué à différents endroits de l'interface, mais qui gagnerait à être évoqué de manière plus claire, notamment dans la documentation. Après avoir effectué différents tests, nous avons pu confirmer qu'il suffit bien d'utiliser et d'exposer le port 8080.

Cela passe par une modification du serveur web nginx à qui vous devez soumettre un fichier de configuration modifié. On le place à la racine de notre projet pour pouvoir l'intégrer spécifiquement dans l'image :

nano scaleway.conf

On y ajoute le contenu suivant. Il reprend les paramètres par défaut de nginx, à compléter selon vos besoins :

server {
listen 8080;
listen [::]:8080;
server_name localhost;

location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
}

On modifie ensuite le fichier dockerfile qui aura alors le contenu suivant :

FROM nginx:alpine
RUN apk update && apk upgrade

COPY src/ /usr/share/nginx/html/
COPY scaleway.conf /etc/nginx/conf.d/default.conf

EXPOSE 8080

Une solution qui ne facilite pas un déploiement à l'identique et sans contrainte depuis n'importe quelle image, on préfèrerait disposer d'une gestion plus flexible des ports exploitables ou non sur un conteneur déployé. Ce service a d'autres limitations, détaillées ici : image d'un maximum de 250 Mo (compressée) ou 1 Go (décompressée), 512 Mo de stockage temporaire au maximum, 1 000 requêtes par seconde maximum, etc.

Il est en effet pensé pour répondre à de petits besoins, des usages ponctuels. Si nous l'avons utilisé pour un petit site, il pourrait très bien servir à récupérer régulièrement (via CRON) le code d'un projet, le compiler et le stocker dans un bucket S3 par exemple. Ou récupérer des fichiers, les traiter, compresser et diffuser en ligne. L'intérêt principal étant ici de ne pas avoir une instance constamment en ligne, mais un usage/facturation à la demande.

On a tout de même certains regrets, notamment dans la façon de gérer les images, dont on ne sait pas pour quelles architectures elles ont été construites. Ainsi, nous avons pu envoyer une image ARM depuis un Raspberry Pi sans alerte, sans mention dans l'interface. Et en cas de tentative de déploiement ? Aucune erreur explicite n'était affichée. On avait juste droit à une mention (tooltip) indiquant que la procédure a planté. Peut mieux faire...

  • Container as a Service Scaleway
  • Container as a Service Scaleway
  • Container as a Service Scaleway
  • Container as a Service Scaleway Facturation

Quoi qu'il en soit, une fois l'image modifiée et poussée dans le registre, créez un espace de nom dans le service de conteneurs. Il est pour le moment forcément hébergé à Paris. Si nécessaire vous pouvez définir des variables d'environnement (ce qui n'est pas utile dans notre exemple). Vous pourrez choisir d'y déployer un conteneur, ou le faire depuis le menu « ... » à droite de votre image dans le service de registre.

Plusieurs paramètres sont proposés : nom du conteneur, ressources mises à disposition, accès simultanés, délai d'expiration, création de « triggers » CRON (pour un lancement régulier) ou MQTT (un protocole de messagerie PubSub). Laissez tout par défaut et limitez à une instance. Un minimum de 0 instance permettra de ne pas être facturé lorsque le conteneur n'est pas actif, mais le site sera parfois lent au premier accès (cold start). 

Une fois le déploiement lancé, il suffit de quelques secondes pour que le site soit accessible. Une URL lui est attribuée, l'accès se fait sans avoir à préciser de numéro de port (le 80 est utilisé). Et si jamais l'image évolue ? Poussez la nouvelle version dans le registre. Elle ne sera pas automatiquement déployée, mais si vous demandez un nouveau déploiement d'un conteneur actif, il sera mis à jour et le nouveau site prendra la place de l'ancien.

Vous pouvez d'ailleurs le faire via l'API, de manière à automatiser vous-même ce processus. Notez que les sources du projet ici développé sont disponibles dans une branche spécifique de notre dépôt GitHub.

Vous n'avez pas encore de notification

Page d'accueil
Options d'affichage
Abonné
Actualités
Abonné
Des thèmes sont disponibles :
Thème de baseThème de baseThème sombreThème sombreThème yinyang clairThème yinyang clairThème yinyang sombreThème yinyang sombreThème orange mécanique clairThème orange mécanique clairThème orange mécanique sombreThème orange mécanique sombreThème rose clairThème rose clairThème rose sombreThème rose sombre

Vous n'êtes pas encore INpactien ?

Inscrivez-vous !