Le labo de Nico

🔭 đŸŽ¶ đŸ•ș

Pourquoi Docker ?

6 août 2020

Pour travailler ensemble

Tout le monde dĂ©veloppe sur diffĂ©rentes machines. Il n’est pas rare que plusieurs collĂšgues aient installĂ© diffĂ©rentes version d’une mĂȘme library, d’un package manager, du runtime de leur application
​ (cc node/npm 👋)

Lorsque l’application de dĂ©veloppement est dockerisĂ©e, tous les devs (et la prod !) sont soumis aux mĂȘmes rĂšgles, ce qui Ă©vite le syndrĂŽme de "mais ça marche sur mon PC" tout en rĂ©duisant la configuration nĂ©cessaire Ă  installer l’environnement de dev. Voir juste aprĂšs !

Pour moins perdre de temps Ă  configurer

La configuration, c’est du temps passĂ© Ă  ne pas ĂȘtre productif. Plus il y a d’environnements dans lesquels une application doit tourner, plus il y a de configuration Ă  faire. Docker permet d’abstraire l’environnement dans lequel tourne l’application et donc de ne faire que le minimum nĂ©cessaire.

Une consĂ©quence notable : pour ajouter un service Ă  la stack, plus forcĂ©ment besoin d’apprendre en dĂ©tails une technologie. Il suffit d’ajouter une image existante de celle-ci, et de simplement spĂ©cifier les variables d’environnement nĂ©cessaires. Par exemple, pour ajouter une database PostgreSQL, il suffit au minimum de renseigner un root password et de monter un volume pour persister les donnĂ©es.

Pour séparer les problÚmes

Comme chaque service est aussi simple que possible, chacun n’a que trĂšs peu de dĂ©pendances avec le reste du monde. On voit que, par nature, les conteneurs nous poussent Ă  n’avoir que le minimum vital de dĂ©pendances entre services.

Par dépendances, je pense en particulier à :

  • SystĂšme, programmes, libraries installĂ©es
  • Configurations associĂ©es Ă  ce setup
  • Volumes (fichiers)
  • AccĂšs rĂ©seau

Pour gérer et sécuriser les connexions réseau

Car oui : c’est vite fait de faire fuiter le port d’une database, et quand elle n’est pas sĂ©curisĂ©e c’est gĂȘnant 😬

L’idĂ©e est de penser un service comme une boĂźte noire qui expose un ou plusieurs ports. Les services communiquent entre eux grĂące aux volumes montĂ©s en commun ou Ă  travers des ports internes. En effet, les services appartenant Ă  un mĂȘme rĂ©seau peuvent par dĂ©faut s’accĂ©der entre eux.

PiĂšges et trucs Ă  savoir

Sous Windows et Mac, les conteneurs tournent sur une VM. Du coup c’est lent, pas natif et les lectures/Ă©critures disque peuvent ralentir l’édition de fichiers. La solution est simple : utilise Linux 😏 (ou un Windows/Mac puissant)

Lorsqu’un mĂȘme volume (dossier) est montĂ© en Ă©criture dans deux conteneurs Ă  la fois, on peut se retrouver avec des comportements inattendus : chez moi, l’intĂ©gralitĂ© du dossier gĂ©nĂ©rĂ© par un run de build disparaissait en mĂȘme temps que le conteneur Ă  la fin du run. Je recommande donc vivement de ne monter en Ă©criture qu’un seul fichier ou dossier Ă  la fois.

C’est possible de ne partager en Ă©criture qu’une partie d’une mĂȘme arborescence commune. Par exemple, si backend et frontend partagent code en lecture mais que backend doit Ă©crire dans code/target et frontend doit Ă©crire dans code/dist, alors les volumes peuvent ĂȘtre surchargĂ©s comme ceci :

backend:
  volumes:
    - ./code:/code:ro
    - ./code/target:/code/target

webapp:
  volumes:
    - ./code:/code:ro
    - ./code/dist:/code/dist

Les images Docker peuvent vite prendre de l’espace disque. Mais avec le temps, la communautĂ© opte de plus en plus pour des versions minimalistes de chaque image. Autrefois avec une version slim de Debian, et aujourd’hui souvent avec une version Alpine Linux qui permet aux images de faire moins de 10Mo de base ! PrĂ©fĂšre-donc utiliser les tags -alpine de chaque image.

Enfin, la gestion des permissions est dĂ©routante au dĂ©but. Docker tourne en root par dĂ©faut et a de bonnes raisons de le faire : autant dire que j’apprĂ©cie de pouvoir ouvrir les ports 80 ou 443 en dev comme en prod 🙂

Pour mieux comprendre pourquoi et comment bien gérer ses permissions : voir cet article.

Par oĂč commencer?

En prenant le temps de lire la doc dans l’ordre, tout ne peut que bien se passer :

  1. Comprends Docker
  2. Comprends docker compose pour simplement faire cohabiter les services entre eux
  3. Installe docker et son plugin compose
  4. Ajoute ton user au groupe docker pour piloter le daemon sans sudo
  5. C’est parti ! N’oublie pas de garder la configuration la plus simple possible.
Exemple

Une stack complĂšte React/Rust/PostgreSQL pourrait ĂȘtre lancĂ©e avec la simple config suivante Ă  la racine d’un projet :

version: "3"
services:
  db:
    image: postgres:alpine
    environment:
      - POSTGRES_PASSWORD=yolo
    volumes:
      - ./db/data:/var/lib/postgresql/data
  backend:
    image: rust:slim
    environment:
      - PGHOST=db
      - PGDATABASE=monservice
      - PGUSER=root
      - PGPASSWORD=yolo
    volumes:
      - ./backend/:/home/backend
      - ./webapp/:/home/webapp:ro
    command: cargo run
    ports:
      - 4000:4000
  webapp:
    image: node:alpine
    environment:
      - BACKEND_URL=http://backend:4000/
    volumes:
      - ./webapp/:/home/webapp
    command: sh -c "yarn install && CI=true yarn start"
    ports:
      - 80:8080

docker compose up -d et c’est parti directement sur localhost ! đŸ’»