Servir son contenu statique avec Docker

Posted on jeu. 17 mai 2018 in adminsys

Docker est la technologie incontournable dans le monde de l'IT d'aujourd'hui. Elle peut être utilisée pour beaucoup de chose, mais ici, nous allons voir un cas d'usage simple : servir un contenu web statique en l'utilisant. En étant le plus minimaliste et le plus simple dans notre approche.

On va aussi se rajouter une contrainte supplémentaire, sinon, c'est pas drôle : je veux que le docker container soit aussi le plus minimaliste en termes d'utilisation ressources (disque, RAM, CPU), une fois en route. Et aussi, il faut que ça soit un peu rigolo à faire et sans prise de tête à configurer.

La voie royale : Nginx

Le plus simple et qui vient immédiatement à l'esprit est Nginx. Enfin, dans mon cas, car je le connais plutôt bien et qu'il est vraiment performant.

Pourquoi

Heu... vous connaissez Nginx, bien sûr, non ?

Ok, alors, présentons Nginx :

Nginx (pronounced "engine-x") is an open source reverse proxy server for HTTP, HTTPS, SMTP, POP3, and IMAP protocols, as well as a load balancer, HTTP cache, and a web server (origin server). The nginx project started with a strong focus on high concurrency, high performance and low memory usage.

En gros, Nginx est ultra performant pour du servir du contenu statique, il a été conçu pour ça et est beaucoup plus performant qu'Apache à tout point de vue pour cet usage particulier.

Code

Ok, comment fait-on, alors ? Simple : mettez juste le Dockerfile qui suit à la racine du contenu que vous voulez servir, buildez, et runnez, et fini.

FROM nginx:alpine
COPY . /usr/share/nginx/html

En détail, placez un fichier Dockerfile avec le contenu précédent (oui, juste ces 2 lignes) à la racine de votre dépôt git contenant vos fichiers statiques, puis faites ceci :

docker build -t static-content-server .
docker run -d -p "80:80" --name static-server static-content-server

Voilà. Je peux pas faire plus simple, je vous promets.

La voie de l'amusement

Le serveur web proprement dit

  • "Dis papa, comment on fait les serveurs web ?"
  • "Regarde ma fille, c'est facile. Tu peux même le faire toi-même"

Bon, c'est faisable en 15 lignes en go, mais si on en veut plus, un serveur web, avec doc incluse et quelques options sympa, ça se fait en ~250 lignes de go sur https://github.com/halverneus/static-file-server/blob/master/serve.go

Il faut git-cloner ce code, le builder et ensuite, on peut l'utiliser en l'incluant facile dans nos propre dépôt git.

D'abord, on build :

git clone https://github.com/halverneus/static-file-server.git
cd static-file-server
docker build -t static-file-server .

On met ça à la racine de notre dépôt git contenant les ressources statiques à servir:

FROM static-file-server
COPY . /web

Et ensuite, il faut builder et runner ce nouveau docker :

docker build -t static-content-server .
docker run -d -p "80:8080" --name static-server static-content-server

Avec Ansible

Et si on rajoutait du fun avec Ansible ? Commençons par un état des lieux :

user@computer:~/code$ tree startpage/
startpage/
├── Dockerfile
├── index.html
└── robots.txt

0 directories, 3 files

user@computer:~/code$ git -C startpage/ remote -v
origin  ssh://git@git.example.net/user/startpage.git (fetch)
origin  ssh://git@git.example.net/user/startpage.git (push)

user@computer:/home/code$ cat startpage/Dockerfile
FROM registry.example.net/static-file-server
COPY . /web

(Parce que je suis trop fainéant pour vous mettre des captures d'écran de dépôts git)

Voilà un petit playbook Ansible qui buildera, mettra dans une registry privée et fera tourner le serveur web pour vous servir le contenu de notre startpage contenu dans le dépôt git git.example.net/user/startpage.git.

- hosts: mon-super.serveur-perso.example.net
  tasks:

    - name: Get static-file-server code
      git:
              repo: https://github.com/halverneus/static-file-server.git
              dest: "{{ app_code_dir }}/static-file-server"
      register: git_pull_server

    - name: Build static-file-server
      docker_image:
              path: "{{ app_code_dir }}/static-file-server"
              name: medusa
              tag: latest
              push: yes
              force: yes
              repository: registry.example.net/static-file-server
      when: git_pull_server.after != git_pull_server.before

    - name: Get StartPage code
      git:
              repo: ssh://git@git.example.net/user/startpage.git
              dest: "{{ app_code_dir }}/startpage"
              key_file: "{{ app_data_dir }}/.ssh/id_rsa"
      register: git_pull

    - name: Build Startpage
      docker_image:
              path: "{{ app_code_dir }}/startpage"
              name: startpage
              tag: latest
              push: yes
              force: yes
              repository: registry.example.net/startpage
      when: git_pull.after != git_pull.before

    - name: Deploy StartPage
      docker_container:
              pull: yes
              name: StartPage
              image: registry.example.net/startpage:latest
              ports:  
                      - "80:8080"
              restart_policy: unless-stopped

PS : le playbook ansible est moche, il faut le découper en rôles, avec des handler, et tout et tout, mais ça, je vous laisse le faire ;-)