This question already has answers here:
Deploying a minimal flask app in docker - server connection issues
(8 answers)
Closed 2 years ago.
I have simple flask app which uses SQLLite database.
Here is my app.py code
from flask import Flask
from flask_restful import Api
from flask_jwt import JWT
from datetime import timedelta
from db import db
from security import authenticate, identity
from resources.user import UserRegister
from resources.product import Product, ProductList
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.secret_key = '#hsgvTyb#3gd###123'
api = Api(app)
#app.before_first_request
def create_tables():
db.create_all()
jwt = JWT(app, authenticate, identity) # /auth
app.config['JWT_EXPIRATION_DELTA'] = timedelta(seconds=1800)
api.add_resource(Product, '/product/<string:name>')
api.add_resource(ProductList, '/products')
api.add_resource(UserRegister, '/register')
if __name__ == '__main__':
db.init_app(app)
app.run(port=5000, debug=False)
DockerFile as below:
FROM python:3
ADD app/ /app
WORKDIR /app
RUN apt-get update
RUN pip install -r requirements.txt
CMD python app.py
docker-compose.yml as below:
version: "2"
services:
app:
container_name: test-146957-app
build:
context: ../
dockerfile: deployments/app/Dockerfile
ports:
- "5000:5000"
Now when I execute docker-compose up command it is showing container is running but I hit any endpoints from postman, it does not return any response.
You have to add host=0.0.0.0 as Flask run parameter. See the documentation for details: https://flask.palletsprojects.com/en/1.1.x/api/#flask.Flask.run
Related
I am trying to build and run a flask application using docker on GCP.
My file structure is as follows:
> /project
> static (contains some images)
> templates (contains html files)
> tmp_data (contains some data that is created during usage of the app)
> __init__.py
> auth.py (app has a login feature, this script helps authorize them)
> main.py
> Dockerfile
> some other function scripts
My Dockerfile is as follows:
FROM python:3.9-slim
RUN pip3 install Flask gunicorn scipy seaborn matplotlib pandas numpy flask_excel flask_login flask_sqlalchemy
COPY . /project
WORKDIR project
ENV FLASK_APP=main.python
# run flask in dev mode
ENV FLASK_ENV=development
EXPOSE 5001:5000
CMD ["flask", "run", "--host", "0.0.0.0"]
My main.py file is as follows:
from flask import Blueprint, render_template, redirect, url_for
from flask_login import login_required, current_user
from . import db
import flask_excel as excel
import json
# user written imports (not sure why it wants relative imports now?)
from .generate_data import get_truncated_normal, create_data
from .create_graphs import plot_graph, hist_plot, bar_plot, pie_plot, data_comments
from .generate_html_file import generate_html
main = Blueprint('main', __name__)
#main.route('/')
def index():
return render_template('index.html')
... some functions and flask views ...
When I build my app (successfully) using the command
~/some_upper_folder/project (my_sandbox)$ docker build -t project .
and then run it with the command
~/some_upper_folder/project (my_sandbox)$ docker run project
I get the error:
* Serving Flask app 'main.python' (lazy loading)
* Environment: development
* Debug mode: on
Usage: flask run [OPTIONS]
Try 'flask run --help' for help.
Error: Could not import 'project.main.python'.
I am not sure why this is occurring, I'm guessing this is due to the fact that I'm referencing an incorrect directory?
NOTE: The app is working correctly, I can run it using a venv created in another folder not seen here
I am trying to migrate my python changes to my docker project, however when I try to run the command python manage.py db migrate I get the error unknown database 'main', however when I look inside of my docker-compose.yml file I see that main is indeed defined inside of the MYSQL_DATABASE variable inside of the container db. I have tried some solutions found on StackOverflow as well as Github like getting the restart: always out of my docker-compose.yml script and making a Windows PowerShell script that will run to restart my docker container as found here: MYSQL Docker container gives "unknown database" error, and trying to change my DATA_SAVE_PATH variable and other such variables in my docker-compose.yml: https://github.com/laradock/laradock/issues/1017 and I have also tried to change the MYSQL_DATABASE variable to a different name but that doesn't work either.
Here is the full error that I am receiving when I run my code:
sqlalchemy.exc.OperationalError: (MySQLdb._exceptions.OperationalError) (1049, "Unknown database 'main'")
(Background on this error at: http://sqlalche.me/e/13/e3q8)
Here is my docker-compose.yml script:
version: '3.9'
services:
backend:
build:
context: .
dockerfile: Dockerfile
ports:
- 8001:5000
volumes:
- .:/app
depends_on:
- db
db:
image: mysql:5.7.22
restart: always
environment:
MYSQL_DATABASE: main
MYSQL_USER: root
MYSQL_PASSWORD: root
MYSQL_ROOT_PASSWORD: root
volumes:
- .dbdata:/var/lib/mysql
ports:
- 33067:3306
Here is my Dockerfile:
FROM python:3.9
ENV PYTHONUNBUFFERED 1
WORKDIR /app
COPY requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt
COPY . /app
CMD python main.py
Here is my main.py file:
from flask_cors import CORS
from sqlalchemy import UniqueConstraint
from vegaaimain.vegamain import main
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = 'mysql://root:root#db/main'
CORS(app)
db = SQLAlchemy(app)
class VegaScriptRun(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement=False)
title = db.Column(db.String(200))
description = db.Column(db.String(400))
image = db.Column(db.String(200))
main()
class VegaScriptUser(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer)
title = db.Column(db.String(200))
description = db.Column(db.String(400))
image = db.Column(db.String(200))
UniqueConstraint('user_id', 'title', 'description', 'image', name='user_experiment_unique')
#app.route('/')
def index():
return 'Hello'
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
And finally my manage.py file, and requirements.txt file:
from main import app, db
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
migrate = Migrate(app, db)
manager = Manager(app)
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
requirements.txt
Flask==1.1.2
Flask-SQLAlchemy==2.4.4
SQLAlchemy==1.3.20
Flask-Migrate==3.0.0
Flask-Script==2.0.6
Flask-Cors==3.0.9
requests==2.25.0
mysqlclient==2.0.1
pika==1.1.0
wolframalpha==5.0.0
What exactly am I missing or doing wrong here, thank you!
I solved this problem by looking in my .dbdata folder and found my service, I then changed the MYSQL_DATABASE variable and the app configuration to the same variable as MYSQL_DATABASE which was vegatest instead of main.
So I ran the same command python manager.py db migrate and I got a successful migration.
So, I've got this flask app that works fine when I run it via the terminal, but for some reason, if I start up a docker container, it instantly exits with 'exit code zero'.
Here is the folder structure:
https://imgur.com/a/BOGCt6S
docker-compose.yml:
version: '3.2'
services:
flask-app:
build: ./Flask_App
volumes:
- ./Flask_App/static:/Flask_App/static
- ./Flask_App/db:/Flask_App/db
ports:
- '5001:5001'
# restart: unless-stopped
Dockerfile:
FROM python:3
# Setup env
COPY requirements.txt ./
RUN pip install -r requirements.txt
# Setup App
RUN mkdir -p /Flask_App
COPY . /Flask_App
WORKDIR /Flask_App
EXPOSE 5001
ENTRYPOINT [ 'python3' ]
CMD [ 'app.py' ]
and the app.py file: (I know its just imports, but it works fine when I run it via the terminal on the host, so it probably is working ok)
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_bootstrap import Bootstrap
from forms import *
app = Flask(__name__)
app.config.from_pyfile('config.py')
Bootstrap(app)
db = SQLAlchemy(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
from views import *
if __name__ == '__main__':
app.run(host=app.config['HOST'], port=app.config['PORT'], debug=app.config['DEBUG'])
and just in case, here is a part of the 'config.py' file:
DEBUG = False
HOST = '0.0.0.0'
PORT = 5001
As said by David Maze in a comment, the single quotes(') I used in ENTRYPOINT and CMD should be changed to double quotes ("), since they are supposed to be JSON arrays.
I have a small Flask application. I add an extra security layer which is log in. I based my refactoring on the DO article.
In a nutshell,
__init__.py:
from flask import Flask
from flask_login import LoginManager
from flask_sqlalchemy import SQLAlchemy
from werkzeug.security import generate_password_hash
from sqlalchemy import create_engine
# init SQLAlchemy so we can use it later in our models
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = 'e56432f4402c9a0c166fe6c6a0a2fbbd'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite'
db.init_app(app)
# blueprint for auth routes in our app
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint)
# blueprint for non-auth parts of app
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(app)
from .models import User
#login_manager.user_loader
def load_user(user_id):
# since the user_id is just the primary key of our user table, use it in the query for the user
return User.query.get(int(user_id))
return app
In order to create DB, I need to run in REPL:
from project import db, create_app
db.create_all(app=create_app())
This is both inconvenient and makes Docker image creation harder. I run an application as flask run. I saw similar issues but don't understand how to apply to my scenario.
How can I overcome this complication?
UPDATE 1:
My project structure is the following:
project/
project/
__init__.py
auth.py
main.py
models.py
static/
templates/
Dockerfile
requirements.txt
If you want the database to be created when you run the flask app:
I would put this code
def createMyDatabase():
from project import db, create_app
db.create_all(app=create_app())
into the file makedatabase.py and save it into your program's root directory. Then add from <path to makedatabase.py>/makedatabase import createMyDatabase to the top of your __init__.py file and then just after your import statements in __init__.py write createMyDatabase(). I think that this would be the easiest way to do it in your situation.
If you don't want the database to be created every time that you run the program:
You could just take the function out of the makedatabase.py file and then run the file just as it is before you run the flask application.
I found a more elegant solution
Instead of return app make the following block, so an application will be created in the runtime if and only if the context was initialized and database created.
with app.app_context():
db.create_all()
return app
Surprisingly the Flask-SqlAlchemy is pointing out to REPL db creation as a first solution, not the one above.
UPDATE:
Here is an example of my Dockerfile:
FROM python:3.7-slim
ENV FLASK_APP=.
WORKDIR /app
COPY requirements.txt /app/requirements.txt
COPY . /app
RUN pip install -r requirements.txt
CMD flask run -h 0.0.0.0 -p 5000
The catch is that you have to change how you run flask, not via python command.
I've created a simple flask web app and managed to publish it with CI/CD from azure devops to an azure web app. The pipelines are working except the startup of my app.
If i look at the log files in the webapp this comes up -
logfile default_docker.log:
2020-01-08T13:04:17.017575225Z Documentation: http://aka.ms/webapp-linux
2020-01-08T13:04:17.017579025Z Python 3.7.5
2020-01-08T13:04:17.017582725Z Note: Any data outside '/home' is not persisted
2020-01-08T13:04:17.093756525Z Starting OpenBSD Secure Shell server: sshd.
2020-01-08T13:04:17.109540649Z Site's appCommandLine: gunicorn --bind = 0.0.0.0 --timeout 600 app: application
2020-01-08T13:04:17.110379356Z Launching oryx with: -appPath /home/site/wwwroot -output /opt/startup/startup.sh -virtualEnvName antenv -defaultApp /opt/defaultsite -bindPort 8000 -userStartupCommand 'gunicorn --bind = 0.0.0.0 --timeout 600 app: application'
2020-01-08T13:04:17.114336587Z Oryx Version: 0.2.20191105.2, Commit: 67e159d71419415435cb5d10c05a0f0758ee8809, ReleaseTagName: 20191105.2
2020-01-08T13:04:17.116548105Z Found build manifest file at '/home/site/wwwroot/oryx-manifest.toml'. Deserializing it...
2020-01-08T13:04:17.118951024Z Build Operation ID: |DGaRVt5jG5c=.2a144509_
2020-01-08T13:04:17.554659456Z Writing output script to '/opt/startup/startup.sh'
2020-01-08T13:04:17.784203265Z Found virtual environment .tar.gz archive.
2020-01-08T13:04:17.784884970Z Removing existing virtual environment directory /antenv...
2020-01-08T13:04:17.788272497Z Extracting to directory /antenv...
2020-01-08T13:04:32.810295030Z Using packages from virtual environment antenv located at /antenv.
2020-01-08T13:04:32.817794689Z Updated PYTHONPATH to ':/antenv/lib/python3.7/site-packages'
2020-01-08T13:04:36.780635398Z usage: gunicorn [OPTIONS] [APP_MODULE]
2020-01-08T13:04:36.780670499Z gunicorn: error: unrecognized arguments: app: application
my simplefied app treeview looks like this -
test_app/
venv/
application/
templates/
__init__.py
routes.py
errors.py
models.py
forms.py
app.py
i've tried different startup commands in azure portal "general setting" but to no solution
gunicorn --bind=0.0.0.0 --timeout 600 app:application
EDIT : added app.py and init.py
app.py:
from application import app, db
from application.models import User, Post
#app.shell_context_processor
def make_shell_context():
return {'db': db, 'User': User, 'Post': Post, 'Classrooms' : Classrooms, 'ClassSession' : ClassSession, 'Teacher' : Teacher}
init.py
from flask import Flask
from config import Config
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
from logging.handlers import RotatingFileHandler
import os
from flask_bootstrap import Bootstrap
import logging
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
login = LoginManager(app)
login.login_view = 'login'
bootstrap = Bootstrap(app)
from application import routes, models, errors
if __name__ == '__main__':
# * --- DEBUG MODE: --- *
app.run(host='127.0.0.1', port=5000, debug=True)
can anybody point me a direction to where i can solve this stupid problem.
thx a lot!!
The gunicorn command isn't actually pointing to the WSGI app object. Try this instead:
gunicorn --bind=0.0.0.0 --timeout 600 application:app