[Docker] Ajuster le délai de démarrage du conteneur entre les services dépendants [python]

À propos de cet article

Cet article est la ** partie 5 ** des articles relatifs à ** Apprenez à utiliser Docker via la construction d'environnement Django + MySQL ** Cela correspond à.

  1. Créer un environnement virtuel Python à l'aide de venv
  2. Examinez la description de Dockerfile
  3. Considérez la description de docker-compose.yml
  4. Modifiez le fichier de configuration et exécutez docker-compose up
  5. ** Ajustez le délai de démarrage du conteneur entre les services dépendants (cet article) **

introduction

Dans cet article, nous allons essayer de résoudre le problème de ** l'échec de connexion dû à l'ordre de démarrage ** qui peut se produire lors de l'exécution de plusieurs services dépendants à l'aide de docker-compose.

Dans les articles jusqu'à Dernière fois, nous définissons la construction de l'environnement de Django + MySQL en utilisant docker-compose. Une fois les paramètres de base terminés, lorsque j'essaye de démarrer le serveur Django avec $ docker-compose up, ** Même si le côté MySQL n'est pas prêt, Django essaie de se connecter à la DB, et la situation ne progresse pas avec une erreur de connexion **. Cela peut finir.

Pour le moment, c'est un problème qui ne survient qu'au moment de l'exécution initiale, et si vous attendez la préparation du côté MySQL, annulez-la manuellement une fois, et exécutez à nouveau $ docker-compose up, la connexion réussira, mais dans le futur Afin d'éviter le même problème et le même désagrément lors de la modification du processus de travail, ** réfléchissez à la possibilité d'incorporer des contre-mesures à l'avance **.

Détails de l'erreur

Si la connexion avec la base de données échoue, l'erreur suivante sera envoyée et le conteneur côté Django deviendra rigide.

# (Extrait)
djst_django | MySQLdb._exceptions.OperationalError: (2002, "Can't connect to MySQL server on 'db' (115)")
djst_django | django.db.utils.OperationalError: (2002, "Can't connect to MySQL server on 'db' (115)")

Cela semble être une erreur envoyée lors de la tentative de connexion à une base de données qui n'existe pas. En d'autres termes, dans ce cas, le problème est que la base de données n'est pas encore prête, alors réfléchissons à la possibilité d'ajuster l'ordre en attendant que cela puisse être fait par certains moyens.

Au fait, Docker recommande officiellement de résoudre avec le script shell, mais cette fois, le codage Python et la connexion mysqlclient Pour la pratique, je vais préparer un fichier Python dédié et essayer de le résoudre **.

Contenu du fichier

L'ensemble

Les fichiers suivants sont préparés dans le répertoire config.

config/wait_for_db.py


import os
import MySQLdb
from time import sleep
from pathlib import Path

os.chdir(Path(__file__).parent)
from local_settings import DB_NAME, DB_USER, DB_PASSWORD


count_to_try = 0
LIMIT_OF_COUNT = 20 #Ajustez la valeur au besoin


def check_connection(count, limit):
    """
    docker-Compose up Fonction pour le réglage de l'heure à l'exécution
    """
    try:
        conn = MySQLdb.connect(
            unix_socket = "/var/run/mysqld/mysqld.sock",
            user=DB_USER,
            passwd=DB_PASSWORD,
            host="db",
            port=3306,
            db=DB_NAME,
        )
    except MySQLdb._exceptions.OperationalError as e:
        count += 1
        print("Waiting for MySQL... (", count, "/ 20 )")
        sleep(3)
        if count < limit:
            check_connection(count, limit)
        else:
            print(e)
            print("Failed to connect mySQL.")
    else:
        print("Connected!\n")
        conn.close()
        exit()


if __name__ == "__main__":
    check_connection(count_to_try, LIMIT_OF_COUNT)

À propos de la description

Ensuite, j'écrirai sur le contenu du code.

Tout d'abord, installez les bibliothèques et packages requis.

config/wait_for_db.py


import os
import MySQLdb
from time import sleep
from pathlib import Path

os.chdir(Path(__file__).parent)
from local_settings import DB_NAME, DB_USER, DB_PASSWORD

Pour local_settings.py, déplacez le répertoire avec ʻos.chdir (Path (__ file__) .parent)` puis importez.

Ensuite, définissez les variables.

config/wait_for_db.py


count_to_try = 0
LIMIT_OF_COUNT = 20 #Ajustez la valeur au besoin

count_to_try sert à compter le nombre de fois où la fonction décrite plus loin est appelée, et LIMIT_OF_COUNT est la limite de nombre. Le branchement conditionnel est effectué dans la fonction de sorte que le fichier se termine après 20 répétitions. Ajustez cette valeur si nécessaire.

Pour le contenu de la fonction principale check_connection,

  1. Essayez de vous connecter à MySQL avec l'instruction try,
  2. En cas d'échec, comptez le nombre de tentatives de connexion avec l'instruction ʻexcept` et revenez à la même fonction.
  3. En cas de succès, mettez fin à la connexion avec l'instruction ʻelse` et fermez ce fichier Ce sera le flux.

config/wait_for_db.py


try:
    conn = MySQLdb.connect(
        unix_socket = "/var/run/mysqld/mysqld.sock",
        user=DB_USER,
        passwd=DB_PASSWORD,
        host="db",
        port=3306,
        db=DB_NAME,
    )

L'instruction try ʻunix_socket est la socket utilisée pour la connexion, mais elle est affichée dans le journal lorsque $ docker-compose upest exécuté, vous pouvez donc le copier. Le reste est le même que celui deDjango` la dernière fois. .

config/wait_for_db.py


except MySQLdb._exceptions.OperationalError as e:
    count += 1
    print("Waiting for MySQL... (", count, "/ 20 )")
    sleep(3)
    if count < limit:
        check_connection(count, limit)
    else:
        print(e)
        print("Failed to connect mySQL.")

Pour l'instruction ʻexcept`, le nombre d'essais est compté et sorti, puis il attend 3 secondes, et quand il atteint 20 fois, le contenu de l'erreur est sorti et le fichier est terminé. La limite supérieure est définie pour empêcher une boucle infinie en cas d'erreur de connexion réelle. .

config/wait_for_db.py


else:
    print("Connected!\n")
    conn.close()
    exit()

Lorsque la tentative de connexion réussit dans l'instruction try (=> ** lorsque MySQL est prêt **), déclarez la connexion réussie dans l'instruction ʻelse`, fermez la connexion, puis quittez le fichier. ..

Si vous pouvez passer l'instruction ʻelse, la prochaine commande runserver` devrait être exécutée sans délai. .

config/wait_for_db.py


if __name__ == "__main__":
    check_connection(count_to_try, LIMIT_OF_COUNT)

La dernière partie est ʻif name == "main": , c'est-à-dire **" lorsque ce fichier est exécuté directement "**, la fonction check_connection` est lue. L'argument est la variable définie au début.

Enfin, ajoutez une description dans la commande de docker-compose.yml pour que ce fichier soit exécuté avant que le serveur ne s'exécute.

docker-compose.yml


command: >
    bash -c "
        pip install -r requirements.txt &&
        python config/wait_for_db.py &&
        python manage.py runserver 0.0.0.0:8000
    "

Vous avez maintenant un programme ** qui attend l'exécution de la commande ** runserver pour configurer MySQL.

Quand j'exécute réellement $ docker-compose up ...

# (Extrait)
djst_django | Waiting for MySQL... ( 1 / 20 )
# (Omission...)
djst_mysql | Version: '5.7.31'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)
djst_django | Connected!
# (Omission...)
djst_django | Starting development server at http://0.0.0.0:8000/
djst_django | Quit the server with CONTROL-C.

Après avoir attendu, j'ai pu démarrer le serveur Django en toute sécurité après avoir confirmé la connexion. (Répétez de l'article précédent, en raison du réglage, le contrôle de fonctionnement réel n'est pas le http: //0.0.0.0: 8000 / affiché, mais ** http://172.0.0.1 Cela se fera depuis: 8000 / ʻou http: // localhost: 8000 / `**.)

À la fin

Avec ce qui précède, l'objectif initial de ** l'ajustement du délai de démarrage du conteneur entre les services dépendants ** a été atteint. Si vous avez des suggestions, je vous serais reconnaissant de bien vouloir commenter.

Cette fois, je l'ai écrit en python pour l'entraînement, mais j'aimerais contester le script shell afin qu'il puisse être utilisé librement.

(Vous pouvez revenir à la première page à partir d'ici ↓.) Apprenez à utiliser Docker via la construction d'environnement Django + MySQL

Merci pour votre visite.

Recommended Posts

[Docker] Ajuster le délai de démarrage du conteneur entre les services dépendants [python]
Ajuster les différences de police entre Qt pour Python OS
Placez Python3 dans le conteneur Docker d'Amazon Linux2
Utiliser python dans le conteneur Docker comme interpréteur Pycharm
Essayez le mode interactif Python dans un conteneur Docker