I am unable to connect to my MySQL database from Flask application.
I am learning to build web application with Python Flask from this tutorial but tried modifying some elements of it for experimenting with Docker. Even without using docker-compose, I was unable to connect to the database from the web application.
Let me first give the error traceback in the application log (flask_test container):
[2021-12-20 18:13:18 +0000] [1] [INFO] Starting gunicorn 20.1.0
[2021-12-20 18:13:18 +0000] [1] [INFO] Listening at: http://0.0.0.0:5000 (1)
[2021-12-20 18:13:18 +0000] [1] [INFO] Using worker: sync
[2021-12-20 18:13:18 +0000] [8] [INFO] Booting worker with pid: 8
[2021-12-20 18:13:19,105] INFO in __init__: Microblog startup
[2021-12-20 18:14:19,239] ERROR in app: Exception on /auth/register [POST]
Traceback (most recent call last):
File "/home/flasktest/venv/lib/python3.10/site-packages/urllib3/connection.py", line 174, in _new_conn
conn = connection.create_connection(
File "/home/flasktest/venv/lib/python3.10/site-packages/urllib3/util/connection.py", line 96, in create_connection
raise err
File "/home/flasktest/venv/lib/python3.10/site-packages/urllib3/util/connection.py", line 86, in create_connection
sock.connect(sa)
ConnectionRefusedError: [Errno 111] Connection refused
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/flasktest/venv/lib/python3.10/site-packages/elasticsearch/connection/http_urllib3.py", line 255, in perform_request
response = self.pool.urlopen(
File "/home/flasktest/venv/lib/python3.10/site-packages/urllib3/connectionpool.py", line 755, in urlopen
retries = retries.increment(
File "/home/flasktest/venv/lib/python3.10/site-packages/urllib3/util/retry.py", line 507, in increment
raise six.reraise(type(error), error, _stacktrace)
File "/home/flasktest/venv/lib/python3.10/site-packages/urllib3/packages/six.py", line 770, in reraise
raise value
File "/home/flasktest/venv/lib/python3.10/site-packages/urllib3/connectionpool.py", line 699, in urlopen
httplib_response = self._make_request(
File "/home/flasktest/venv/lib/python3.10/site-packages/urllib3/connectionpool.py", line 394, in _make_request
conn.request(method, url, **httplib_request_kw)
File "/home/flasktest/venv/lib/python3.10/site-packages/urllib3/connection.py", line 239, in request
super(HTTPConnection, self).request(method, url, body=body, headers=headers)
File "/usr/local/lib/python3.10/http/client.py", line 1282, in request
self._send_request(method, url, body, headers, encode_chunked)
File "/usr/local/lib/python3.10/http/client.py", line 1328, in _send_request
self.endheaders(body, encode_chunked=encode_chunked)
File "/usr/local/lib/python3.10/http/client.py", line 1277, in endheaders
self._send_output(message_body, encode_chunked=encode_chunked)
File "/usr/local/lib/python3.10/http/client.py", line 1037, in _send_output
self.send(msg)
File "/usr/local/lib/python3.10/http/client.py", line 975, in send
self.connect()
File "/home/flasktest/venv/lib/python3.10/site-packages/urllib3/connection.py", line 205, in connect
conn = self._new_conn()
File "/home/flasktest/venv/lib/python3.10/site-packages/urllib3/connection.py", line 186, in _new_conn
raise NewConnectionError(
urllib3.exceptions.NewConnectionError: <urllib3.connection.HTTPConnection object at 0x7f73470be7d0>: Failed to establish a new connection: [Errno 111] Connection refused
And this is the MySQL container (mysql_test) log:
2021-12-20T18:13:14.094155Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
2021-12-20T18:13:14.098891Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
2021-12-20T18:13:14.110089Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
2021-12-20T18:13:14.110149Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.27' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL.
mbind: Operation not permitted
mbind: Operation not permitted
2021-12-20 18:13:10+00:00 [Note] [Entrypoint]: Creating database test_db
2021-12-20 18:13:10+00:00 [Note] [Entrypoint]: Creating user test_user
2021-12-20 18:13:10+00:00 [Note] [Entrypoint]: Giving user test_user access to schema test_db
2021-12-20 18:13:10+00:00 [Note] [Entrypoint]: Stopping temporary server
2021-12-20 18:13:13+00:00 [Note] [Entrypoint]: Temporary server stopped
2021-12-20 18:13:13+00:00 [Note] [Entrypoint]: MySQL init process done. Ready for start up.
Here is the starting point of Python application (microblog.py):
from app_pkg import create_app, cli
app = create_app()
cli.register(app)
Here is the model class:
class User(UserMixin, SearchableMixin, db.Model):
__searchable__ = ['username']
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
posts = db.relationship('Post', backref='author', lazy='dynamic')
about_me = db.Column(db.String(140))
last_seen = db.Column(db.DateTime, default=datetime.utcnow)
followed = db.relationship(
'User', secondary=followers,
primaryjoin=(followers.c.follower_id == id),
secondaryjoin=(followers.c.followed_id == id),
backref=db.backref('followers', lazy='dynamic'), lazy='dynamic')
This is my compose.yaml:
version: '3'
services:
python_app:
container_name: flask_test
build: .
env_file: .env
ports:
- 8000:5000
links:
- mysqldb:dbserver
depends_on:
mysqldb:
condition: service_healthy
mysqldb:
container_name: mysql_test
image: mysql:latest
env_file: database.conf
volumes:
- db-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent"]
interval: 3s
retries: 5
start_period: 30s
volumes:
db-data:
This is my Dockerfile:
FROM python:slim
RUN useradd flasktest
WORKDIR /home/flasktest
COPY requirements.txt requirements.txt
RUN python -m venv venv
RUN venv/bin/pip install -r requirements.txt
RUN venv/bin/pip install gunicorn pymysql cryptography
COPY app_pkg app_pkg
COPY migrations migrations
COPY microblog.py config.py boot.sh ./
RUN chmod +x boot.sh
ENV FLASK_APP microblog.py
RUN chown -R flasktest:flasktest ./
USER flasktest
EXPOSE 5000
ENTRYPOINT ["./boot.sh"]
And finally, this is the boot.sh:
#!/bin/bash
source venv/bin/activate
while true; do
flask db upgrade
if [[ "$?" == "0" ]]; then
break
fi
echo Upgrade command failed, retrying in 5 secs...
sleep 5
done
exec gunicorn -b :5000 --access-logfile - --error-logfile - microblog:app
And these are some necessary environment variables that are being used in the application:
DATABASE_URL=mysql+pymysql://test_user:abc123#dbserver/test_db
MYSQL_ROOT_PASSWORD=root123
MYSQL_DATABASE=test_db
MYSQL_USER=test_user
MYSQL_PASSWORD=abc123
Sorry if the question has become too lengthy. I wanted to give as much detail as possible in the question. Let me know if any other details is required. I have been trying to debug this issue for the past week, but am unable to find a way to connect the app with the sql server.
Also let me know if I should try any specific method to try to debug this issue.
Edit:
create_app function:
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
from flask_mail import Mail
from flask_bootstrap import Bootstrap
from flask_moment import Moment
db = SQLAlchemy()
migrate = Migrate()
login = LoginManager()
login.login_view = 'auth.login'
login.login_message = _l('Please log in to access this page.')
mail = Mail()
bootstrap = Bootstrap()
moment = Moment()
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app)
migrate.init_app(app, db)
login.init_app(app)
mail.init_app(app)
bootstrap.init_app(app)
moment.init_app(app)
from app_pkg.errors import bp as errors_bp
app.register_blueprint(errors_bp)
from app_pkg.auth import bp as auth_bp
app.register_blueprint(auth_bp, url_prefix='/auth')
from app_pkg.main import bp as main_bp
app.register_blueprint(main_bp)
I tried changing DATABASE_URL from mysql+pymysql://test_user:abc123#dbserver/test_db to mysql+pymysql://test_user:abc123#mysqldb/test_db, but the issue still persists.
I also tried adding 'ports: -3306:3306' to compose.yaml and changing DATABASE_URL to 0.0.0.0 as host, but this is giving this error:
[+] Running 3/4
- Network flask_tutorial_default Created 0.7s
- Volume "flask_tutorial_db-data" Created 0.0s
- Container mysql_test Starting 2.4s
- Container flask_test Created 0.2s
Error response from daemon: Ports are not available: listen tcp 0.0.0.0:3306: bind: Only one usage of each socket address (protocol/network address/port) is normally permitted.
You are currently using the docker-compose dns feature in which you can use the container name as domain name for services running in docker-compose, thats neat - unless when you rename containers ;) Did you rename the mysqldb from dbserver?
If you want to continue using this feature, modify the env vars as so: (change dbserver to mysqldb)
DATABASE_URL=mysql+pymysql://test_user:abc123#mysqldb/test_db
...
If you instead what to use a more explicit approach:
In your docker-compose, you need to bind the port 3306 to your host network by
version: '3'
services:
python_app:
container_name: flask_test
build: .
env_file: .env
ports:
- 8000:5000
links:
- mysqldb:dbserver
depends_on:
mysqldb:
condition: service_healthy
mysqldb:
container_name: mysql_test
image: mysql:latest
env_file: database.conf
volumes:
- db-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent"]
interval: 3s
retries: 5
start_period: 30s
ports:
- 3306:3306
...
Then change the env var to:
DATABASE_URL=mysql+pymysql://test_user:abc123#0.0.0.0/test_db
Thanks for all the info, you did not post too much - needed it all :)
Related
My configuration is as follows:
I am running a Django-REST backend, with a MySQL database. I am trying to run the Django backend in its own Docker container, as well as running a MySQL database in its own Django container. It seems that Django is not able to connect to the MySQL database when my containers are running.
Database settings in Django:
DATABASES = {
"default": {
"ENGINE": os.environ.get("SQL_ENGINE", "django.db.backends.sqlite3"),
"NAME": os.environ.get("SQL_DATABASE", BASE_DIR / "db.sqlite3"),
"USER": os.environ.get("SQL_USER", "user"),
"PASSWORD": os.environ.get("SQL_PASSWORD", "password"),
"HOST": os.environ.get("SQL_HOST", "localhost"),
"PORT": os.environ.get("SQL_PORT", "5432"),
}
}
Dockerfile:
FROM python:3.10.2-slim-buster
ENV PYTHONUNBUFFERED 1
RUN mkdir /code
WORKDIR /code
RUN apt update \
&& apt install -y --no-install-recommends python3-dev \
default-libmysqlclient-dev build-essential default-mysql-client \
&& apt autoclean
RUN pip install --no-cache-dir --upgrade pip
COPY ./requirements.txt /code/
RUN pip install --no-cache-dir -r requirements.txt
COPY ./neura-dbms-backend /code/
EXPOSE 7000
Requirements.txt:
Django
djangorestframework
django-cors-headers
requests
boto3
django-storages
pytest
mysqlclient==2.1.1
django-use-email-as-username
djangorestframework-simplejwt
gunicorn
docker-compose.yml:
version: "3.8"
services:
neura-dbms-backend:
build:
context: ./DBMS/neura-dbms-backend
command: [sh, -c, "python manage.py runserver 0.0.0.0:7000"]
image: neura-dbms-backend
container_name: neura-dbms-backend
volumes:
- ./DBMS/neura-dbms-backend/neura-dbms-backend:/code
ports:
- 7000:7000
networks:
- docker-network
environment:
- DEBUG=1
- SECRET_KEY=${SECRET_KEY_DBMS}
- DJANGO_ALLOWED_HOSTS=${DJANGO_ALLOWED_HOSTS}
- DJANGO_ALLOWED_ORIGINS=${DJANGO_ALLOWED_ORIGINS}
- JWT_KEY=${JWT_KEY}
- SQL_ENGINE=django.db.backends.mysql
- SQL_DATABASE=db_neura_dbms
- SQL_USER=neura_dbms_user
- SQL_PASSWORD=super_secure_password
- SQL_HOST=db_neura_dbms
- SQL_PORT=5432
depends_on:
- "db_neura_dbms"
db_neura_dbms:
image: mysql:latest
volumes:
- mysql_data_db_neura_dbms:/var/lib/mysql/
environment:
- MYSQL_DATABASE=db_neura_dbms
- MYSQL_USER=neura_dbms_user
- MYSQL_PASSWORD=super_secure_password
- MYSQL_ROOT_PASSWORD=super_secure_password
networks:
- docker-network
networks:
docker-network:
driver: bridge
volumes:
mysql_data_db_neura_dbms:
I am able to build images for Django and the Database, but when I try to run the containers, I get the following error from the Django container:
neura-dbms-backend | System check identified no issues (0 silenced).
neura-dbms-backend | Exception in thread django-main-thread:
neura-dbms-backend | Traceback (most recent call last):
neura-dbms-backend | File "/usr/local/lib/python3.10/site-packages/django/db/backends/base/base.py", line 282, in ensure_connection
neura-dbms-backend | self.connect()
neura-dbms-backend | File "/usr/local/lib/python3.10/site-packages/django/utils/asyncio.py", line 26, in inner
neura-dbms-backend | return func(*args, **kwargs)
neura-dbms-backend | File "/usr/local/lib/python3.10/site-packages/django/db/backends/base/base.py", line 263, in connect
neura-dbms-backend | self.connection = self.get_new_connection(conn_params)
neura-dbms-backend | File "/usr/local/lib/python3.10/site-packages/django/utils/asyncio.py", line 26, in inner
neura-dbms-backend | return func(*args, **kwargs)
neura-dbms-backend | File "/usr/local/lib/python3.10/site-packages/django/db/backends/mysql/base.py", line 247, in get_new_connection
neura-dbms-backend | connection = Database.connect(**conn_params)
neura-dbms-backend | File "/usr/local/lib/python3.10/site-packages/MySQLdb/__init__.py", line 123, in Connect
neura-dbms-backend | return Connection(*args, **kwargs)
neura-dbms-backend | File "/usr/local/lib/python3.10/site-packages/MySQLdb/connections.py", line 185, in __init__
neura-dbms-backend | super().__init__(*args, **kwargs2)
neura-dbms-backend | MySQLdb.OperationalError: (2002, "Can't connect to MySQL server on 'db_neura_dbms' (115)")
What am I missing? Thanks!
So I added a script so that Django waits for the mysql database to be ready before it connects:
#!/bin/bash
if [ "$SQL_HOST" = "db" ]
then
echo "Waiting for mysql..."
while !</dev/tcp/$SQL_HOST/$SQL_PORT; do sleep 1; done;
echo "MySQL started"
fi
# python manage.py migrate
exec "$#"
When I first run the Docker containers, it seems that MySQL runs through some sort of setup, Django then tries to connect and fails.
If I then kill the containers, and run them again, the MySQL setup is finished, and Django is able to connect to the database. I wonder if there is a way for Django to wait for this setup to be finished as well?
depends_on only waits till the database container is started, but in this case, after the container is started it still takes some time for mysql to make the system ready for connection.
what you can do is create a command file (This is for postgres, you can make one for yours, you will need to add raised mysql exception instead of Psycopg2Error )
import time
from psycopg2 import OperationalError as Psycopg2Error
from django.db.utils import OperationalError
from django.core.management.base import BaseCommand
class Command(BaseCommand):
"""
Django command to wait for database
"""
def handle(self, *args, **options):
"""
Command entrypoint
"""
self.stdout.write("Checking database availability\n")
db_up = False
seconds_cnt = 0
while not db_up:
try:
self.check(databases=['default'])
db_up = True
self.stdout.write(
self.style.WARNING(
"Available within {} seconds".format(seconds_cnt)))
self.stdout.write(self.style.SUCCESS("Database available!"))
except(Psycopg2Error, OperationalError):
seconds_cnt += 1
self.stdout.write(
self.style.WARNING(
"Database unavailable waiting... {} seconds"
.format(seconds_cnt)))
time.sleep(1)
Your command can be updated with,
command: >
sh -c "python manage.py wait_for_db &&
python manage.py runserver 0.0.0.0:87000"
I am trying to connect to MySQL database using Docker Compose and I get the following error
Traceback (most recent call last):
| File "/usr/local/lib/python3.9/site-packages/mysql/connector/connection_cext.py", line 268, in _open_connection
| self._cmysql.connect(**cnx_kwargs)
| _mysql_connector.MySQLInterfaceError: Can't connect to MySQL server on '172.22.0.2:3306' (110)
|
| The above exception was the direct cause of the following exception:
| Traceback (most recent call last):
| File "//script.py", line 19, in <module>
| cnx = mysql.connector.connect(host='172.22.0.2', user='user', password='pass', database='db', port=3306)
| File "/usr/local/lib/python3.9/site-packages/mysql/connector/pooling.py", line 286, in connect
| return CMySQLConnection(*args, **kwargs)
| File "/usr/local/lib/python3.9/site-packages/mysql/connector/connection_cext.py", line 101, in __init__
| self.connect(**kwargs)
| File "/usr/local/lib/python3.9/site-packages/mysql/connector/abstracts.py", line 1108, in connect
| self._open_connection()
| File "/usr/local/lib/python3.9/site-packages/mysql/connector/connection_cext.py", line 273, in _open_connection..
| raise get_mysql_exception(mysql.connector.errors.DatabaseError: 2003 (HY000): Can't connect to MySQL server on '172.22.0.2:3306'
In my programm I have to containers: for python script and for MySQL database. Both containers are built successfully and db container starts just fine.
172.22.0.2 stands for ip address in network I've created (see docker-compose).
My python script simply connects to the database using mysql-connector.
The code is the following
Dockerfile for script
FROM python:3.9
COPY script.py script.py
RUN pip install mysql-connector-python
script.py
import mysql.connector
cnx = mysql.connector.connect(host='172.22.0.2', user='user', password='pass', database='db', port=3306)
docker-compose.yaml
version: "3"
services:
db:
image: mysql
container_name: db
command: '--init-file /data/app/init.sql'
ports:
- "3306:3306"
volumes:
- "./init.sql:/data/app/init.sql"
environment:
MYSQL_DATABASE: "db"
MYSQL_USER: "user"
MYSQL_PASSWORD: "pass"
MYSQL_ROOT_PASSWORD: "pass"
networks:
net:
ipv4_address: 172.22.0.2
script:
build:
context: ./
dockerfile: Dockerfile
depends_on:
- db
links:
- db
container_name: script
command: sh -c "sleep 10s ; python script.py"
networks:
net:
ipv4_address: 172.22.0.3
networks:
net:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.22.0.0/24
gateway: 172.22.0.1
init.sql
CREATE DATABASE IF NOT EXIST db;
USE db;
I installed airflow in local, using MySQL, celery executor, and rabbitmq
now I install airflow in the docker to set up Airflow HA Scheduler with YAML file:
version: '3'
x-airflow-common:
&airflow-common
image: ${AIRFLOW_IMAGE_NAME:-apache/airflow:2.3.4}
environment:
&airflow-common-env
AIRFLOW__CORE__EXECUTOR: CeleryExecutor
# AIRFLOW__DATABASE__SQL_ALCHEMY_CONN: postgresql+psycopg2://airflow:airflow#postgres/airflow
# AIRFLOW__CORE__SQL_ALCHEMY_CONN: postgresql+psycopg2://airflow:airflow#postgres/airflow
# AIRFLOW__CELERY__RESULT_BACKEND: db+postgresql://airflow:airflow#postgres/airflow
# AIRFLOW__CELERY__BROKER_URL: redis://:#redis:6379/0
# AIRFLOW__CORE__FERNET_KEY: ''
# AIRFLOW__CORE__DAGS_ARE_PAUSED_AT_CREATION: 'true'
# AIRFLOW__CORE__LOAD_EXAMPLES: 'true'
# AIRFLOW__API__AUTH_BACKENDS: 'airflow.api.auth.backend.basic_auth'
# _PIP_ADDITIONAL_REQUIREMENTS: ${_PIP_ADDITIONAL_REQUIREMENTS:-}
AIRFLOW__DATABASE__SQL_ALCHEMY_CONN: mysql://airflow:password#localhost/airflow
AIRFLOW__CORE__SQL_ALCHEMY_CONN: mysql://airflow:password#localhost/airflow
AIRFLOW__CELERY__RESULT_BACKEND: db+mysql://airflow:password#localhost:3306/airflow
AIRFLOW__CELERY__BROKER_URL: pyamqp://airflow:password#localhost:5672/myvhost
AIRFLOW__CORE__FERNET_KEY: 'LgPLCqY0vrVDAI7s7eR408ZfRNm_CekdALmA1CJtYgs='
AIRFLOW__CORE__DAGS_ARE_PAUSED_AT_CREATION: 'true'
AIRFLOW__CORE__LOAD_EXAMPLES: 'false'
AIRFLOW__API__AUTH_BACKENDS: 'airflow.api.auth.backend.basic_auth'
_PIP_ADDITIONAL_REQUIREMENTS: ${_PIP_ADDITIONAL_REQUIREMENTS:-}
volumes:
- ./dags:/opt/airflow/dags
- ./logs:/opt/airflow/logs
- ./plugins:/opt/airflow/plugins
user: "${AIRFLOW_UID:-50000}:0"
depends_on:
&airflow-common-depends-on
rabbitmq:
condition: service_healthy
mysql:
condition: service_healthy
services:
# postgres:
# image: postgres:13
# environment:
# POSTGRES_USER: airflow
# POSTGRES_PASSWORD: airflow
# POSTGRES_DB: airflow
# volumes:
# - postgres-db-volume:/var/lib/postgresql/data
# healthcheck:
# test: ["CMD", "pg_isready", "-U", "airflow"]
# interval: 5s
# retries: 5
# restart: always
mysql:
image: mysql:5.7
environment:
MYSQL_DATABASE: airflowdb
MYSQL_USER: airflow
MYSQL_PASSWORD: password
MYSQL_ROOT_PASSWORD: password
volumes:
- mysql-db-volume:/var/lib/mysql/airflowdb
healthcheck:
test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"]
interval: 5s
retries: 5
ports:
- '3306:3306'
restart: always
# redis:
# image: redis:latest
# expose:
# - 6379
# healthcheck:
# test: ["CMD", "redis-cli", "ping"]
# interval: 5s
# timeout: 30s
# retries: 50
# restart: always
rabbitmq:
image: rabbitmq:3.9
container_name: rabbitmq
ports:
- 5672:5672
- 15672:15672
volumes:
- ~/.docker-conf/rabbitmq/data/:/var/lib/rabbitmq/
- ~/.docker-conf/rabbitmq/log/:/var/log/rabbitmq
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:15672"]
interval: 30s
timeout: 10s
retries: 5
networks:
- rabbitmq_go_net
volumes:
# postgres-db-volume:
mysql-db-volume:
To deploy Airflow on Docker Compose, I fetch file from airflow docker-compose then edit environment to the same airflow.config (sql_alchemy, reesult_backend, broker) and mysql, rabbitmq instead of postgres, redis.
when I run docker-compose up airflow-init get error
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/docker/api/client.py", line 268, in _raise_for_status
response.raise_for_status()
File "/home/linhnq/.local/lib/python3.10/site-packages/requests/models.py", line 1022, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 502 Server Error: Bad Gateway for url: http+docker://localhost/version
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/docker/api/client.py", line 214, in _retrieve_server_version
return self.version(api_version=False)["ApiVersion"]
File "/usr/lib/python3/dist-packages/docker/api/daemon.py", line 181, in version
return self._result(self._get(url), json=True)
File "/usr/lib/python3/dist-packages/docker/api/client.py", line 274, in _result
self._raise_for_status(response)
File "/usr/lib/python3/dist-packages/docker/api/client.py", line 270, in _raise_for_status
raise create_api_error_from_http_exception(e)
File "/usr/lib/python3/dist-packages/docker/errors.py", line 31, in create_api_error_from_http_exception
raise cls(e, response=response, explanation=explanation)
docker.errors.APIError: 502 Server Error for http+docker://localhost/version: Bad Gateway ("b'Bad response from Docker engine'")
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/bin/docker-compose", line 33, in <module>
sys.exit(load_entry_point('docker-compose==1.29.2', 'console_scripts', 'docker-compose')())
File "/usr/lib/python3/dist-packages/compose/cli/main.py", line 81, in main
command_func()
File "/usr/lib/python3/dist-packages/compose/cli/main.py", line 200, in perform_command
project = project_from_options('.', options)
File "/usr/lib/python3/dist-packages/compose/cli/command.py", line 60, in project_from_options
return get_project(
File "/usr/lib/python3/dist-packages/compose/cli/command.py", line 152, in get_project
client = get_client(
File "/usr/lib/python3/dist-packages/compose/cli/docker_client.py", line 41, in get_client
client = docker_client(
File "/usr/lib/python3/dist-packages/compose/cli/docker_client.py", line 170, in docker_client
client = APIClient(use_ssh_client=not use_paramiko_ssh, **kwargs)
File "/usr/lib/python3/dist-packages/docker/api/client.py", line 197, in __init__
self._version = self._retrieve_server_version()
File "/usr/lib/python3/dist-packages/docker/api/client.py", line 221, in _retrieve_server_version
raise DockerException(
docker.errors.DockerException: Error while fetching server API version: 502 Server Error for http+docker://localhost/version: Bad Gateway ("b'Bad response from Docker engine'")
how can I fix this error?
thanks,`
I am using Docker for the container service.
I have created a seed file and run it by npx sequelize-cli db:seed:all, then error occur:
Sequelize CLI [Node: 13.12.0, CLI: 6.2.0, ORM: 6.5.1]
Loaded configuration file "migrations/config.js".
Using environment "development".
events.js:292
throw er; // Unhandled 'error' event
^
Error: Redis connection to my-redis:6379 failed - getaddrinfo ENOTFOUND my-redis
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:66:26)
Emitted 'error' event on RedisClient instance at:
at RedisClient.on_error (/Users/CCCC/Desktop/Source Tree/my-server/node_modules/redis/index.js:342:14)
at Socket.<anonymous> (/Users/CCCC/Desktop/Source Tree/my-server/node_modules/redis/index.js:223:14)
at Socket.emit (events.js:315:20)
at Socket.EventEmitter.emit (domain.js:485:12)
at emitErrorNT (internal/streams/destroy.js:84:8)
at processTicksAndRejections (internal/process/task_queues.js:84:21) {
errno: -3008,
code: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'my-redis'
}
It seems to show that my redis is not found/not running in port 6379.
Then I run docker ps, it shows my-redis run in port 6379.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
...
f637ee218d03 redis:6 "docker-entrypoint.s…" 18 minutes ago Up 18 minutes 0.0.0.0:6379->6379/tcp my-server_my-redis_1
docker-compose.yml
version: '2.1'
services:
my-db:
image: mysql:5.7
...
ports:
- 3306:3306
my-redis:
image: redis:6
ports:
- 6379:6379
my-web:
restart: always
environment:
- NODE_ENV=dev
- PORT=3030
build: .
command: >
sh -c "npm install && ./wait-for-db-redis.sh my-db my-redis npm run dev"
ports:
- "3030:3030"
volumes:
- ./:/server
depends_on:
- my-db
- my-redis
.sequelizerc
const path = require('path');
module.exports = {
'config': path.resolve('migrations/config.js'),
'seeders-path': path.resolve('migrations/seeders'),
'models-path': path.resolve('migrations/models.js')
};
migrations/model.js
const Sequelize = require('sequelize');
const app = require('../src/app');
const sequelize = app.get('sequelizeClient');
const models = sequelize.models;
module.exports = Object.assign({
Sequelize,
sequelize
}, models);
config.js
const app = require('../src/app');
const env = process.env.NODE_ENV || 'development';
const dialect = 'mysql';
module.exports = {
[env]: {
dialect,
url: app.get(dialect),
migrationStorageTableName: '_migrations'
}
};
Are you running the migration within the Docker Compose container for your app, or on the Docker host machine?
From the host machine's point of view, there is no such hostname as my-redis (it's only a thing within a Docker overlay network with that container in it).
Since you've exposed the Redis port 6379 to your host (and in fact the whole wide world), you'd use localhost:6379 on the host machine.
I'm very new for docker, now I am trying to run django with mariadb in docker through docker-compose, but I always get this error:
I use Docker version 17.09.1-ce, build 19e2cf6, docker-compose version 1.18.0, build 8dd22a9
django.db.utils.OperationalError: (2003, 'Can\'t connect to MySQL
server on \'mariadb55\' (111 "Connection refused")')
I can connect db correctly after run docker-compose up db in local or remote, and I even can run python manage.py runserver 0.0.0.0:6001 correctly in anaconda virtual environment to connect db service in docker by setting parameters of settings.py file like below:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test',
'USER': 'belter',
# 'HOST': 'mariadb55',
'HOST': '127.0.0.1',
'PORT': '3302',
'PASSWORD': 'belter_2017',
'default-character-set': 'utf8',
'OPTIONS': {
'sql_mode': 'traditional',
}
}
}
This is my docker-compose.yml file
version: '3'
services:
db:
image: mariadb:5.5
restart: always
environment:
- MYSQL_HOST=localhost
- MYSQL_PORT=3306
- MYSQL_ROOT_HOST=%
- MYSQL_DATABASE=test
- MYSQL_USER=belter
- MYSQL_PASSWORD=belter_2017
- MYSQL_ROOT_PASSWORD=123456_abc
volumes:
- /home/belter/mdbdata/mdb55:/var/lib/mysql
ports:
- "3302:3306"
web:
image: onlybelter/django_py35
command: python3 manage.py runserver 0.0.0.0:6001
volumes:
- /mnt/data/www/mysite:/djcode
ports:
- "6001:6001"
depends_on:
- db
links:
- db:mariadb55
I almost tried everything I can find, but still cannot figure it out, any help would be nice!
What I have tried:
Docker compose mysql connection failing
Linking django and mysql containers using docker-compose
Django connection to postgres by docker-compose
Finally, I figured it out!
The key point is, just as #SangminKim said, I need to use 3306 not 3302 in settings.py, and use db as HOST not 127.0.0.1.
So this is my docker-compose.yml file now:
version: '3'
services:
db:
image: mariadb:5.5
restart: always
environment:
- MYSQL_HOST=localhost
- MYSQL_PORT=3306 # cannot change this port to other number
- MYSQL_ROOT_HOST=%
- MYSQL_DATABASE=test
- MYSQL_USER=belter
- MYSQL_PASSWORD=belter_2017
- MYSQL_ROOT_PASSWORD=123456_abc
volumes:
- /home/belter/mdbdata/mdb55:/var/lib/mysql
ports:
- "3302:3306"
web:
image: onlybelter/django_py35
command: python3 manage.py runserver 0.0.0.0:6001
volumes:
- .:/djcode
ports:
- "6001:6001"
depends_on:
- db
So now we can connect this docker-mysql by mysql -h 127.0.0.1 -P 3302 -u root -p in shell directly, but we have to use db and 3306 in django settings.py file:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'test',
'USER': 'belter',
# 'HOST': 'mariadb55',
'HOST': 'db', #<---
'PORT': '3306', #<---
'PASSWORD': 'belter_2017',
'default-character-set': 'utf8',
'OPTIONS': {
'sql_mode': 'traditional',
}
}
}
And we can still check if this port is open, by running extra command in docker-compose.yml file:
...
web:
image: onlybelter/django_py35
command: /bin/sh -c "python check_db.py --service-name mysql --ip db --port 3306"
volumes:
- .:/djcode
...
Here is check_db.py file:
# check_db.py
import socket
import time
import argparse
""" Check if port is open, avoid docker-compose race condition """
parser = argparse.ArgumentParser(description='Check if port is open, avoid\
docker-compose race condition')
parser.add_argument('--service-name', required=True)
parser.add_argument('--ip', required=True)
parser.add_argument('--port', required=True)
args = parser.parse_args()
# Get arguments
service_name = str(args.service_name)
port = int(args.port)
ip = str(args.ip)
# Infinite loop
while True:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex((ip, port))
if result == 0:
print("{0} port is open! Bye!".format(service_name))
break
else:
print("{0} port is not open! I'll check it soon!".format(service_name))
time.sleep(3)
By the way, this is my Dockerfile for build django-py35:
FROM python:3.5-alpine
MAINTAINER Xin Xiong "xiongxin20008#126.com"
ENV PYTHONUNBUFFERED 1
RUN set -e; \
apk add --no-cache --virtual .build-deps \
gcc \
libc-dev \
linux-headers \
mariadb-dev \
python3-dev \
postgresql-dev \
freetype-dev \
libpng-dev \
g++ \
;
RUN mkdir /djcode
WORKDIR /djcode
ENV REFRESHED_AT 2017-12-25
ADD requirements.txt /djcode/
RUN pip install --no-cache-dir -r /djcode/requirements.txt
RUN pip install uwsgi
ADD . /djcode/ # copy . to /djcode/
EXPOSE 6001
See more details from here: https://github.com/OnlyBelter/django-compose
You should use the container name instead of localhost (or 127.0.0.1) in your settings.py file. Try providing a container name to the db service in the docker-compose.yml file using container_name attribute and replace the host name in the settings.py by the value of the container_name. (Make sure that they are in the same network that docker compose creates for you.)
Build container with this:
docker run --name mysql-latest \
-p 3306:3306 -p 33060:33060 \
-e MYSQL_ROOT_HOST='%' -e MYSQL_ROOT_PASSWORD='strongpassword' \
-d mysql/mysql-server:latest
Make sure MYSQL_ROOT_HOST='%', that means root can connect from any IP.