Python Docker Client无法正确执行MySQL命令,求助排查解决
Let's break down why your initialization script isn't running and fix it step by step:
1. Shell Redirection Isn't Being Processed (The Most Likely Culprit)
When you use exec_run() without specifying shell=True, Docker executes the command directly without passing it through a shell. That means the < redirection symbol isn't interpreted—it's just treated as a regular argument to the mysql command, which is why your script isn't being loaded.
Fixes:
Option 1: Enable shell execution to let the shell handle the redirection:
er = container.exec_run( 'mysql -h localhost < /data/init.sql', shell=True # This is the key addition )
Option 2: Avoid shell redirection entirely by using MySQL's built-in source command:
er = container.exec_run( ['mysql', '-h', 'localhost', '-e', 'source /data/init.sql'] )
2. MySQL Might Not Be Ready When You Run the Script
Docker containers start quickly, but MySQL needs a few seconds to initialize its data directory and start accepting connections. If you run exec_run() immediately after starting the container, the database might not be up yet.
Fix: Add a wait loop to check if MySQL is ready
import time def wait_for_mysql(container): while True: # Use mysqladmin to check if the server is responsive result = container.exec_run('mysqladmin ping -h localhost --silent') if result.exit_code == 0: print("MySQL is ready!") break print("Waiting for MySQL to start...") time.sleep(1) # Wait for MySQL to be ready before running the script wait_for_mysql(container) er = container.exec_run('mysql -h localhost < /data/init.sql', shell=True)
3. Better Alternative: Use MySQL Docker Image's Built-in Initialization
The official MySQL Docker image has a built-in feature that automatically runs scripts placed in /docker-entrypoint-initdb.d/ when the container starts for the first time. This is more reliable because the image handles waiting for MySQL to be ready before executing the scripts.
How to implement this:
Modify your volumes configuration to mount your init.sql directly into this directory:
volumes={ f"{path_to_current_dir}/init.sql": { 'bind': '/docker-entrypoint-initdb.d/init.sql', 'mode': 'ro' }, }
With this setup, you can remove the exec_run() call entirely—MySQL will run your script automatically during initialization.
内容的提问来源于stack exchange,提问作者Most Wanted

