Deploying Dash to Google App Engine


#1

@dbill I saw you posted about deploying dash to google cloud, was wondering if you had a github or somewhere I could see the structure of your app?

I’m trying to deploy an app using a mix of the dash deployment process and the google app engine flask deployment process but just end up with a google development webpage showing instances and a menu on the left.

I’ve been trying in a virtual environment and have an app.yaml, appengine_config.py, main.py, requirements.txt and lib folder but can’t seem to get it to deploy correctly.

Any suggestions of anything you did different to the standard google app engine flash deployment would be awesome to know.


#2

Hi. I haven’t done anything fancy yet, but have been able to deploy a simple one file Dash app to the Google Cloud. This app accesses my Google MySQL database. My strategy was to… take a simple Dash app that was working standalone on my PC and get it to work in my local virtual environment and then deploy it to get it work in Google Cloud. Once that was working I then added functionality that would pull data from my cloud database and display it.


#3

@dbill just like @bemur I’d be extremely grateful if you were willing to share the code you used to deploy this to Google Cloud. My website is hosted on Google Cloud, but I’m not very good with these app engines and deployments yet. Seeing example code would be so helpful - my goal is to deploy Plotly Dash dashboards to Google Cloud and then create hyperlinks that are like www.mydomain.com/client1, www.mydomain.com/client2, etc.


#4

Hey @bld2014 I eventually got a dash app to deploy, I had to use the flexible environment because of the packages I was using (if you need pandas you’ll need to use the flexible app engine environment). Here’s the gist of my code.

app.yaml: Here I had to use main:server as server is the flask instance, rather than main:app which you might see on the google app engine tutorials.

runtime: python
env: flex
entrypoint: gunicorn -b :$PORT main:server

runtime_config:
  python_version: 2

# This sample incurs costs to run on the App Engine flexible environment. 
# The settings below are to reduce costs during testing and are not appropriate
# for production use. For more information, see:
# https://cloud.google.com/appengine/docs/flexible/python/configuring-your-app-with-app-yaml
manual_scaling:
  instances: 1
resources:
  cpu: 1
  memory_gb: 0.5
  disk_size_gb: 10

main.py:

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import numpy as np
import pandas as pd
from pandas.io import gbq
from flask import Flask


server = Flask(__name__)
app = dash.Dash(__name__, server=server)
app.scripts.config.serve_locally = True
app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})

app.layout = html.Div(...)

@app.callback(...)
def update_figure():


if __name__ == '__main__':
	app.run_server()

requirements.txt:

Flask==0.12.2
gunicorn==19.7.1
dash==0.18.3
dash-core-components==0.12.5
dash-html-components==0.7.0
dash-renderer==0.9.0
plotly==2.2.3
numpy==1.13.3
pandas==0.19.2

If you follow the google app engine flexible guides that should give you most of the process like creating virtual environments and installing packages from requirements.txt etc. You don’t need to copy libraries into a lib folder as in the standard environment when in the flexible environmnent though.

I’m not an expert but this worked for me, hopefully it helps you get going too.


#5

This is great, thank you! I think I understand it, I am going to try this in the next week or so and if I have issues I hope it’s okay if I post again on this thread.


#6

EDIT!: I forgot to change app.yaml to main:server as you said! Re-deploying now and seeing if it works, my last message (below) might be irrelevant!

@bemur Thank you again for posting this! This was unbelievably helpful. I have made a lot of progress but the app still won’t deploy.

I have everything exactly the way that you do except I had to use a more recent version of Pandas in requirements.txt since I use a datetime and it wasn’t deploying because of that before. And of course I have my own code replacing:

app.scripts.config.serve_locally = True
app.css.append_css({"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"})

app.layout = html.Div(...)

@app.callback(...)
def update_figure():

This is the error I am getting:

Updating service [default] (this may take several minutes)...failed.                                    
ERROR: (gcloud.app.deploy) Error Response: [9] 
Application startup error:
[2017-12-26 17:02:01 +0000] [1] [INFO] Starting gunicorn 19.7.1
[2017-12-26 17:02:01 +0000] [1] [INFO] Listening at: http://0.0.0.0:8080 (1)
[2017-12-26 17:02:01 +0000] [1] [INFO] Using worker: sync
[2017-12-26 17:02:01 +0000] [7] [INFO] Booting worker with pid: 7
Application object must be callable.
[2017-12-26 17:02:09 +0000] [7] [INFO] Worker exiting (pid: 7)
[2017-12-26 17:02:09 +0000] [1] [INFO] Shutting down: Master
[2017-12-26 17:02:09 +0000] [1] [INFO] Reason: App failed to load.

I googled it and found this SO article. I don’t fully understand what the article is saying, but did you wind up editing any other files or doing something similar to what is in this article?

Thank you again,
Barb


#7

@bemur please ignore my last post, after making that change that I missed the first time (main:server in app.yaml) it successfully deployed!

Again, uber thank you’s for your original post with the gist of your code!!

Barb


#8

Hey Bemur! Curious how much your monthly cost using Flexible App Engine are with Dash? Big bummer that Pandas cannot be used on Standard as the cost would be significantly less.


#9

Hey @syphon5 I am currently on the free year with 300USD credit from Google, but I just checked and it looks like it’s costing about 50USD/month with the settings I had in that yaml file above. I’m changing my settings to match this: https://medium.com/google-cloud/three-simple-steps-to-save-costs-when-prototyping-with-app-engine-flexible-environment-104fc6736495 (except changing CPU to 0.2 and memory to 0.5 as per one of the comments).
And since I’m not running a permanent app yet I’ll deploy using dev mode too so hopefully that reduces the cost a fair bit.


#10

Just wanted to chime in with thanks for sharing your experience, @bemur. It made getting up and running on Google App Engine really straightforward for me!


#11

Hi, just wondering if anyone got a Dash app to deploy on the Standard environment? Is it even possible?
Asking mainly because of the free tier… thanks!


#12

It’s possible to deploy on Standard for sure, even if you have Pandas.
The app.yaml will just have the runtime as python37, and the same gunicorn entrypoint as discussed above.
runtime: python37
entrypoint: gunicorn -b :$PORT main:server

Edited: if you’re using python 2.7 you can also use runtime as python27


#13

Great! You have deployed it successfully like that before?


#14

Yes! And they have updated GAE standard to use a requirements.txt file, rather than the more complicated lib folder from the past.


#15

Alright, many thanks!


#16

@a.fraser may you please share a full example of your app.yaml and main.py? (in this one I’m specially interested in seeing how the server, app and port variables are managed). It would help me a lot

I have followed the previous points for deploying on standard environment but have been unsuccessful :frowning:


#17

I can’t share my specific files since they are for work, but I’ve tweaked a simple Dash example that should give you everything you need.

main.py:

import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
from pandas_datareader import data as web
from datetime import datetime as dt
import flask


server = flask.Flask(__name__)
app = dash.Dash(__name__, server=server)


app.layout = html.Div([
    html.H1('Stock Tickers'),
    dcc.Dropdown(
        id='my-dropdown',
        options=[
            {'label': 'Coke', 'value': 'COKE'},
            {'label': 'Tesla', 'value': 'TSLA'},
            {'label': 'Apple', 'value': 'AAPL'}
        ],
        value='COKE'
    ),
    dcc.Graph(id='my-graph')
])

@app.callback(Output('my-graph', 'figure'), [Input('my-dropdown', 'value')])
def update_graph(selected_dropdown_value):
    df = web.DataReader(
        selected_dropdown_value, data_source='iex',
        start=dt(2017, 1, 1), end=dt.now())
    return {
        'data': [{
            'x': df.index,
            'y': df.close
        }]
    }



if __name__ == "__main__":
    app.run_server(debug=True, port=8080)

app.yaml:

runtime: python37
instance_class: F2
entrypoint: gunicorn -b :$PORT main:server

I hope this helps!


#18

@a.fraser thanks for sharing. I could make it to work thanks to you. It works as well if the server variable is an instance of dash.Dash().server

Just for anyone that checks this thread in the future, if you’re using standard environment with dash AND Pandas/Numpy, make sure you get the 1gb memory instance. Otherwise it will have a lot of memory problems…

In your app.yaml file: instance_class: F4_1G