I'm following various tutorials from Google Cloud to try and deploy my first Python Flask application to App Engine. I organized my app as a package instead of a module, after watching the tutorial from Corey Schafer on YouTube titled: "Python Flask Tutorial: Full-Featured Web App Part 5 - Package Structure"
So now, in my working directory, I have a structure like this:
1. Project folder
1.1 myapp folder
1.1.1 __pycache__
1.1.2 static folder
1.1.3 __init__.py
1.1.4 app.yaml
1.1.5 requirements.txt
1.1.6 something_else.py
1.2 run.py
My run.py file has the following code:
from myapp import app
if __name__ == '__main__':
app.run(debug=True)
My app.yaml file looks like this:
runtime: python37
handlers:
# This configures Google App Engine to serve the files in the app's static
# directory.
- url: /static
static_dir: static
# This handler routes all requests not caught above to your main app. It is
# required when static routes are defined, but can be omitted (along with
# the entire handlers section) when there are no static files defined.
- url: /.*
script: auto
Now I am not sure how to set up my app.yaml file to specify the entry point, and also make my app run when I deploy it to App Engine. I am currently running the gcloud app deploy command via the Google Cloud SDK after I cd into myapp folder first?
The deployment phase in the console goes well, but when I check the app's browsing link, I am faced with a 502 Bad Gateway error (as I'm also expecting).
Everything works fine locally, but the deployment isn't too straightforward for me now that my app is structured like a package. Any help is greatly appreciated.
In your app.yaml, you can specify a custom entrypoint like so:
runtime: python37
entrypoint: gunicorn -b :$PORT myapp:app
Where myapp:app corresponds to the module to import the WSGI app from (from myapp import app)
You should also move your app.yaml file to be in the project folder instead, and run gcloud app deploy from there instead.
More details here: https://cloud.google.com/appengine/docs/standard/python3/runtime
Related
I'm trying to deploy my Django project to Google AppEngine, however I can't figure out how to properly set up application entrypoint.
This is my whole project structure:
app.yaml
main.py
service:
manage.py
service-project:
wsgi.py
settings.py
...
service-app-1:
...
service-app-2:
...
How can I make it work? I tried to move main.py to service directory and use entrypoint: gunicorn --chdir /service main:application in app.yaml but it results in Error: can't chdir to '/service', I guess AppEngine doesn't allow to change directory.
You need to change entrypoint: gunicorn --chdir /service main:application to entrypoint: gunicorn --chdir ./service main:application in your app.yaml.
The reason you are seeing Error: can't chdir to '/service' is because gunicorn is trying to change directory to the service folder in your root directory.
Adding dot in front of the slash will make it change directory to the service folder in your project, this is because the dot refers to the current directory where your app.yaml is.
I know this question has been asked in some facet or another, but I have gone through readings as shown here and I am still not seeing where my issue is as I am still unable to publish my Django 2.1.1 app in the Python37 environment in Google App Engine:
Python 3 Django on App Engine Standard: App Fails to Start
Overall what I am attempting to do is publish a simple app engine app using:
gcloud app deploy
My application works locally but when I publish, it goes through without issue, but I get the annoying:
500 Server Error message
When I look at the logs in Google I get the same error as many others have gotten:
ModuleNotFoundError: No module named 'main'
here is my relevant directory structure
project_portal
project_portal
init.py
settings.py
urls.py
wsgi.py
main.py
app.yaml
requirements.txt
my app.yaml file
runtime: python37
entrypoint: gunicorn -b :$PORT project_portal.wsgi
env: standard
handlers:
- url: .*
secure: always
redirect_http_response_code: 301
script: project_portal.wsgi.application
my project_portal/wsgi.py file
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project_portal.settings')
application = get_wsgi_application()
from main.py in project root
from project_portal.wsgi import application
from requirements.txt
django == 2.1.1
Without an entrypoint defined, it will try to start from a file called main.py. Create one, at the same level as app.yamlwith some simple logic in it:
from project_portal.wsgi import application
Edit:
Since you have an entrypoint defined, it seems that is the issue. So, make sure you have gunicorn in your 'requirements.txt':
gunicorn==19.9.0
This did not help:
Try changing
entrypoint: gunicorn -b :$PORT project_portal.wsgi
to
entrypoint: gunicorn -b :$PORT project_portal.wsgi:application
I have a working sample site with the file system as such (https://github.com/alvations/APE):
APE
\app
\templates
base.html
index.html
instance.html
__init__.py
hamlet.py
config.py
run.py
I have created a flask project on https://www.pythonanywhere.com and the file system is as such:
/home/alvations/
/Dropbox/
/mysite/
/templates
base.html
index.html
instance.html
flask_app.py
/web2py/
Where do I place my run.py in my pythonanywhere project?
How do I use the same file structure as my the project in my Github on pythonanywhere?
PythonAnywhere dev here -- you don't need a run.py on PythonAnywhere. The code that normally goes in there is to run a local Flask server that can serve your app -- that's all handled for you by our system.
Instead, you need to change the WSGI file (linked from the "Web" tab) to import the appropriate application module. So, because the sample site you have on github does
from app import app
app.run(debug=True)
...on PythonAnywhere in the WSGI file you'll need to do this:
from app import app as application
One thing to be aware of -- if I'm understanding your file listings above correctly, you don't have all of the github app installed -- only the templates. You'll need __init__.py, hamlet.py, and config.py, and they'll need to be in the same directory structure as the original.
After successfully deploying a test app using the steps outlined here:
http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_Python_flask.html
I tried to deploy my actual flask application which has the following structure:
myApp/
runServer.py
requirements.txt
myApp/
__init__.py
helpers.py
clean.sh
static/
myApp.css
handlers/
__init__.py
views.py
templates/
layout.html
viewOne.html
viewTwo.html
Where views.py contains my url mappings.
I have tried initializing the eb instance in the root directory as well as within the myApp module and git aws.push but I get the following error on the AWS dashboard:
ERROR Your WSGIPath refers to a file that does not exist. and the application does not work (404 for any path).
How can I deploy the above Flask application to elastic beanstalk?
I encountered a similar problem deploying a Flask application to EB, with a similar directory structure, and had to do 2 things:
Update my manage.py to create an object of name application, not app
import os
from application import create_app, db
from flask.ext.script import Manager, Shell
application = create_app(os.getenv('FLASK_CONFIG') or 'default')
manager = Manager(application)
Create .ebextensions/myapp.config, and define the following block to point to manage.py
option_settings:
"aws:elasticbeanstalk:container:python":
WSGIPath: manage.py
"aws:elasticbeanstalk:container:python:staticfiles":
"/static/": "application/static/"
This let Elastic Beanstalk find the application callable correctly.
This is described briefly at the official docs, and is described in more detail in this blog post
EDIT - see project structure below
ProjectRoot
.ebextensions
application.config
application
main
forms.py
views.py
static
templates
tests
manage.py
requirements.txt
config.py
etc, etc
Add the following to .ebextensions/<env-name>.config:
option_settings:
"aws:elasticbeanstalk:container:python":
WSGIPath: myApp/handlers/views.py
Update:
If you don't have .ebextensions directory, please create one for the project. You can find more information of what can be done regarding the container configuration in Customizing and Configuring AWS Elastic Beanstalk Environments guide.
Your WSGIPath refers to a file that does not exist.
This error appears because Beanstalk, by default, looks for application.py. Check at Beanstalk web UI, Configuration > Software Configuration, WSGIPath is mapped to application.py
Update the WSGIPath as shown in the previous replies or rename to application.py file.
As of awsebcli 3.0, you can actually edit your configuration settings to represent your WSGI path via eb config. The config command will then pull (and open it in your default command line text editor, i.e nano) an editable config based on your current configuration settings. You'll then search for WSGI and update it's path that way. After saving the file and exiting, your WSGI path will be updated automatically.
WSGI configuration was painful for me. I did changed WSCI settings using eb config command but it did not work. Below you can fix this in 5 easy steps.
1- Moved app.py function to the root of the directory (where I runned eb init command.
2- Also renamed app.py as application.py and in that initilized application as application = Flask(__name__) not app = Flask(__name__)
3- eb deploy did not worked after this (in the same project) I tried to fix config by using eb config but it was too hairy to sort it out. Delete all .extensions, .gitignore etc from your project.
4- re initialize your project on EB with eb init and follow the prompts. when deployment is done, eb open would launch your webapp (hopefully!)
When I encountered this problem it was because I was using the GUI to upload a zip of my project files. Initially I was zipping the project level directory and uploading that zip to EB.
Then I switched to simply uploading a zip of the project files themselves-ie select all files and send those to a zip-and then the GUI upload utility was able to find my application.py file without a problem because the application.py file was not in a subfolder.
Well, In my case I followed the entire process and conventions but was still getting 404. The problem was my virtual environment. I was ignoring all environment config related folders/files in my .gitignore but not in .ebignore. After creating .ebignore and ignoring all the folders/files which were not related to project code, fixed the issue.
Here is the setup:
Using ngBoilerplate (grunt, bower, angular, the works...) to create a SAP application. On my localhost, it launches a NodeJS server so I can test the app. This all works fine minus the database/apis. Using Grunt, it will create a /build folder (which is all the non-minified source,assets, for debugging) and a /bin folder with the production code.
For the backend I have a Python flask app (which I'll use for REST API's) on Heroku. Inside the main Python script:
#app.route("/")
def index():
#index.html has the angular SAP
return make_response( open('build/index.html').read() )
I push the code to Heroku, it detects a Python app (which I believe is good as I will need Python to make my api requests), and it serves the correct index.html. I see Angular making requests to /vendor/angular.js /css/angular.css etc, when those files technically live in /build/vendor/angular.js.
I'm not sure if I'm suppose to tell Angular where to grab the files or if it's Python related.
Am I suppose to change the DOCROOT (WWW) like in LAMP land?
Do I change the routeprovider/urlrouterprovider in Angular to tell it to serve the files to a different location?
Or do I change what I'm doing in Python?
The project directory looks like:
hellworld.py
requirements.txt
runp-heroku.py
procfile
Gruntfile.js
build/ //test code
assets/
index.html
vendor/
bin/ //production code
assets/
index.html
vendor/
src/ //original code
assets/
index.html
vendor/
I never used Heroku, I usually get the Ubuntu server somewhere in the cloud and setup production manually. But the main point is that you production differs from development and you need a distinct config for production. You have two options:
Configure Flask's static_path
Or configure nginx to serve js/css you've built from the right dir