How to connect a flask container with a mysql container - docker

I have already a mysql container named "mysqlDemoStorage" running, exposing port 3306 to 0.0.0.0:3306. I also have a flask app which provides a login page and table-displaying page. The flask app works quite well in host. The login page connects to "user" table in the mysql container and the table-displaying page connects to another table holding all the data to display.
The docker-compose file I used to create the mysql container is as follows:
version: '3'
services:
mysql:
container_name: mysqlDemoStorage
environment:
MYSQL_ROOT_PASSWORD: "demo"
command:
--character-set-server=utf8
ports:
- 3306:3306
image: "docker.io/mysql:latest"
restart: always
Now I want to dockerize the flask app so that I can still view the app from host. The mysql container detail is as followed:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c48955b3589e mysql:latest "docker-entrypoint.s…" 13 days ago Up 49 minutes 0.0.0.0:3306->3306/tcp, 33060/tcp mysqlDemoStorage
The dockerfile of the flask app I wrote is as follows:
FROM python:latest
WORKDIR /storage_flask
ADD . /storage_flask
RUN pip install -r requirements.txt
EXPOSE 5000
ENTRYPOINT ["python","run.py"]
The flask image can be successfuly built, but when I run the image, I fail to load the page. One point I think that causes the problem is the init.py file to initiate the flask app, which is as follows:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
app = Flask(__name__)
app.config['SECRET_KEY'] = 'aafa4f8047ce31126011638be8530da6'
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:demo#localhost:3306/storage'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = "login"
login_manager.login_message_category = 'info'
from storage_flask import routes
I was thinking passing the IP of the mysql container to the flask container as the config string for DB connection. But I'm not sure how to do it.
Could someone help to solve the problem? Thank you

change this line
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:demo#localhost:3306/storage'
to
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:demo#mysql:3306/storage'
You also need to make sure that both containers are connected to the same network, for that you need to update your docker-compose file to be something like the below file
version: '3.7'
networks:
my_network_name:
name: my_network_name
external: false
services:
mysql:
container_name: mysqlDemoStorage
environment:
MYSQL_ROOT_PASSWORD: "demo"
command:
--character-set-server=utf8
ports:
- 3306:3306
image: "docker.io/mysql:latest"
restart: always
networks:
- my_network_name
second file
version: '3.7'
networks:
my_network_name:
name: my_network_name
external: true
services:
python_app:
container_name: pythonDemoStorage
ports:
- 5000:5000
image: "Myimage"
restart: always
networks:
- my_network_name

Related

Docker compose for nginx, streamlit, and mariadb

I am not exactly sure how to go about this. I have an instance in AWS Lightsail that has a static IP for which the IP department granted access to read from MariaDB database. I am using streamlit for my app and have stored my database credentials in a .env file. After, I have copied the file code and dockerized it (running the following command):
docker-compose up --build -d
It is built successfully, but when I use the static IP to look at the web page I get the following error:
OperationalError: (2003, "Can't connect to MySQL server on 'localhost' ([Errno 99] Cannot assign requested address)")
Is there something I have to do either in docker or with MariaDB? Thank you in advance.
File of docker-compose.yml:
version: '3'
services:
app:
container_name: app
restart: always
build: ./app
ports:
- "8501:8501"
command: streamlit run Main.py
database:
image: mariadb:latest
volumes:
- /data/mysql:/var/lib/mysql
restart: always
env_file: .env
nginx:
container_name: nginx
restart: always
build: ./nginx
ports:
- "80:80"
depends_on:
- app
- database
I am not sure how the streamlit app is connected with mariadb here.

Dockerized Flask app is not accessible in localhost

I have been playing around with docker, celery, redis and Flask for the past 2-3 days, after successfully setting up a flask, celery and redis server I decided to go onto to the next point which dockerizing it. I have successfully created a docker image and a composer file which seem to work just fine when building. I am using a local redis server and I am able to access it by using docker.for.mac.localhost as the host name in order to access the redis server from inside the container, but, when I try to access the flask app while it's running from outside of the container it doesn't work.
Having done some research I have tried the following:
Running with server host as 0.0.0.0
Exposing and using a different port other than 5000
This is my Dockerfile:
WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python3", "./app.py"]
And this is my docker-compose.yml file
version: "3"
services:
web:
container_name: web
build: ./api
ports:
- "5000:5001"
links:
- redis
depends_on:
- redis
environment:
- FLASK_ENV=development
volumes:
- ./api:/app
redis:
container_name: redis
image: redis:5.0.5
hostname: redis
worker:
build:
context: ./api
hostname: worker
entrypoint: celery
command: -A app.celery worker --loglevel=info
volumes:
- ./api:/app
links:
- redis
depends_on:
- redis
Thanks for any help in advance!
Your port mapping is backwards. It should be external to internal.
ports:
- "5001:5000"

Docker unable to connect to postgres, but same command works fine when running from containers bash

When building the docker file, I have the command:
CMD ["/app/database/updateLocalDocker.sh"]
The shell script should connect to the postgres service using liquibase but fails with the error connection refused...
When i comment out the above CMD and run the same script directory from the container via docker exec -t -i f42c4bbcd95d /bin/bash, it works fine.
The URL i'm trying to connect to is: jdbc:postgresql://localhost:5432/service_x"
I have a feeling that it's related to either the service not being started or a network issue, when trying to execute the CMD during the docker-compose build stage.
Any guidance would be much appreicated.
docker-compose.yml:
version: "3.8"
services:
db:
image: local.db
build:
context: .
ports:
- 15432:5432
environment:
POSTGRES_PASSWORD: password
networks:
- a
networks:
a:
name: a
external: true
To access your database from your localhost you need to use the port 15432 instead of 5432.
services:
db:
image: local.db
build:
context: .
ports:
- 15432:5432 <--- Here
environment:
POSTGRES_PASSWORD: password
networks:
- a
The first port is your host and the second is the port used in your container.
You can also access it with the container name and the port used in it.
Docker port mapping documentation :
https://docs.docker.com/config/containers/container-networking/
Instead of putting the command in the Dockerfile, you can directly put the command in the docker-compose file and remove CMD ["/app/database/updateLocalDocker.sh"].
docker-compose.yml
version: "3.8"
services:
db:
image: local.db
build:
context: .
command: sh -c "<Enter-your-command>"
ports:
- 15432:5432
environment:
POSTGRES_PASSWORD: password
networks:
- a
networks:
a:
name: a
external: true
If you have one command execute
command: <command>
OR
If you have more than one command, it should be separated by &&.
Syntax:
sh -c "<command-1> && <command-2> && <command-3>"

Nuxt.js 500 NuxtServerError under docker-compose

my system contains 3 dockers:
mongodb
api backend, built with Nestjs
web application, build with Nuxt.js
the mongo and the backend seems to be working, because i can access the swagger at localhost:3000/api/.
the Nuxtjs web app is failing, and i'm getting 500 Nuxtserver error.
Dockerfile (for the web app):
FROM node:12.13-alpine
ENV APP_ROOT /src
RUN mkdir ${APP_ROOT}
WORKDIR ${APP_ROOT}
ADD . ${APP_ROOT}
RUN npm install
RUN npm run build
ENV HOST 0.0.0.0
EXPOSE 4000
docker-compose.yml:
version: "3"
services:
# backend nestjs app
api:
image: nestjs-api-server
container_name: my-api
depends_on:
- db
restart: unless-stopped
environment:
- NODE_ENV=production
ports:
- 3000:3001
networks:
- mynet
links:
- db
# mongodb
db:
image: mongo
container_name: db_mongo
restart: unless-stopped
volumes:
- ~/data/:/data/db
ports:
- 27017:27017
networks:
- mynet
# front web app, nuxt.js
web:
image: nuxtjs-web-app
container_name: my-web
depends_on:
- api
restart: always
ports:
- 4000:4000
environment:
- BASE_URL=http://localhost:3000/api
command:
"npm run start"
networks:
- mynet
networks:
mynet:
driver: bridge
Looks like the nuxtjs app cannot connect to the api. in the log i see:
ERROR connect ECONNREFUSED 127.0.0.1:3000
But why? the swagger (coming from the same api) works fine on http://localhost:3000/api/#/.
Any idea?
environment:
- BASE_URL=http://localhost:3000/api
localhost in a container means inside that particular container. i.e., it will try to resolve port 3000 in my-web container itself.
Basically from front-end you cannot do container communication. May be you can communicate via public hostname or ip or you can make use of extra_hosts concept in docker-compose to resolve localhost.
Got it. The problem was in nuxtServerInit. This is a very special method on vuex, and it is running in the server. i called $axios from it, and i guess you can't do that.
once i commented that method, it's working fine.

Connecting to MySQL from Flask Application using docker-compose

I have an application using Flask and MySQL. The application does not connect to MySQL container from the Flask Application but it can be accessed using Sequel Pro with the same credentials.
Docker Compose File
version: '2'
services:
web:
build: flask-app
ports:
- "5000:5000"
volumes:
- .:/code
mysql:
build: mysql-server
environment:
MYSQL_DATABASE: test
MYSQL_ROOT_PASSWORD: root
MYSQL_ROOT_HOST: 0.0.0.0
MYSQL_USER: testing
MYSQL_PASSWORD: testing
ports:
- "3306:3306"
Docker file for MySQL
The docker file for MySQL will add schema from test.dump file.
FROM mysql/mysql-server
ADD test.sql /docker-entrypoint-initdb.d
Docker file for Flask
FROM python:latest
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
ENTRYPOINT ["python"]
CMD ["app.py"]
Starting point app.py
from flask import Flask, request, jsonify, Response
import json
import mysql.connector
from flask_cors import CORS, cross_origin
app = Flask(__name__)
def getMysqlConnection():
return mysql.connector.connect(user='testing', host='0.0.0.0', port='3306', password='testing', database='test')
#app.route("/")
def hello():
return "Flask inside Docker!!"
#app.route('/api/getMonths', methods=['GET'])
#cross_origin() # allow all origins all methods.
def get_months():
db = getMysqlConnection()
print(db)
try:
sqlstr = "SELECT * from retail_table"
print(sqlstr)
cur = db.cursor()
cur.execute(sqlstr)
output_json = cur.fetchall()
except Exception as e:
print("Error in SQL:\n", e)
finally:
db.close()
return jsonify(results=output_json)
if __name__ == "__main__":
app.run(debug=True,host='0.0.0.0')
When I do a GET request on http://localhost:5000/ using REST Client I get a valid response.
A GET request on http://localhost:5000/api/getMonths gives error message:
mysql.connector.errors.InterfaceError: 2003: Can't connect to MySQL server on '0.0.0.0:3306' (111 Connection refused)
When the same credentials were used on Sequel Pro, I was able to access the database.
Please advice me on how to connect the MySQL container from the Flask Application. This is my first time suing Docker and do forgive me if this is a silly mistake from my part.
Change this
return mysql.connector.connect(user='testing', host='0.0.0.0', port='3306', password='testing', database='test')
to
return mysql.connector.connect(user='testing', host='mysql', port='3306', password='testing', database='test')
Your code is running inside the container and not on your host. So you need to provide it a address where it can reach within container network. For docker-compose each service is reachable using its name. So in your it is mysql as that is name you have used for the service
For others who encounter similar issue, if you are mapping different ports from host to container for the MySQL service, make sure that container that needs to connect to the MySQL service is using the port for the container not for the host.
Here is an example of a docker compose file. Here you can see that my application (which is running in a container) will be using port 3306 to connect to the MySQL service (which is also running in a container on port 3306). Anyone connecting to this MySQL service from the outside of the "backend" network which is basically anything that does not run in a container with the same network will need to use port 3308 to connect to this MySQL service.
version: "3"
services:
redis:
image: redis:alpine
command: redis-server --requirepass imroot
ports:
- "6379:6379"
networks:
- frontend
mysql:
image: mariadb:10.5
command: --default-authentication-plugin=mysql_native_password
ports:
- "3308:3306"
volumes:
- mysql-data:/var/lib/mysql/data
networks:
- backend
environment:
MYSQL_ROOT_PASSWORD: imroot
MYSQL_DATABASE: test_junkie_hq
MYSQL_HOST: 127.0.0.1
test-junkie-hq:
depends_on:
- mysql
- redis
image: test-junkie-hq:latest
ports:
- "80:5000"
networks:
- backend
- frontend
environment:
TJ_MYSQL_PASSWORD: imroot
TJ_MYSQL_HOST: mysql
TJ_MYSQL_DATABASE: test_junkie_hq
TJ_MYSQL_PORT: 3306
TJ_APPLICATION_PORT: 5000
TJ_APPLICATION_HOST: 0.0.0.0
networks:
backend:
frontend:
volumes:
mysql-data:

Resources