shelf, bookcase, library

Gérer l’ordre de démarrage de vos containers Docker avec un script Bash simple et efficace

Ce qu’il faut retenir

  • Le script automatise l’arrêt complet des containers puis leur redémarrage dans un ordre défini : d’abord les services critiques (Nginx Proxy Manager, MariaDB, Apache), ensuite les applications métier.
  • Il sépare les conteneurs en deux tableaux (PRIORITY_CONTAINERS et ADDITIONAL_CONTAINERS) pour garantir que les services d’infrastructure sont opérationnels avant de lancer les containers secondaires, contournant ainsi les limites de depends_on.
  • Cette approche ne modifie aucun docker‑compose.yml existant, est facilement personnalisable (chemins, temps d’attente, variables d’environnement) et peut être installée comme commande globale dans ~/.local/bin pour une utilisation quotidienne fluide.

Résumé généré par IA

Quand on travaille sur plusieurs projets Docker en parallèle, la gestion du démarrage des containers peut vite devenir un casse-tête. Imaginons un environnement de développement typique : un Nginx Proxy Manager qui gère vos entrées HTTP, une base de données MariaDB partagée, et plusieurs applications web indépendantes. Chaque projet a son propre docker-compose.yml, ce qui est une bonne pratique pour maintenir une séparation claire des responsabilités. Mais comment s’assurer que tout démarre dans le bon ordre ?

La problématique

Vous connaissez probablement ce scénario :

  • Vous démarrez votre Nginx Proxy Manager… mais attendez, il y a déjà des containers qui tournent
  • Vous arrêtez tout, redémarrez dans ce qui vous semble être le bon ordre
  • Une application plante parce que la base de données n’était pas prête
  • Vous recommencez…

Docker Compose propose bien l’option depends_on, mais elle présente deux limitations majeures :

  1. Elle ne fonctionne qu’au sein d’un même fichier docker-compose.yml
  2. Elle ne garantit pas que les services sont réellement « prêts », juste qu’ils ont démarré

Une solution pragmatique

Et si on pouvait simplement avoir un script qui :

  • Arrête proprement tous les containers en cours
  • Redémarre chaque projet dans un ordre précis
  • Attend le bon moment avant de passer au suivant
  • Gère aussi bien les services critiques que les applications secondaires

C’est exactement ce que nous allons mettre en place avec un script Bash simple mais efficace. L’idée est de définir deux catégories de containers :

  1. Les containers prioritaires (infrastructure critique)
  2. Les containers additionnels (applications métier)

Pourquoi cette approche ?

Cette solution présente plusieurs avantages :

  • Pas besoin de modifier vos docker-compose.yml existants
  • Contrôle total sur l’ordre de démarrage
  • Facilement adaptable à vos besoins
  • Idéal pour les environnements de développement
  • Fonctionne avec n’importe quelle structure de projets

Dans la suite de cet article, nous allons voir en détail comment implémenter cette solution, la personnaliser selon vos besoins, et l’utiliser efficacement dans votre workflow quotidien.

La mise en place du script

Notre script va s’articuler autour d’une structure simple mais efficace. Commençons par la base :

#!/bin/bash
# Description: Script pour arrêter et redémarrer les containers Docker dans un ordre spécifique

1. Configuration des priorités

La première étape consiste à définir nos containers par ordre de priorité. Nous utilisons deux tableaux pour une meilleure organisation :

# Définition des chemins de base des containers prioritaires
PRIORITY_CONTAINERS=(
    "/Users/samy/Sites/docker/containers/Nginx-Proxy-Manager"
    "/Users/samy/Sites/docker/containers/mariadb"
    "/Users/samy/Sites/docker/containers/www/apache_php8"
)

# Tableau pour les containers additionnels
ADDITIONAL_CONTAINERS=(
    "/Users/samy/Sites/docker/containers/laravel_test"
    "/Users/samy/Sites/Projects/blog"
    "/Users/samy/Sites/Projects/Laravel"
)

Pourquoi cette séparation ?

La distinction entre containers prioritaires et additionnels n’est pas qu’esthétique :

  • Les containers prioritaires sont généralement des services d’infrastructure
  • Ils doivent être pleinement opérationnels avant le démarrage des autres services
  • Cette séparation permet une maintenance plus claire
  • Facilite l’ajout ou la suppression de projets

Le choix des containers prioritaires est personnel et dépend entièrement de ton contexte. Dans mon cas, on a NPM, mariadb et apache. De ton côté, tu pourrais avoir un traefik, postgresql etc.

2. Les fonctions utilitaires

Nous avons besoin de deux fonctions principales :

# Fonction pour arrêter tous les containers
stop_all_containers() {
    echo "Arrêt de tous les containers Docker..."
    docker stop $(docker ps -q) 2>/dev/null
    docker rm $(docker ps -aq) 2>/dev/null
    sleep 2
}

# Fonction pour démarrer un container
start_container() {
    local container_path="$1"
    if [ -d "$container_path" ]; then
        echo "Démarrage du container dans: $container_path"
        cd "$container_path" && docker compose up -d
        # Attente pour s'assurer que le container est bien démarré
        sleep 5
    else
        echo "ERREUR: Le répertoire $container_path n'existe pas"
    fi
}

Zoom sur stop_all_containers()

  • docker stop $(docker ps -q) arrête tous les containers en cours d’exécution
  • docker rm $(docker ps -aq) supprime les containers arrêtés
  • La redirection 2>/dev/null évite les messages d’erreur si aucun container n’est présent
  • Le sleep 2 assure que tout est bien arrêté avant de continuer

Analyse de start_container()

  • Vérifie l’existence du répertoire avant toute action
  • Utilise cd pour se placer dans le bon contexte
  • Lance le container avec docker compose up -d
  • Le sleep 5 est crucial pour laisser le temps au container de démarrer

L’instruction sleep 5 permet d’introduire une pause de 5 secondes entre le démarrage des containers. Cette temporisation assure un démarrage séquentiel et stable de l’environnement. Dans mon cas, après plusieurs tests, 5 secondes se sont avérées suffisantes pour mes containers. Cependant, ce délai est à ajuster selon vos besoins et la complexité de vos services.

3. La fonction principale

Le cœur du script qui orchestre tout :

main() {
    # 1. Arrêt de tous les containers
    stop_all_containers

    # 2. Démarrage des containers prioritaires dans l'ordre
    echo "Démarrage des containers prioritaires..."
    for container in "${PRIORITY_CONTAINERS[@]}"; do
        start_container "$container"
    done

    # 3. Démarrage des containers additionnels
    if [ ${#ADDITIONAL_CONTAINERS[@]} -gt 0 ]; then
        echo "Démarrage des containers additionnels..."
        for container in "${ADDITIONAL_CONTAINERS[@]}"; do
            start_container "$container"
        done
    fi

    echo "Opération terminée!"
}

# Exécution du script
main

Points clés à noter

  1. Ordre d’exécution :
    • Arrêt propre de l’existant
    • Démarrage séquentiel des prioritaires
    • Puis démarrage des additionnels
  2. Gestion des erreurs :
    • Vérification de l’existence des répertoires
    • Redirection des erreurs pour les commandes sensibles
    • Messages clairs pour le suivi
  3. Temps d’attente :
    • Entre l’arrêt et le redémarrage
    • Après chaque démarrage de container
    • Ajustables selon vos besoins

Personnalisation et bonnes pratiques

1. Adapter le script à votre environnement

Le script peut être facilement personnalisé selon vos besoins. Voici les principaux points d’adaptation :

# Variables d'environnement personnalisables
BASE_PATH="/Users/samy/Sites/docker/containers"
WAIT_AFTER_STOP=2    # Temps d'attente après l'arrêt (en secondes)
WAIT_AFTER_START=5   # Temps d'attente après chaque démarrage

# Version améliorée des tableaux de containers
PRIORITY_CONTAINERS=(
    "${BASE_PATH}/Nginx-Proxy-Manager"    # Proxy - démarre en premier
    "${BASE_PATH}/mariadb"                # Base de données
    "${BASE_PATH}/www/apache_php8"        # Serveur web
)

Cette configuration part du principe que tous vos containers sont centralisés au même endroit. Si ce n’est pas le cas, vous devrez définir plusieurs variables source pour chaque emplacement. Dans mon cas par exemple, j’utilise deux répertoires distincts :

  • /Users/samy/Sites/docker/containers : dédié aux containers temporaires, de test, ou indépendants des projets
  • /Users/samy/Sites/projects : comme son nom l’indique, réservé aux containers liés aux projets en cours

2. Amélioration de la gestion des temps d’attente

Une version plus sophistiquée de la fonction start_container pourrait inclure des temps d’attente personnalisés :

start_container() {
    local container_path="$1"
    local wait_time="${2:-$WAIT_AFTER_START}"  # Utilise la valeur par défaut si non spécifiée
    
    if [ -d "$container_path" ]; then
        echo "🚀 Démarrage du container dans: $container_path"
        cd "$container_path" && docker compose up -d
        echo "⏳ Attente de $wait_time secondes pour stabilisation..."
        sleep $wait_time
        echo "✅ Démarrage terminé pour: $container_path"
    else
        echo "❌ ERREUR: Le répertoire $container_path n'existe pas"
        return 1
    fi
}

Ce ne sont que deux exemples d’améliorations possibles, mais les possibilités sont nombreuses. Voici quelques suggestions :

  • Implémenter un contrôle post-démarrage pour vérifier l’état des containers
docker ps | grep -q "$container_name"  # Retourne true/false selon l'état du container
  • Enrichir le système de logs pour plus de détails sur le démarrage
  • Et bien d’autres optimisations possibles comme :
    • Gestion des dépendances entre containers
    • Monitoring des ressources
    • Alertes en cas d’échec
    • Redémarrage automatique sur erreur

💡 L’objectif est d’automatiser au maximum pour un environnement plus robuste et facile à maintenir.

Bonnes pratiques d’utilisation

Placement du script

Concernant le placement du script, je le traite comme une commande système en le plaçant dans ~/.local/bin/. Cette approche présente plusieurs avantages :

  • Le script devient disponible globalement dans le système
  • Accessible depuis n’importe quel répertoire
chmod +x restart-containers.sh
mv restart-containers.sh ~/.local/bin/reloadDockerContainer

⚠️ Points importants à noter :

  • Le script doit être marqué comme exécutable (chmod +x)
  • L’utilisation de chemins absolus est cruciale (comme expliqué précédemment)
  • Le répertoire ~/.local/bin/ doit être dans votre $PATH

💡 Pro tip : Cette organisation permet de gérer le script comme une véritable commande système, facilitant son utilisation quotidienne

Alias utile

Pour simplifier encore plus l’utilisation, je recommande la création d’un alias. Cette approche offre deux avantages majeurs :

  1. Organisation plus claire :
    • Tu peux nommer ton script de façon explicite (ex: restart-containers.sh)
    • Distinction facile entre les commandes système et tes scripts personnels
  2. Utilisation simplifiée :
    • Commande courte et mémorisable
    • Accessible partout dans le système

Pour configurer l’alias, ajoute cette ligne dans ton ~/.bashrc ou ~/.zshrc :

alias rdocker='reloadDockerContainer'

🚀 TL;DR : Pour les Ninjas du Ctrl+C/Ctrl+V

Ah, je vous vois venir, vous les as du copier-coller, qui surfez sur Stack Overflow (Bon, OK, maintenant avec les LLM, c’est beaucoup moins utilisé) plus vite que votre ombre ! Vous savez, ceux qui lisent le dernier chapitre d’un livre policier en premier… 😏

#!/bin/bash
# Description: Script pour arrêter et redémarrer les containers Docker dans un ordre spécifique

# Définition des chemins de base des containers prioritaires
PRIORITY_CONTAINERS=(
    "/Users/samy/Sites/docker/containers/Nginx-Proxy-Manager"
    "/Users/samy/Sites/docker/containers/mariadb"
    "/Users/samy/Sites/docker/containers/www/apache_php8"
    # ICI les autres
)

# Tableau pour les containers additionnels (à remplir selon vos besoins)
ADDITIONAL_CONTAINERS=(
    "/Users/samy/Sites/docker/containers/laravel_test"
    "/Users/samy/Sites/projets/blog"
    # Ajoutez vos containers supplémentaires ici, exemple:
    # "/Users/samy/Sites/docker/containers/container1"
    # "/Users/samy/Sites/docker/containers/container2"
)

# Fonction pour arrêter tous les containers
stop_all_containers() {
    echo "Arrêt de tous les containers Docker..."
    docker stop $(docker ps -q) 2>/dev/null
    docker rm $(docker ps -aq) 2>/dev/null
    sleep 2
}

# Fonction pour démarrer un container
start_container() {
    local container_path="$1"
    if [ -d "$container_path" ]; then
        echo "Démarrage du container dans: $container_path"
        cd "$container_path" && docker compose up -d
        # Attente pour s'assurer que le container est bien démarré
        sleep 5
    else
        echo "ERREUR: Le répertoire $container_path n'existe pas"
    fi
}

# Fonction principale
main() {
    # 1. Arrêt de tous les containers
    stop_all_containers

    # 2. Démarrage des containers prioritaires dans l'ordre
    echo "Démarrage des containers prioritaires..."
    for container in "${PRIORITY_CONTAINERS[@]}"; do
        start_container "$container"
    done

    # 3. Démarrage des containers additionnels
    if [ ${#ADDITIONAL_CONTAINERS[@]} -gt 0 ]; then
        echo "Démarrage des containers additionnels..."
        for container in "${ADDITIONAL_CONTAINERS[@]}"; do
            start_container "$container"
        done
    fi

    echo "Opération terminée!"
}

# Exécution du script
main

Voilà, vous pouvez maintenant partir en courant avec ce code sous le bras, tel Indiana Jones s’échappant avec un artéfact précieux ! Mais n’oubliez pas : comprendre ce que vous copiez-collez, c’est comme lire les instructions IKEA avant de monter un meuble… Ça peut parfois éviter des surprises ! 🎪

PS : Si votre container crashe, on ne se connaît pas… ! Lisez l’article complet, il y a des trucs cool dedans, promis ! 🤓

Samy Kantari - Expert WordPress + IA

Kantari Samy

Expert WordPress + IA

👨‍💻 10 ans dans le game WordPress, chez Whodunit, à bricoler du code, à dompter des bugs et à faire tourner des projets de toutes tailles.
Puis l’IA est arrivée… et là, révélation 💡 !
J’ai switché de mindset, réinventé ma façon de coder et avec le vibe coding : une nouvelle ère où je ne suis plus limité par le temps ni par les outils.

Aujourd’hui ? Je code toujours… Mais avec mon copilote IA.
On forme une team de choc. Lui, c’est la puissance. Moi, c’est la vision. Ensemble, on déverrouille ce qui semblait impossible hier. 🚀

10+ Années d'expérience
+++ Projets réalisés
80% code par IA
S’abonner
Notification pour
guest
0 Commentaires
Commentaires en ligne
Afficher tous les commentaires