I want to use docker compose to connect a node program, in one container, to a MySQL database, in another container. The database seems to start fine, but my index.js file throws an error: Cannot find module 'mysql2/promise'
I've tried installing different packages with npm, and even edited various lines in my package.json file in desperation, but to no avail; always the same error. Here are the relevant files, and the output of the commands that work so far.
$ npm install mysql2
npm WARN simplyanything#1.0.0 No repository field.
npm WARN simplyanything#1.0.0 No license field.
+ mysql2#2.3.3
updated 1 package and audited 101 packages in 3.302s
found 0 vulnerabilities
$ sudo npm install mysql2-promise
+ mysql2-promise#0.1.4
updated 1 package and audited 101 packages in 3.772s
found 0 vulnerabilities
package.json
{
"name": "simplyanything",
"version": "1.0.0",
"scripts": {
"start": "node index.js"
},
"description": "Actions party game",
"dependencies": {
"express": "^4.17.1",
"mysql2": "^2.3.3",
"mysql2-promise": "^0.1.4",
"socket.io": "^4.4.1"
},
"author": "Chris DeHaan"
}
index.js
const express = require('express');
let app = express();
let http = require('http').createServer(app);
const io = require('socket.io')(http, {pingTimeout: 60000});
app.use(express.static('public'));
app.get('/', (req, res) => { res.sendFile(__dirname + '/index.html'); });
http.listen(3000, () => { console.log('listening on *:3000'); });
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
connectionLimit : 100,
host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
[.... and so on]
Dockerfile
FROM node:latest
WORKDIR /sa/
COPY package.json .
RUN npm install
COPY . .
docker-compose.yml
version: '3.8'
services:
web:
build:
context: .
env_file: ./.env
command: npm start
volumes:
- .:/sa/
- /sa/node_modules
ports:
- $NODE_LOCAL_PORT:$NODE_DOCKER_PORT
depends_on:
- mysqldb
environment:
MYSQL_HOST: mysqldb
mysqldb:
image: mysql
env_file: ./.env
environment:
MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
MYSQL_DATABASE: $MYSQL_DATABASE
ports:
- $MYSQL_LOCAL_PORT:$MYSQL_DOCKER_PORT
volumes:
- mysql:/var/lib/mysql
- mysql_config:/etc/mysql
volumes:
mysql:
mysql_config:
.env
MYSQL_USER=simplyanythingUser
MYSQL_ROOT_PASSWORD=[Well, you don't need to know this]
MYSQL_DATABASE=simplyanything
MYSQL_LOCAL_PORT=3306
MYSQL_DOCKER_PORT=3306
NODE_LOCAL_PORT=3000
NODE_DOCKER_PORT=3000
$ sudo docker build -t sa .
Sending build context to Docker daemon 9.526MB
Step 1/5 : FROM node:latest
---> e6bed6a65a54
Step 2/5 : WORKDIR /sa/
---> Using cache
---> 3da61e5a5928
Step 3/5 : COPY package.json .
---> Using cache
---> 1e7bbeaaa894
Step 4/5 : RUN npm install
---> Using cache
---> 52f36e54d698
Step 5/5 : COPY . .
---> e0a50567567b
Successfully built e0a50567567b
Successfully tagged sa:latest
$ node index.js
Debugger listening on ws://127.0.0.1:44273/a1b49bfc-83e7-47dd-ba53-64a8df19ccc9
For help, see: https://nodejs.org/en/docs/inspector
Debugger attached.
listening on *:3000
(and it works in the browser at this point)
$ sudo docker-compose up
Starting sa_mysqldb_1 ... done
Starting sa_web_1 ... done
Attaching to sa_mysqldb_1, sa_web_1
mysqldb_1 | 2022-02-08 08:31:21+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.28-1debian10 started.
mysqldb_1 | 2022-02-08 08:31:21+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
mysqldb_1 | 2022-02-08 08:31:21+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.28-1debian10 started.
mysqldb_1 | 2022-02-08T08:31:21.660916Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.28) starting as process 1
mysqldb_1 | 2022-02-08T08:31:21.747461Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
web_1 |
web_1 | > simplyanything#1.0.0 start
web_1 | > node index.js
web_1 |
mysqldb_1 | 2022-02-08T08:31:23.587278Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
web_1 | node:internal/modules/cjs/loader:936
web_1 | throw err;
web_1 | ^
web_1 |
web_1 | Error: Cannot find module 'mysql2/promise'
web_1 | Require stack:
web_1 | - /sa/index.js
web_1 | at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
web_1 | at Function.Module._load (node:internal/modules/cjs/loader:778:27)
web_1 | at Module.require (node:internal/modules/cjs/loader:999:19)
web_1 | at require (node:internal/modules/cjs/helpers:102:18)
web_1 | at Object.<anonymous> (/sa/index.js:13:15)
web_1 | at Module._compile (node:internal/modules/cjs/loader:1097:14)
web_1 | at Object.Module._extensions..js (node:internal/modules/cjs/loader:1149:10)
web_1 | at Module.load (node:internal/modules/cjs/loader:975:32)
web_1 | at Function.Module._load (node:internal/modules/cjs/loader:822:12)
web_1 | at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12) {
web_1 | code: 'MODULE_NOT_FOUND',
web_1 | requireStack: [ '/sa/index.js' ]
web_1 | }
web_1 |
web_1 | Node.js v17.4.0
mysqldb_1 | 2022-02-08T08:31:25.086275Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
mysqldb_1 | 2022-02-08T08:31:25.086445Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
mysqldb_1 | 2022-02-08T08:31:25.277625Z 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.
mysqldb_1 | 2022-02-08T08:31:25.354311Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
mysqldb_1 | 2022-02-08T08:31:25.355558Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.28' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL.
I'm really stuck because everything it needs seems to be installed, and it works when I run it on the command line with node index.js so obviously there's something I'm missing in setting up my container, or getting compose to connect them. Any advice would be much appreciated. Cheers.
Good afternoon, I had the same problem. You could try to use
npm install mysql2
Related
I tried many ways and every time the application runs in the container I get such errors:
WARN 1 --- [ main] o.h.e.j.e.i.JdbcEnvironmentInitiator : HHH000342: Could not obtain connection to query metadata
java.lang.IllegalStateException: Cannot get a connection as the driver manager is not properly initialized
my docker-compose:
version: '3.8'
networks:
my_network:
external: true
services:
mysql:
container_name: configs_mysql
image: mysql:latest
restart: always
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: scrap
MYSQL_USER: scrap
MYSQL_PASSWORD: scrap
MYSQL_DATABASE: configs
networks:
- my_network
web:
build: .
image: scrapyconfigmanager_web
ports:
- "8181:8181"
networks:
- my_network
depends_on:
- mysql
my Dockerfile:
FROM openjdk:11
# Copy source code to temporary building location
WORKDIR /source_code
COPY . .
RUN ./gradlew bootJar
WORKDIR /scrapy
RUN cp /source_code/build/libs/ScrapyConfigManager-1.0.jar .
EXPOSE 8181
ENTRYPOINT ["java","-jar","ScrapyConfigManager-1.0.jar"]
my hibernate.cfg:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://configs_mysql:3306/configs</property>
<property name="hibernate.connection.username">scrap</property>
<property name="hibernate.connection.password">scrap</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
<mapping class="org.scrapeusz.model.OlxCar" />
</session-factory>
</hibernate-configuration>
Both containers start up, but after a while the spring container stops.
Below I paste part of the code from the terminal after the "docker-compose up" command:
Creating configs_mysql ... done
Creating scrapyconfigmanager_web_1 ... done
Attaching to configs_mysql, scrapyconfigmanager_web_1
configs_mysql | 2022-07-21 10:34:49+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.29-1.el8 started.
configs_mysql | 2022-07-21 10:34:49+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
configs_mysql | 2022-07-21 10:34:49+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.29-1.el8 started.
configs_mysql | 2022-07-21 10:34:49+00:00 [Note] [Entrypoint]: Initializing database files
configs_mysql | 2022-07-21T10:34:49.504138Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 8.0.29) initializing of server in progress as process 42
configs_mysql | 2022-07-21T10:34:49.515175Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
configs_mysql | 2022-07-21T10:34:49.795876Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
web_1 |
web_1 | . ____ _ __ _ _
web_1 | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
web_1 | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
web_1 | \\/ ___)| |_)| | | | | || (_| | ) ) ) )
web_1 | ' |____| .__|_| |_|_| |_\__, | / / / /
web_1 | =========|_|==============|___/=/_/_/_/
web_1 | :: Spring Boot :: (v2.6.6)
web_1 |
web_1 | 2022-07-21 10:34:50.905 INFO 1 --- [ main] org.scrapeusz.ScrapyConfigManager : Starting ScrapyConfigManager using Java 11.0.15 on 71d7d66bbd3b with PID 1 (/scrapy/ScrapyConfigManager-1.0.jar started by root in /scrapy)
web_1 | 2022-07-21 10:34:50.910 INFO 1 --- [ main] org.scrapeusz.ScrapyConfigManager : No active profile set, falling back to 1 default profile: "default"
configs_mysql | 2022-07-21T10:34:51.393524Z 6 [Warning] [MY-010453] [Server] root#localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
web_1 | 2022-07-21 10:34:52.239 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
web_1 | 2022-07-21 10:34:52.255 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
web_1 | 2022-07-21 10:34:52.255 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.60]
web_1 | 2022-07-21 10:34:52.364 INFO 1 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
web_1 | 2022-07-21 10:34:52.364 INFO 1 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1388 ms
web_1 | 2022-07-21 10:34:52.577 INFO 1 --- [ main] org.hibernate.Version : HHH000412: Hibernate ORM core version 6.0.0.Final
web_1 | 2022-07-21 10:34:53.269 WARN 1 --- [ main] org.hibernate.orm.connections.pooling : HHH10001002: Using built-in connection pool (not intended for production use)
web_1 | 2022-07-21 10:34:53.275 INFO 1 --- [ main] org.hibernate.orm.connections.pooling : HHH10001005: Loaded JDBC driver class: com.mysql.cj.jdbc.Driver
web_1 | 2022-07-21 10:34:53.275 INFO 1 --- [ main] org.hibernate.orm.connections.pooling : HHH10001012: Connecting with JDBC URL [jdbc:mysql://configs_mysql:3306/configs]
web_1 | 2022-07-21 10:34:53.275 INFO 1 --- [ main] org.hibernate.orm.connections.pooling : HHH10001001: Connection properties: {password=****, user=scrap}
web_1 | 2022-07-21 10:34:53.276 INFO 1 --- [ main] org.hibernate.orm.connections.pooling : HHH10001003: Autocommit mode: false
web_1 | 2022-07-21 10:34:53.279 INFO 1 --- [ main] org.hibernate.orm.connections.pooling : HHH10001115: Connection pool size: 20 (min=1)
web_1 | 2022-07-21 10:34:53.407 WARN 1 --- [ main] o.h.e.j.e.i.JdbcEnvironmentInitiator : HHH000342: Could not obtain connection to query metadata
web_1 |
web_1 | java.lang.IllegalStateException: Cannot get a connection as the driver manager is not properly initialized
web_1 | at org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl.getConnection(DriverManagerConnectionProviderImpl.java:259) ~[hibernate-core-6.0.0.Final.jar!/:6.0.0.Final]
web_1 | at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess.obtainConnection(JdbcEnvironmentInitiator.java:284) ~[hibernate-core-6.0.0.Final.jar!/:6.0.0.Final]
web_1 | at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:177) ~[hibernate-core-6.0.0.Final.jar!/:6.0.0.Final]
web_1 | at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:36) ~[hibernate-core-6.0.0.Final.jar!/:6.0.0.Final]
web_1 | at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:100) ~[hibernate-core-6.0.0.Final.jar!/:6.0.0.Final]
web_1 | at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:255) ~[hibernate-core-6.0.0.Final.jar!/:6.0.0.Final]
web_1 | at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:230) ~[hibernate-core-6.0.0.Final.jar!/:6.0.0.Final]
web_1 | at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:207) ~[hibernate-core-6.0.0.Final.jar!/:6.0.0.Final]
web_1 | at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:48) ~[hibernate-core-6.0.0.Final.jar!/:6.0.0.Final]
The issue is with your hibernate.cfg file.
You are referring container name as database host in that config file.
<property name="hibernate.connection.url">jdbc:mysql://configs_mysql:3306/configs</property>
configs_mysql is your container name but it not your DB host in the docker world. Remember communication between the docker containers inside the docker compose network will happen through service name.
For Database service you defined mysql as your service name.
Change the hibernate.connection.url to below
<property name="hibernate.connection.url">jdbc:mysql://mysql:3306/configs</property>
Refer: Docker compose with multiple services (app and DB)
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 :)
So i put my django app and mysql inside docker container. Here is what i do
Docker file
FROM python:3
ENV PYTHONUNBUFFERED 1
WORKDIR /app
COPY requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt
COPY . /app
and here is my docker-compose-yml
version: '3'
services:
db:
container_name: database
image: mysql:8
ports:
- "3306:3306"
command: --default-authentication-plugin=mysql_native_password
environment:
- MYSQL_DATABASE=django_example
- MYSQL_USER=root
- MYSQL_PASSWORD=123456
- MYSQL_ROOT_PASSWORD=123456
- MYSQL_ROOT_HOST=%
volumes:
- "./db:/var/lib/mysql"
web:
container_name: app
build: .
command: python manage.py runserver 0.0.0.0:8000
ports:
- "8000:8000"
volumes:
- .:/app
- /tmp/app/mysqld:/run/mysqld
depends_on:
- db
Then i run it with docker-compose up
I get this error
MySQLdb._exceptions.OperationalError: (2002, "Can't connect to local
MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)")
Here is my database setting
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_example',
'USER': 'root',
'PASSWORD': '123456',
'HOST': 'localhost',
'PORT': '3306',
}
}
My docker ps --all
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c61ac60bc037 mysql:latest "docker-entrypoint.s…" 2 minutes ago Up 34 seconds 0.0.0.0:3306->3306/tcp, 33060/tcp py_rest_api_db_1
f00857755a46 py_rest_api_web "python manage.py ru…" 5 minutes ago Up 34 seconds 0.0.0.0:8000->8000/tcp py_rest_api_web_1
So how can i fix it ? did i miss something?
Full Log
Starting database ... done
Starting app ... done
Attaching to database, app
database | 2020-10-23 06:03:42+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.22-1debian10 started.
database | 2020-10-23 06:03:42+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
database | 2020-10-23 06:03:42+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.22-1debian10 started.
database | 2020-10-23T06:03:43.191491Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.22) starting as process 1
database | 2020-10-23T06:03:43.199528Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive
database | 2020-10-23T06:03:43.214677Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
app | Watching for file changes with StatReloader
app | Performing system checks...
app |
app | System check identified no issues (0 silenced).
app | Exception in thread django-main-thread:
app | Traceback (most recent call last):
app | File "/usr/local/lib/python3.9/site-packages/django/db/backends/base/base.py", line 219, in ensure_connection
app | self.connect()
app | File "/usr/local/lib/python3.9/site-packages/django/utils/asyncio.py", line 26, in inner
app | return func(*args, **kwargs)
app | File "/usr/local/lib/python3.9/site-packages/django/db/backends/base/base.py", line 200, in connect
app | self.connection = self.get_new_connection(conn_params)
app | File "/usr/local/lib/python3.9/site-packages/django/utils/asyncio.py", line 26, in inner
app | return func(*args, **kwargs)
app | File "/usr/local/lib/python3.9/site-packages/django/db/backends/mysql/base.py", line 234, in get_new_connection
app | return Database.connect(**conn_params)
app | File "/usr/local/lib/python3.9/site-packages/MySQLdb/__init__.py", line 130, in Connect
app | return Connection(*args, **kwargs)
app | File "/usr/local/lib/python3.9/site-packages/MySQLdb/connections.py", line 185, in __init__
app | super().__init__(*args, **kwargs2)
app | MySQLdb._exceptions.OperationalError: (2002, "Can't connect to MySQL server on 'db' (115)")
app |
app | The above exception was the direct cause of the following exception:
app |
app | Traceback (most recent call last):
app | File "/usr/local/lib/python3.9/threading.py", line 950, in _bootstrap_inner
app | self.run()
app | File "/usr/local/lib/python3.9/threading.py", line 888, in run
app | self._target(*self._args, **self._kwargs)
app | File "/usr/local/lib/python3.9/site-packages/django/utils/autoreload.py", line 53, in wrapper
app | fn(*args, **kwargs)
app | File "/usr/local/lib/python3.9/site-packages/django/core/management/commands/runserver.py", line 121, in inner_run
app | self.check_migrations()
app | File "/usr/local/lib/python3.9/site-packages/django/core/management/base.py", line 459, in check_migrations
app | executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
app | File "/usr/local/lib/python3.9/site-packages/django/db/migrations/executor.py", line 18, in __init__
app | self.loader = MigrationLoader(self.connection)
app | File "/usr/local/lib/python3.9/site-packages/django/db/migrations/loader.py", line 53, in __init__
app | self.build_graph()
app | File "/usr/local/lib/python3.9/site-packages/django/db/migrations/loader.py", line 216, in build_graph
app | self.applied_migrations = recorder.applied_migrations()
app | File "/usr/local/lib/python3.9/site-packages/django/db/migrations/recorder.py", line 77, in applied_migrations
app | if self.has_table():
app | File "/usr/local/lib/python3.9/site-packages/django/db/migrations/recorder.py", line 55, in has_table
app | with self.connection.cursor() as cursor:
app | File "/usr/local/lib/python3.9/site-packages/django/utils/asyncio.py", line 26, in inner
app | return func(*args, **kwargs)
app | File "/usr/local/lib/python3.9/site-packages/django/db/backends/base/base.py", line 259, in cursor
app | return self._cursor()
app | File "/usr/local/lib/python3.9/site-packages/django/db/backends/base/base.py", line 235, in _cursor
app | self.ensure_connection()
app | File "/usr/local/lib/python3.9/site-packages/django/utils/asyncio.py", line 26, in inner
app | return func(*args, **kwargs)
app | File "/usr/local/lib/python3.9/site-packages/django/db/backends/base/base.py", line 219, in ensure_connection
app | self.connect()
app | File "/usr/local/lib/python3.9/site-packages/django/db/utils.py", line 90, in __exit__
app | raise dj_exc_value.with_traceback(traceback) from exc_value
app | File "/usr/local/lib/python3.9/site-packages/django/db/backends/base/base.py", line 219, in ensure_connection
app | self.connect()
app | File "/usr/local/lib/python3.9/site-packages/django/utils/asyncio.py", line 26, in inner
app | return func(*args, **kwargs)
app | File "/usr/local/lib/python3.9/site-packages/django/db/backends/base/base.py", line 200, in connect
app | self.connection = self.get_new_connection(conn_params)
app | File "/usr/local/lib/python3.9/site-packages/django/utils/asyncio.py", line 26, in inner
app | return func(*args, **kwargs)
app | File "/usr/local/lib/python3.9/site-packages/django/db/backends/mysql/base.py", line 234, in get_new_connection
app | return Database.connect(**conn_params)
app | File "/usr/local/lib/python3.9/site-packages/MySQLdb/__init__.py", line 130, in Connect
app | return Connection(*args, **kwargs)
app | File "/usr/local/lib/python3.9/site-packages/MySQLdb/connections.py", line 185, in __init__
app | super().__init__(*args, **kwargs2)
app | django.db.utils.OperationalError: (2002, "Can't connect to MySQL server on 'db' (115)")
database | 2020-10-23T06:03:45.429683Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
database | 2020-10-23T06:03:45.557475Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
database | 2020-10-23T06:03:45.635937Z 0 [System] [MY-010229] [Server] Starting XA crash recovery...
database | 2020-10-23T06:03:45.639397Z 0 [System] [MY-010232] [Server] XA crash recovery finished.
database | 2020-10-23T06:03:45.805023Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
database | 2020-10-23T06:03:45.805494Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
database | 2020-10-23T06:03:45.818355Z 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.
database | 2020-10-23T06:03:45.855862Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.22' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server - GPL.
Your Database settings has HOST set to localhost. when your django service spins up in container, service will look for mysql on the same container (django) instead of connecting to actual mysql container.
Change the HOST value to db (db container name).
Add a depends_on to web in docker compose, to make sure web container waits for db to be up and running.
You may also need to set MYSQL_ROOT_HOST=% environment variable in mysql container to allow mysql to accept remote connections.
Edit
You can try using below options to wait for db container to be up.
use wait-for-sh as suggested in docker official docs
or try the approach here
In your Django settings.py file, change localhost to 127.0.0.1
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_example',
'USER': 'root',
'PASSWORD': '123456',
'HOST': '127.0.0.1', # <- Change here
'PORT': '3306',
}
}
Also make sure you are running the docker image with --net=host.
docker run --net=host [image-name]
I try to learn how connect Spring App with MySQL using docker-compose.
I've got the following issue:
spring-db | 2020-03-24 13:18:50+01:00 [Note] [Entrypoint]: Temporary server started.
spring-db | 2020-03-24T12:18:50.676560Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Socket: '/var/run/mysqld/mysqlx.sock'
spring-db | Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
spring-db | Warning: Unable to load '/usr/share/zoneinfo/leap-seconds.list' as time zone. Skipping it.
spring-db | Warning: Unable to load '/usr/share/zoneinfo/zone.tab' as time zone. Skipping it.
spring-db | Warning: Unable to load '/usr/share/zoneinfo/zone1970.tab' as time zone. Skipping it.
spring-db | 2020-03-24 13:18:54+01:00 [Note] [Entrypoint]: Creating database spring-db
spring-db | 2020-03-24 13:18:54+01:00 [Note] [Entrypoint]: Creating user spring-db
spring-db | 2020-03-24 13:18:54+01:00 [Note] [Entrypoint]: Giving user spring-db access to schema spring-db
spring-db |
spring-db | 2020-03-24 13:18:54+01:00 [Note] [Entrypoint]: /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/spring-db.sql
spring-db |
spring-db |
spring-db | 2020-03-24 13:18:55+01:00 [Note] [Entrypoint]: Stopping temporary server
spring-db | 2020-03-24T12:18:55.410358Z 15 [System] [MY-013172] [Server] Received SHUTDOWN from user root. Shutting down mysqld (Version: 8.0.19).
spring-db | 2020-03-24T12:18:57.128567Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.19) MySQL Community Server - GPL.
spring-db | 2020-03-24 13:18:57+01:00 [Note] [Entrypoint]: Temporary server stopped
spring-db |
spring-db | 2020-03-24 13:18:57+01:00 [Note] [Entrypoint]: MySQL init process done. Ready for start up.
Therefore I received following error:
spring-app | 2020-03-24 12:19:11.993 ERROR 1 --- [nio-8080-exec-9] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection] with root cause
spring-app |
spring-app | java.net.ConnectException: Connection refused (Connection refused)
Has anyone met a similar problem?
Thank you in advance for your help.
I found I made many mistakes.
Firstly configuration
Configuration
#ComponentScan("SpringAndDocker")
#EnableJpaRepositories("SpringAndDocker.repository")
public class ApplicationConfig {
#Value("${db.driver}")
private String databaseDriver;
#Value("${db.password}")
private String databasePassword;
#Value("${db.url}")
private String databaseUrl;
#Value("${db.username}")
private String databaseUsername;
#Value("${hibernate.dialect}")
private String hibernateDialect;
#Value("${hibernate.show_sql}")
private String hibernateShowSql;
private static final String PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN = "entitymanager.packages.to.scan";
#Resource
private Environment env;
#Bean
public DataSource dataSource()
{
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(databaseDriver);
dataSource.setUrl(databaseUrl);
dataSource.setUsername(databaseUsername);
dataSource.setPassword(databasePassword);
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory()
{
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactoryBean.setPackagesToScan(env.getRequiredProperty(PROPERTY_NAME_ENTITYMANAGER_PACKAGES_TO_SCAN));
entityManagerFactoryBean.setJpaProperties(hibProperties());
return entityManagerFactoryBean;
}
private Properties hibProperties()
{
Properties properties = new Properties();
properties.put("hibernate.dialect", hibernateDialect);
properties.put("hibernate.show_sql", hibernateShowSql);
return properties;
}
#Bean
public JpaTransactionManager transactionManager()
{
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}
Secondly docker-compose.yaml
db:
image: library/postgres:alpine
restart: always
hostname: spring-db
container_name: spring-db
volumes:
- /etc/localtime:/etc/localtime:ro
- ./docker/db/spring-db.sql:/docker-entrypoint-initdb.d/spring-db.sql:ro
- ./docker/db/spring-db.sql:/opt/db/spring-db.sql
environment:
- MYSQL_ROOT_PASSWORD=none
- MYSQL_DATABASE=spring-db
networks:
- spring
The hostname above is spring-db. But according to application.properties
# Database related properties
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:5432/spring-db
db.username=mysql
db.password=none
# Hibernate related properties
hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
hibernate.show_sql=false
entitymanager.packages.to.scan=pl.insudi.model
spring.main.allow-bean-definition-overriding=true
I tried to connect to localhost instead of spring-db.
That was the reason - I should have used the same hostname as in docker-compose.
Also to connect Hibernate properly I needed to use
db.url=jdbc:mysql://insudi-db:3306/insudi-db?allowPublicKeyRetrieval=true&useSSL=false
I am following this tutorial to setup spring boot project with docker-compose. Here is what I did:
My application.properties:
spring.datasource.url = jdbc:mysql://mysql-demo-container:3306/demo_db?useSSL=false
spring.datasource.username = root
spring.datasource.password =root
spring.datasource.tomcat.testWhileIdle = true
spring.datasource.tomcat.timeBetweenEvictionRunsMillis = 60000
spring.datasource.tomcat.validationQuery = SELECT 1
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
My Dockerfile:
`FROM java:8
LABEL maintainer=“foo.bar#gmail.com”
VOLUME /tmp
EXPOSE 8080
ADD target/spring-boot-data-jpa-example-0.0.1-SNAPSHOT.jar spring-boot-data-jpa-example-0.0.1-SNAPSHOT.jar
ENTRYPOINT ["java","-jar","spring-boot-data-jpa-example-0.0.1-SNAPSHOT.jar"]`
I have this docker-compose.yml:
version: '3'
services:
mysql-demo-container:
image: mysql:latest
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=demo_db
- MYSQL_PASSWORD=myPass
ports:
- 2012:3306
volumes:
- /data/mysql
spring-boot-jpa-app:
image: spring-boot-jpa-image
build:
context: ./
dockerfile: Dockerfile
depends_on:
- mysql-demo-container
ports:
- 8087:8080
volumes:
- /data/spring-boot-app
I firstly mvn clean install to build the project jar file, then I run docker-compose up to build images & hopefully run containers.
The logs:
$ docker-compose up
Creating network "spring-boot-data-jpa-example-master_default" with the default driver
Creating spring-boot-data-jpa-example-master_mysql-demo-container_1 ... done
Creating spring-boot-data-jpa-example-master_spring-boot-jpa-app_1 ... done
Attaching to spring-boot-data-jpa-example-master_mysql-demo-container_1, spring-boot-data-jpa-example-master_spring-boot-jpa-app_1
mysql-demo-container_1 | Initializing database
mysql-demo-container_1 | 2019-07-02T13:03:05.097872Z 0 [Warning] [MY-011070] [Server] 'Disabling symbolic links using --skip-symbolic-links (or equivalent) is the default. Consider not using this option as it' is deprecated and will be removed in a future release.
mysql-demo-container_1 | 2019-07-02T13:03:05.098037Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 8.0.16) initializing of server in progress as process 29
mysql-demo-container_1 | 2019-07-02T13:03:09.171833Z 5 [Warning] [MY-010453] [Server] root#localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
spring-boot-jpa-app_1 |
spring-boot-jpa-app_1 | . ____ _ __ _ _
spring-boot-jpa-app_1 | /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
spring-boot-jpa-app_1 | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
spring-boot-jpa-app_1 | \\/ ___)| |_)| | | | | || (_| | ) ) ) )
spring-boot-jpa-app_1 | ' |____| .__|_| |_|_| |_\__, | / / / /
spring-boot-jpa-app_1 | =========|_|==============|___/=/_/_/_/
spring-boot-jpa-app_1 | :: Spring Boot :: (v1.5.9.RELEASE)
spring-boot-jpa-app_1 |
spring-boot-jpa-app_1 | 2019-07-02 13:03:11.516 INFO 1 --- [ main] .s.e.SpringBootDataJpaExampleApplication : Starting SpringBootDataJpaExampleApplication v0.0.1-SNAPSHOT on 3c0d94b76fd6 with PID 1 (/spring-boot-data-jpa-example-0.0.1-SNAPSHOT.jar started by root in /)
spring-boot-jpa-app_1 | 2019-07-02 13:03:11.556 INFO 1 --- [ main] .s.e.SpringBootDataJpaExampleApplication : No active profile set, falling back to default profiles: default
spring-boot-jpa-app_1 | 2019-07-02 13:03:11.979 INFO 1 --- [ main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#6d5380c2: startup date [Tue Jul 02 13:03:11 UTC 2019]; root of context hierarchy
mysql-demo-container_1 | 2019-07-02T13:03:13.525348Z 0 [System] [MY-013170] [Server] /usr/sbin/mysqld (mysqld 8.0.16) initializing of server has completed
mysql-demo-container_1 | Database initialized
mysql-demo-container_1 | MySQL init process in progress...
mysql-demo-container_1 | MySQL init process in progress...
mysql-demo-container_1 | MySQL init process in progress...
mysql-demo-container_1 | 2019-07-02T13:03:15.636380Z 0 [Warning] [MY-011070] [Server] 'Disabling symbolic links using --skip-symbolic-links (or equivalent) is the default. Consider not using this option as it' is deprecated and will be removed in a future release.
mysql-demo-container_1 | 2019-07-02T13:03:15.636539Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.16) starting as process 80
mysql-demo-container_1 | 2019-07-02T13:03:18.070695Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
mysql-demo-container_1 | 2019-07-02T13:03:18.081045Z 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.
mysql-demo-container_1 | 2019-07-02T13:03:18.152808Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.16' socket: '/var/run/mysqld/mysqld.sock' port: 0 MySQL Community Server - GPL.
mysql-demo-container_1 | 2019-07-02T13:03:18.311442Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Socket: '/var/run/mysqld/mysqlx.sock'
spring-boot-jpa-app_1 | 2019-07-02 13:03:20.039 INFO 1 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
spring-boot-jpa-app_1 | 2019-07-02 13:03:20.221 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
spring-boot-jpa-app_1 | 2019-07-02 13:03:20.232 INFO 1 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.23
spring-boot-jpa-app_1 | 2019-07-02 13:03:21.210 INFO 1 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
spring-boot-jpa-app_1 | 2019-07-02 13:03:21.213 INFO 1 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 9251 ms
spring-boot-jpa-app_1 | 2019-07-02 13:03:22.153 INFO 1 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
spring-boot-jpa-app_1 | 2019-07-02 13:03:22.169 INFO 1 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
spring-boot-jpa-app_1 | 2019-07-02 13:03:22.178 INFO 1 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
spring-boot-jpa-app_1 | 2019-07-02 13:03:22.178 INFO 1 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
spring-boot-jpa-app_1 | 2019-07-02 13:03:22.181 INFO 1 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
mysql-demo-container_1 | Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
mysql-demo-container_1 | Warning: Unable to load '/usr/share/zoneinfo/leap-seconds.list' as time zone. Skipping it.
spring-boot-jpa-app_1 | 2019-07-02 13:03:25.161 ERROR 1 --- [ main] o.a.tomcat.jdbc.pool.ConnectionPool : Unable to create initial connections of pool.
spring-boot-jpa-app_1 |
spring-boot-jpa-app_1 | com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
spring-boot-jpa-app_1 |
spring-boot-jpa-app_1 | The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
spring-boot-jpa-app_1 | at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_111]
spring-boot-jpa-app_1 | at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_111]
spring-boot-jpa-app_1 | at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_111]
spring-boot-jpa-app_1 | at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_111]
spring-boot-jpa-app_1 | at com.mysql.jdbc.Util.handleNewInstance(Util.java:425) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
spring-boot-jpa-app_1 | at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:989) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
spring-boot-jpa-app_1 | at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:341) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
spring-boot-jpa-app_1 | at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2189) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
spring-boot-jpa-app_1 | at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2222) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
spring-boot-jpa-app_1 | at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2017) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
spring-boot-jpa-app_1 | at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:779) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
spring-boot-jpa-app_1 | at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:47) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
spring-boot-jpa-app_1 | at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_111]
spring-boot-jpa-app_1 | at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_111]
spring-boot-jpa-app_1 | at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_111]
spring-boot-jpa-app_1 | at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_111]
spring-boot-jpa-app_1 | at com.mysql.jdbc.Util.handleNewInstance(Util.java:425) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
spring-boot-jpa-app_1 | at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:389) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
spring-boot-jpa-app_1 | at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:330) ~[mysql-connector-java-5.1.44.jar!/:5.1.44]
spring-boot-jpa-app_1 | at org.apache.tomcat.jdbc.pool.PooledConnection.connectUsingDriver(PooledConnection.java:310) ~[tomcat-jdbc-8.5.23.jar!/:na]
spring-boot-jpa-app_1 | at org.apache.tomcat.jdbc.pool.PooledConnection.connect(PooledConnection.java:203) ~[tomcat-jdbc-8.5.23.jar!/:na]
spring-boot-jpa-app_1 | at org.apache.tomcat.jdbc.pool.ConnectionPool.createConnection(ConnectionPool.java:735) [tomcat-jdbc-8.5.23.jar!/:na]
spring-boot-jpa-app_1 | at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:667) [tomcat-jdbc-8.5.23.jar!/:na]
spring-boot-jpa-app_1 | at org.apache.tomcat.jdbc.pool.ConnectionPool.init(ConnectionPool.java:482) [tomcat-jdbc-8.5.23.jar!/:na]
spring-boot-jpa-app_1 | at org.apache.tomcat.jdbc.pool.ConnectionPool.<init>(ConnectionPool.java:154) [tomcat-jdbc-8.5.23.jar!/:na]
spring-boot-jpa-app_1 | at org.apache.tomcat.jdbc.pool.DataSourceProxy.pCreatePool(DataSourceProxy.java:118) [tomcat-jdbc-8.5.23.jar!/:na]
spring-boot-jpa-app_1 | at org.apache.tomcat.jdbc.pool.DataSourceProxy.createPool(DataSourceProxy.java:107) [tomcat-jdbc-8.5.23.jar!/:na]
spring-boot-jpa-app_1 | at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:131) [tomcat-jdbc-8.5.23.jar!/:na]
spring-boot-jpa-app_1 | at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111) [spring-jdbc-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
spring-boot-jpa-app_1 | at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77) [spring-jdbc-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
spring-boot-jpa-app_1 | at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:326) [spring-jdbc-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
spring-boot-jpa-app_1 | at org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData(JdbcUtils.java:366) [spring-jdbc-4.3.13.RELEASE.jar!/:4.3.13.RELEASE]
spring-boot-jpa-app_1 | at org.springframework.boot.autoconfigure.orm.jpa.DatabaseLookup.getDatabase(DatabaseLookup.java:72) [spring-boot-autoconfigure-1.5.9.RELEASE.jar!/:1.5.9.RELEASE]
spring-boot-jpa-app_1 | at org.springframework.boot.autoconfigure.orm.jpa.JpaProperties.determineDatabase(JpaProperties.java:139) [spring-boot-autoconfigure-1.5.9.
As you can see from the beginning of the log, the containers seem created successfully.
Run docker ps shows me:
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8fa64acb363d mysql:latest "docker-entrypoint.s…" 30 minutes ago Up 30 minutes 33060/tcp, 0.0.0.0:2012->3306/tcp spring-boot-data-jpa-example-master_mysql-demo-container_1
What could be the reason for the error?
You should be aware of this very important footnote in the reference documentation of Docker Compose:
depends_on does not wait for db and redis to be “ready” before starting web - only until they have been started. If you need to wait for a service to be ready, see Controlling startup order for more on this problem and strategies for solving it.
In your case, your Spring boot container starts right after your MySQL container is being started. There's no guarantee though that MySQL will be able to take connections when Spring boot is setting up its connection pool.
This means that your Spring boot connection will fail to startup, because MySQL isn't ready yet. This results in your application container to be killed.
The solution to this problem is mentioned within the documentation I quoted. Namely, you have to use some kind of polling mechanism to see if you can connect to your database or not.
If you don't want to use tools like wait-for-it or wait-for, you could write a simple Shell script that does something like this:
while ! exec 6<>/dev/tcp/mysql-demo-container/3306; do
echo "Trying to connect to MySQL..."
sleep 10
done
exec java -jar spring-boot-data-jpa-example-0.0.1-SNAPSHOT.jar
This also means you have to change the ENTRYPOINT within your Dockerfile to refer to such shell script rather than directly running your JAR file.