"Can't connect to MySQL server on 'mysql' ([Errno 111] Connectio

ghz 8months ago ⋅ 51 views

I'm trying to run Docker + Flask + MySQL, and here is my docker-compose.yaml:

services:
  dockerflaskexample:
    image: dockerflaskexample
    build:
      context: .
      dockerfile: ./Dockerfile
    ports:
      - 5002:5002
    volumes:
      - app_code:/app
    depends_on:
      - mysql
    container_name: dockerflaskexample
  mysql:
    image: mysql:latest
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: webapp-db-root-password
      MYSQL_DATABASE: webapp-db
      MYSQL_USER: webapp-db-user
      MYSQL_PASSWORD: webapp-db-password
    volumes:
      - mysql_data:/var/lib/mysql
    ports:
      - "3306:3306"
volumes:
  mysql_data:
  app_code:

... and in __init__.py:

# Establishing a connection to the MySQL database
connection = pymysql.connect(
    host='mysql',
    database='webapp-db',
    user='webapp-db-user',
    password='webapp-db-password',
    port=3306,
    charset='utf8mb4',  # adjust charset if necessary
)

After I docker-compose up, the dockerflaskexample container always fails with the following error:

2024-04-02 16:25:05 pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on 'mysql' ([Errno 111] Connection refused)")

However, if I simply run the Exited (3) container again, it works.

May I know why this is so? Is it because mysql isn't ready when the webapp started?

Answers

Yes, you're correct. The issue you're experiencing is likely due to the fact that the Flask container starts up before the MySQL container has fully initialized and is ready to accept connections. This results in the Flask container attempting to connect to MySQL before MySQL is ready, leading to the "Connection refused" error.

To address this problem, you can implement a mechanism to wait for the MySQL container to be fully ready before starting the Flask application. One common approach is to use a tool like wait-for-it.sh or dockerize to wait for the MySQL container to be ready before starting the Flask application.

Here's how you can modify your Dockerfile and docker-compose.yaml to incorporate wait-for-it.sh:

  1. Download wait-for-it.sh: You can download wait-for-it.sh from GitHub. Here's the command to download it in your Dockerfile:
# Download wait-for-it.sh
ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh /usr/local/bin/wait-for-it.sh
RUN chmod +x /usr/local/bin/wait-for-it.sh
  1. Modify your entrypoint script: Create a shell script that waits for MySQL to be ready before starting your Flask application. Here's an example:
#!/bin/bash
# wait-for-mysql.sh

# Wait for MySQL to be ready
/wait-for-it.sh mysql:3306 -t 60

# Start the Flask application
python app.py

Make sure to grant execute permissions to this script (chmod +x wait-for-mysql.sh).

  1. Update your Dockerfile: Modify your Dockerfile to use the entrypoint script you created:
# Use the entrypoint script
ENTRYPOINT ["/wait-for-mysql.sh"]

With these modifications, your Flask container will wait for the MySQL container to be ready before attempting to establish a connection. This should prevent the "Connection refused" error during startup.