Aller au contenu

Introduction

Docker est une plateforme open-source qui permet d’automatiser le déploiement d’applications à l’intérieur de conteneurs légers et portables

Un conteneur regroupe tout ce dont une application a besoin pour fonctionner : le code, les bibliothèques, les dépendances et le système d'exploitation léger

Cela permet de s’assurer que l’application fonctionne de manière cohérente, indépendamment de l’environnement


Concepts de base

  • Images : Les images sont des instantanés d’applications. Elles sont immuables et servent de modèles pour les conteneurs. Elles sont créées à partir d’un Dockerfile
  • Conteneurs : Les conteneurs sont des instances d’images qui tournent. Ils sont légers et portables
  • Dockerfile : Un fichier texte qui contient les instructions pour construire une image Docker

Avantages de Docker

  • Portabilité : Fonctionne de manière identique sur tous les environnements
  • Isolation : Les conteneurs isolent l’application, ses dépendances et les processus
  • Rapidité : Les conteneurs démarrent rapidement grâce à leur légèreté
  • Scalabilité : Facile à mettre à l'échelle (scaler) en utilisant des systèmes d'orchestration comme Kubernetes

Création d'un Dockerfile

Un Dockerfile est un fichier texte qui contient une série d'instructions permettant de construire une image Docker

Explication des directives principales : - FROM : Spécifie l’image de base à utiliser (ex : Node.js, Python, Alpine) - WORKDIR : Définit le répertoire de travail à l’intérieur du conteneur - COPY : Copie les fichiers de l’hôte dans le conteneur - RUN : Exécute une commande pendant la construction de l’image - EXPOSE : Indique le port sur lequel l’application sera exposée - CMD : Spécifie la commande par défaut à exécuter lorsque le conteneur démarre


Structure d’un Dockerfile

Exemple pour une application Node.js (optimisé pour le cache des couches) :

# 1. Utiliser une version LTS récente
FROM node:20-alpine

# 2. Définir le répertoire de travail
WORKDIR /usr/src/app

# 3. Copier d'abord les fichiers de dépendances (optimisation cache)
COPY package*.json ./

# 4. Installer les dépendances
RUN npm ci

# 5. Copier le reste du code source
COPY . .

# 6. Exposer le port et démarrer
EXPOSE 3000
CMD ["node", "app.js"]

Optimisations possibles

Pour améliorer les performances et la taille de vos images Docker, voici quelques bonnes pratiques :

  1. Utilisation des images légères
    Il est préférable d’utiliser des images de base légères, comme alpine, pour réduire la taille de l’image :
FROM node:20-alpine

Cela permet de réduire considérablement la taille de l’image


Optimisations possibles

  1. Réduction du nombre de couches

    Chaque instruction Docker crée une nouvelle couche. Pour réduire la taille des images, combinez les instructions RUN :
RUN apt-get update && \
    apt-get install -y curl && \
    apt-get clean

Optimisations possibles

  1. Nettoyage après installation
    Lorsque vous installez des dépendances ou des outils, nettoyez les fichiers inutiles après :
RUN apt-get update && apt-get install -y \
    build-essential \
 && rm -rf /var/lib/apt/lists/*

Optimisations possibles

  1. Utilisation de multi-stage builds
    Les multi-stage builds permettent de réduire la taille de l’image finale en ne conservant que les fichiers essentiels à l’exécution :
# Étape 1: Construction
FROM node:20-alpine as builder
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Étape 2: Production
FROM node:20-alpine
WORKDIR /usr/src/app
ENV NODE_ENV=production
COPY --from=builder /usr/src/app/dist ./dist
COPY --from=builder /usr/src/app/node_modules ./node_modules
CMD ["node", "dist/app.js"]

Bonnes pratiques

  • Minimalisme : Essayez de garder vos images aussi petites que possible pour des raisons de performance et de sécurité
  • Utilisez .dockerignore : Tout comme .gitignore, ce fichier permet d’exclure les fichiers inutiles (logs, node_modules locaux)
  • Sécurité : Évitez d’inclure des secrets (clés API) dans le Dockerfile. Utilisez des variables d’environnement
  • Versionner vos images : Utilisez des tags spécifiques et évitez le tag latest pour garantir la reproductibilité
  • Testez vos images localement : Assurez-vous du bon fonctionnement avant de pousser vers un registre

Récap

Docker est un outil puissant pour le déploiement et la gestion d’applications dans des environnements isolés et reproductibles. En suivant les bonnes pratiques, il est possible de créer des images légères, performantes et sécurisées, tout en améliorant la portabilité de vos applications


Let's build !


Build Docker Image avec Docker-in-Docker (DinD)

Le principe du Docker-in-Docker (DinD) est de permettre d'exécuter Docker à l'intérieur d'un conteneur Docker

# .gitlab-ci.yml
stages:
  - build

variables:
  DOCKER_DRIVER: overlay2
  DOCKER_HOST: tcp://docker:2375
  DOCKER_TLS_CERTDIR: ""

services:
  - docker:dind

build_image:
  stage: build
  image: docker:latest
  script:
    - docker info
    - docker build -t my-app .
    - docker images
  • Services : GitLab CI démarre un démon Docker via le service docker:dind
  • Variables : DOCKER_HOST permet la communication avec le démon
  • Image Docker : Utilisation de l'image officielle docker:latest
  • Script : La commande docker build construit l'image à partir du Dockerfile

Build Docker Image avec Kaniko

Kaniko construit des images Docker sans avoir besoin d'exécuter le démon Docker. C'est plus sécurisé (pas de mode privilégié) et idéal pour Kubernetes

# .gitlab-ci.yml
build_image:
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  script:
    - mkdir -p /kaniko/.docker
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
    - /kaniko/executor --dockerfile $CI_PROJECT_DIR/Dockerfile --context $CI_PROJECT_DIR --destination $IMAGE_NAME
  • Sécurité : Pas besoin d'accès privilégié sur le Runner
  • Authentification : Kaniko gère l'auth au registre via un fichier config.json injecté
  • Performance : Build natif efficace dans des environnements conteneurisés

Benchmark

DinD (Docker-in-Docker) : - Plus simple et familier pour les utilisateurs de Docker - Nécessite souvent des privilèges élevés (risque sécurité) - Supporte bien le cache local si configuré proprement

Kaniko : - Plus sécurisé (rootless, pas de démon Docker) - Temps de construction légèrement supérieur - Solution recommandée pour les clusters Kubernetes (ex: GitLab Runners sur K8s)


☕️ Si tu souhaites soutenir mon travail, tu peux m'offrir un café ici.