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

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

Quelques commandes suffisent

Avatar de l'auteur
David Legrand

Publié dans

Internet

25/11/2021 10 minutes
20

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

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.

Écrit par David Legrand

Tiens, en parlant de ça :

Sommaire de l'article

Introduction

Vous préparer avant de commencer

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

Création et déploiement de votre propre image

Stockez vos images et distribuez-les via un registre

Déploiement et usage à la demande (CaaS)

Fermer

Commentaires (20)


Merci pour cette série d’articles.



Par contre, tout cet arsenal pour des pages statiques… :reflechis: :D


C’est justement le contraire, sur le fond tu monopolises juste un conteneur activé à la demande, là où certains hébergent ce genre de site sur des instances surdimensionnées ou des serveurs mutualisés/dédiés constamment fonctionnels. On a dit “éco-conception” :D



Pour la création, ça peut paraître lourd parce que je détaille tout, mais en réalité tu récupères le code, tu déploies, tu en as pour 2 minutes, allez 10 si tu n’as pas de compte au départ :D



PS : et comme évoqué à la fin de l’article, je prends l’exemple d’un site parce qu’il est simple à comprendre avec quelque chose de “concret” au bout. Mais tu mets dans ton conteneur ce que tu veux. C’est tout l’intérêt d’une telle solution par rapport à une figée sur un usage particulier.


David_L

C’est justement le contraire, sur le fond tu monopolises juste un conteneur activé à la demande, là où certains hébergent ce genre de site sur des instances surdimensionnées ou des serveurs mutualisés/dédiés constamment fonctionnels. On a dit “éco-conception” :D



Pour la création, ça peut paraître lourd parce que je détaille tout, mais en réalité tu récupères le code, tu déploies, tu en as pour 2 minutes, allez 10 si tu n’as pas de compte au départ :D



PS : et comme évoqué à la fin de l’article, je prends l’exemple d’un site parce qu’il est simple à comprendre avec quelque chose de “concret” au bout. Mais tu mets dans ton conteneur ce que tu veux. C’est tout l’intérêt d’une telle solution par rapport à une figée sur un usage particulier.


Je vois l’idée, mais pour des pages statiques, ça n’est pas super convaincant par rapport à un mutualisé ;). Mais je vois l’intérêt pour des services intensifs en cpu, à la sollicitation irrégulière.



Et un grand merci pour cette série d’articles, ça permet d’y voir un peu plus clair quand on suit ça de très loin. Une présentation claire et sans jargon, c’est ce que j’attendais depuis longtemps :inpactitude:


white_tentacle

Je vois l’idée, mais pour des pages statiques, ça n’est pas super convaincant par rapport à un mutualisé ;). Mais je vois l’intérêt pour des services intensifs en cpu, à la sollicitation irrégulière.



Et un grand merci pour cette série d’articles, ça permet d’y voir un peu plus clair quand on suit ça de très loin. Une présentation claire et sans jargon, c’est ce que j’attendais depuis longtemps :inpactitude:


Il n’y a pas de règle constamment valable. Si tu veux un site pour répondre à quelques requête ici ou là (j’en ai quelques uns à titre perso), du CaaS fera l’affaire.



Pourquoi payer un serveur à l’année ? Comme ça peut être très adapté pour répondre à certaines requêtes via une brique isolée. Si tu as un besoin constant et du trafic plus ou moins important, tu iras vers d’autres solutions (mutualisé ou PaaS, le second simplifiant le déploiement).


David_L

C’est justement le contraire, sur le fond tu monopolises juste un conteneur activé à la demande, là où certains hébergent ce genre de site sur des instances surdimensionnées ou des serveurs mutualisés/dédiés constamment fonctionnels. On a dit “éco-conception” :D



Pour la création, ça peut paraître lourd parce que je détaille tout, mais en réalité tu récupères le code, tu déploies, tu en as pour 2 minutes, allez 10 si tu n’as pas de compte au départ :D



PS : et comme évoqué à la fin de l’article, je prends l’exemple d’un site parce qu’il est simple à comprendre avec quelque chose de “concret” au bout. Mais tu mets dans ton conteneur ce que tu veux. C’est tout l’intérêt d’une telle solution par rapport à une figée sur un usage particulier.


Je comprends bien l’exercice pour démontrer l’usage d’un conteneur.



Une autre approche pour un site statique, et tout en restant chez Scaleway, pourrait être d’utiliser un bucket S3 : + “éco-friendly” et + simple.



La fonction Bucket Website permet d’héberger des sites web statiques en utilisant Scaleway Object Storage. + d’infos


Novariom

Je comprends bien l’exercice pour démontrer l’usage d’un conteneur.



Une autre approche pour un site statique, et tout en restant chez Scaleway, pourrait être d’utiliser un bucket S3 : + “éco-friendly” et + simple.



La fonction Bucket Website permet d’héberger des sites web statiques en utilisant Scaleway Object Storage. + d’infos


effectivement ca peut paraitre lourd quand on ne maitrise pas bien mais sur le long terme ca semble très intéressant… après chaque cas/besoin est différent… je vais tester ça bientot :ouioui:



David_L a dit:


Mais tu mets dans ton conteneur ce que tu veux.




Un ERP par exemple ? :fou3: :pleure: :fume:



Mais sinon, c’est cool les articles qui démystifient la techno.
:inpactitude:


Je tente de m’y mettre à Docker via mon NAS QNAP, au départ parce que les applications natives font tout en tant qu’admin, donc pas top.
C’est un peu l’angoisse quand on débute, surtout avec les outils simplifiés QNAP… qui complexifient au final plus qu’autre chose.
Heureusement Portainer me permet un peu plus de marge de manoeuvre, mais j’ai encore de quoi creuser de mon côté car j’arrive même pas à éditer le settings.json de mon container Transmission :oops:



En tout cas cette virtualisation du contenu est hyper intéressante pour la modularité de l’hébergement. Effectivement pour un site à très faible trafic, le montage à la demande peut être une super idée pour s’héberger à faible coût.


En dehors de l’aspect pédagogique sur Docker y’a plus simple



genre Github Pages c’est 10x plus simple pour déployer un site statique (qui en plus se met a jour a chaque git commit sans autre intervention)


Voir le projet de départ du site (le lien est dans l’article ;)) Comme dit, ce n’est qu’un prétexte à du déploiement Docker sur un serveur distant, de manière classique ou CaaS.



Note au passage que Pages c’est un peu différent puisque le but principal c’est d’utiliser un template pour un site qui sera généré avant d’être déployé, le plus souvent pour présenter un projet issu d’un dépôt (ça a été créé pour ça au départ), ce qui n’est pas le cas ici.


David_L

Voir le projet de départ du site (le lien est dans l’article ;)) Comme dit, ce n’est qu’un prétexte à du déploiement Docker sur un serveur distant, de manière classique ou CaaS.



Note au passage que Pages c’est un peu différent puisque le but principal c’est d’utiliser un template pour un site qui sera généré avant d’être déployé, le plus souvent pour présenter un projet issu d’un dépôt (ça a été créé pour ça au départ), ce qui n’est pas le cas ici.


Pages ce n’est pas que des templates. On peut déployer n’importe quel site statique avec et même le faire générer avec l’automation de Github Actions. J’utilise Hugo par exemple avec le résultat sur un site Pages. D’ailleurs leur templates utilisent Jekyll.



Mais effectivement ce n’est pas le but ici.


kgersen

Pages ce n’est pas que des templates. On peut déployer n’importe quel site statique avec et même le faire générer avec l’automation de Github Actions. J’utilise Hugo par exemple avec le résultat sur un site Pages. D’ailleurs leur templates utilisent Jekyll.



Mais effectivement ce n’est pas le but ici.


Ce que je veux dire, c’est que comme précisé dans l’article, le code ici déployé est un prétexte, pas représentatif du use case ultime (concept qui n’existe pas)


David_L

Ce que je veux dire, c’est que comme précisé dans l’article, le code ici déployé est un prétexte, pas représentatif du use case ultime (concept qui n’existe pas)


oui j’avais bien compris ce point. C’était juste d’être certain que quelqu’un qui a cet use case ne s’embarque pas dans du Docker parce qu’il tombe sur cet article. Je pense que ca serait bien de l’indiquer dans l’article car son titre peut laisser pensé que c’est une solution sérieuse et pérenne et pas juste un exercice pédagogique sur Docker.


kgersen

oui j’avais bien compris ce point. C’était juste d’être certain que quelqu’un qui a cet use case ne s’embarque pas dans du Docker parce qu’il tombe sur cet article. Je pense que ca serait bien de l’indiquer dans l’article car son titre peut laisser pensé que c’est une solution sérieuse et pérenne et pas juste un exercice pédagogique sur Docker.


C’est aussi pour ça que je renvoie vers l’exemple initial qui était un hébergement PaaS plus “classique”. Et le titre mentionne ici bien qu’on le fait de manière spécifique pour un usage “à la demande” (et donc CaaS). Mais c’est comme quand on explique comment faire un site web nginx/alpine, ça permet de découvrir les possibilités et les bases. Si tu veux faire de la prod “sérieuse”, il faut forcément aller un peu plus loin :D


Excellent article ! Merci !
Pour ceux qui sont intéressés en plus par une infra décentralisée et indépendante, je recommande de se renseigner sur runonflux.io que j’ai découvert récemment.


Un exemple que je trouve pas mal pour illustrer la puissance des containers et de l’orchestration liée (notamment via Kubernetes), c’est de faire ça avec un orchestrateur CI/CD à la Jenkins ou Gitlab CI.



Un master qui s’interface avec un cluster K8S (voire qui peut lui-même être dessus, mais c’est pas forcément le meilleur choix), et qui derrière provisionne du pod à la demande des différents jobs de build en utilisant l’image de container adaptée à la situation (image pour build du node, du java, du python, du docker … Car oui, on peut faire des containers qui build des containers :D).



Pour l’exemple de l’article, perso c’est pas le choix que je ferais non plus même s’il illustre très bien le cas d’usage. Dans le cas d’un site statique, je partirais plus sur un stockage compatible S3 avec un frontal devant qui servira la couche TLS + le nom de domaine (soit via un composant d’un cloud provider, soit un simple reverse proxy qui peut être mis pour le coup en container). Tout dépend aussi du prix qu’on veut y mettre, un frontal applicatif peut engendrer un certain coût chez un public cloud provider.


Dans tous les cas tu paiera ton frontal de manière constante. L’intérêt du CaaS ici évoqué, c’est de montrer que tu peux avoir un conteneur, mais monté et facturé uniquement à la demande. Après il faut pouvoir supporter le cold start, mais c’est une option intéressante qui peut être utile dans certains cas ou pour certains éléments non critiques (en termes de réactivité) d’une infra.


David_L

Dans tous les cas tu paiera ton frontal de manière constante. L’intérêt du CaaS ici évoqué, c’est de montrer que tu peux avoir un conteneur, mais monté et facturé uniquement à la demande. Après il faut pouvoir supporter le cold start, mais c’est une option intéressante qui peut être utile dans certains cas ou pour certains éléments non critiques (en termes de réactivité) d’une infra.


Chez AWS, ils annonce un cold start en 1/10e de seconde.


David_L

Dans tous les cas tu paiera ton frontal de manière constante. L’intérêt du CaaS ici évoqué, c’est de montrer que tu peux avoir un conteneur, mais monté et facturé uniquement à la demande. Après il faut pouvoir supporter le cold start, mais c’est une option intéressante qui peut être utile dans certains cas ou pour certains éléments non critiques (en termes de réactivité) d’une infra.


Après j’avoue avoir beaucoup plus en tête le next fucking level avec Kubernetes qui permet d’avoir une orchestration bien chiadée pour du à la demande. :D