Python 谷歌云上的Bokeh Flask部署

Python 谷歌云上的Bokeh Flask部署,python,flask,google-cloud-platform,bokeh,Python,Flask,Google Cloud Platform,Bokeh,我正试图通过Flask将我的Bokeh仪表板部署到Google云。我试图将Bokeh仪表板嵌入Flask网站中,但无法将其从localhost上取下以正确部署它。我一直在寻找一个典型的例子,但还没有看到一些简单的东西,以便我可以推断出一个更复杂的系统 我的git hub存储库的当前文件结构如下: app.yaml requirements.txt bokeh-sliders.py hello.py templates/ hello.html 我的bokeh-sliders.py文件是

我正试图通过Flask将我的Bokeh仪表板部署到Google云。我试图将Bokeh仪表板嵌入Flask网站中,但无法将其从
localhost
上取下以正确部署它。我一直在寻找一个典型的例子,但还没有看到一些简单的东西,以便我可以推断出一个更复杂的系统

我的git hub存储库的当前文件结构如下:

app.yaml
requirements.txt
bokeh-sliders.py
hello.py
templates/
     hello.html
我的bokeh-sliders.py文件是

import numpy as np

from bokeh.io import curdoc
from bokeh.layouts import row, widgetbox
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Slider, TextInput
from bokeh.plotting import figure

# Set up data
N = 200
x = np.linspace(0, 4*np.pi, N)
y = np.sin(x)
source = ColumnDataSource(data=dict(x=x, y=y))


# Set up plot
plot = figure(plot_height=400, plot_width=400, title="my sine wave",
              tools="crosshair,pan,reset,save,wheel_zoom",
              x_range=[0, 4*np.pi], y_range=[-2.5, 2.5])

plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)


# Set up widgets
text = TextInput(title="title", value='my sine wave')
offset = Slider(title="offset", value=0.0, start=-5.0, end=5.0, step=0.1)
amplitude = Slider(title="amplitude", value=1.0, start=-5.0, end=5.0)
phase = Slider(title="phase", value=0.0, start=0.0, end=2*np.pi)
freq = Slider(title="frequency", value=1.0, start=0.1, end=5.1)


# Set up callbacks
def update_title(attrname, old, new):
    plot.title.text = text.value

text.on_change('value', update_title)

def update_data(attrname, old, new):

    # Get the current slider values
    a = amplitude.value
    b = offset.value
    w = phase.value
    k = freq.value

    # Generate the new curve
    x = np.linspace(0, 4*np.pi, N)
    y = a*np.sin(k*x + w) + b

    source.data = dict(x=x, y=y)

for w in [offset, amplitude, phase, freq]:
    w.on_change('value', update_data)


# Set up layouts and add to document
inputs = widgetbox(text, offset, amplitude, phase, freq)

curdoc().add_root(row(inputs, plot, width=800))
curdoc().title = "Sliders"
我的hello.py文件是

from flask import Flask, flash, redirect, render_template, request, session, abort
from bokeh.embed import server_document

app = Flask(__name__)

@app.route("/")
def hello():
    script=server_document("http://localhost:5006/bokeh-sliders")
    print(script)
    return render_template('hello.html',bokS=script)

if __name__ == "__main__":
    app.run()
我的嵌套hello.html文件是

<html>
<head>
    <title>Website</title>
<style>
@import url(http://fonts.googleapis.com/css?family=Amatic+SC:700);
body{
    text-align: center;
}
h1{
    font-family: 'Amatic SC', cursive;
    font-weight: normal;
    color: #8ac640;
    font-size: 2.5em;
}
</style>

</head>
<body>
 <p>Flask embedding Bokeh test</p>
{{ bokS|indent(4)|safe }}

</body>
</html>

因此,Bokeh服务可以工作,但没有嵌入,因此无法部署它。

我推断您正在尝试在App Engine中部署此应用程序

请参阅前面的内容,了解在App Engine上使用Bokeh和Numpy的更多限制

另请参阅本文档以了解有关应用内引擎标准的更多信息

本文档旨在进一步了解AppEngine Flex的beta功能


总之,由于对持久连接的限制,在App Engine上部署需要套接字连接的应用可能很棘手。您最好使用一个计算引擎实例为您的应用程序提供服务(或Kubernetes,具体取决于您的用例,这里有一个关于如何创建的示例)

为了部署到Google云平台,您必须创建一个自定义flex环境。这意味着必须包含Dockerfile。下面是一个Git存储库的示例,它将

这是Dockerfile

FROM continuumio/miniconda
ENV BK_VERSION=1.4.0 ENV PY_VERSION=3.7 ENV NUM_PROCS=4 ENV BOKEH_RESOURCES=cdn
RUN apt-get install git bash    
RUN git clone https://github.com/BryceWayne/CMCDashboard.git
RUN cd CMCDashboard 
RUN conda install --yes --quiet python=${PY_VERSION} pyyaml jinja2 bokeh=${BK_VERSION} numpy "nodejs>=8.8" pandas requests scikit-learn matplotlib lxml
RUN conda install -c anaconda lxml
RUN conda clean -ay
EXPOSE 8080
CMD bokeh serve --port 8080 \
    --allow-websocket-origin="*" \
    --num-procs=${NUM_PROCS} \
    CMCDashboard/dashboard.py
这是app.yaml文件

runtime: custom
env: flex
仪表板与上面相同,因此我们可以使用sliders.py作为参考

import numpy as np

from bokeh.io import curdoc
from bokeh.layouts import row, widgetbox
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Slider, TextInput
from bokeh.plotting import figure

# Set up data
N = 200
x = np.linspace(0, 4*np.pi, N)
y = np.sin(x)
source = ColumnDataSource(data=dict(x=x, y=y))


# Set up plot
plot = figure(plot_height=400, plot_width=400, title="my sine wave",
              tools="crosshair,pan,reset,save,wheel_zoom",
              x_range=[0, 4*np.pi], y_range=[-2.5, 2.5])

plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)


# Set up widgets
text = TextInput(title="title", value='my sine wave')
offset = Slider(title="offset", value=0.0, start=-5.0, end=5.0, step=0.1)
amplitude = Slider(title="amplitude", value=1.0, start=-5.0, end=5.0)
phase = Slider(title="phase", value=0.0, start=0.0, end=2*np.pi)
freq = Slider(title="frequency", value=1.0, start=0.1, end=5.1)


# Set up callbacks
def update_title(attrname, old, new):
    plot.title.text = text.value

text.on_change('value', update_title)

def update_data(attrname, old, new):

    # Get the current slider values
    a = amplitude.value
    b = offset.value
    w = phase.value
    k = freq.value

    # Generate the new curve
    x = np.linspace(0, 4*np.pi, N)
    y = a*np.sin(k*x + w) + b

    source.data = dict(x=x, y=y)

for w in [offset, amplitude, phase, freq]:
    w.on_change('value', update_data)


# Set up layouts and add to document
inputs = widgetbox(text, offset, amplitude, phase, freq)

curdoc().add_root(row(inputs, plot, width=800))
curdoc().title = "Sliders"

您是否将要嵌入Bokeh应用程序的域列入白名单,其中包含
--允许websocket源代码
?GCP是否配置为代理/转发WebSocket?当浏览器尝试连接时,Bokeh服务器的控制台输出是什么?当浏览器尝试连接时,JS控制台在浏览器中的输出是什么?我将此作为参考,并使用
--allow websocket origin=*
。此外,我编辑了我的帖子,以包含您询问的信息。这些日志是真实部署尝试的日志吗?我问的是在实际部署中会发生什么。确切地说,报告502是什么/在哪里?i、 e.前面是否有nginx代理或类似代理?它的日志显示了什么?这似乎是一个配置问题,而不是代码问题,但这里没有足够的信息来推测我刚才所说的:nginx日志。我不使用GCP,所以我不能帮你找出如何获得它们。但是您看到的实际502来自nginx,因此找到总体答案意味着了解nginx返回502的原因。谢谢您的回复。我已经完成了Bokeh+BigQuery教程,但它不起作用。我遵循了教程,但它似乎不能正常工作。你说它不能正常工作是什么意思?你是不是陷入了困境?您是否看到任何错误消息?
import numpy as np

from bokeh.io import curdoc
from bokeh.layouts import row, widgetbox
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Slider, TextInput
from bokeh.plotting import figure

# Set up data
N = 200
x = np.linspace(0, 4*np.pi, N)
y = np.sin(x)
source = ColumnDataSource(data=dict(x=x, y=y))


# Set up plot
plot = figure(plot_height=400, plot_width=400, title="my sine wave",
              tools="crosshair,pan,reset,save,wheel_zoom",
              x_range=[0, 4*np.pi], y_range=[-2.5, 2.5])

plot.line('x', 'y', source=source, line_width=3, line_alpha=0.6)


# Set up widgets
text = TextInput(title="title", value='my sine wave')
offset = Slider(title="offset", value=0.0, start=-5.0, end=5.0, step=0.1)
amplitude = Slider(title="amplitude", value=1.0, start=-5.0, end=5.0)
phase = Slider(title="phase", value=0.0, start=0.0, end=2*np.pi)
freq = Slider(title="frequency", value=1.0, start=0.1, end=5.1)


# Set up callbacks
def update_title(attrname, old, new):
    plot.title.text = text.value

text.on_change('value', update_title)

def update_data(attrname, old, new):

    # Get the current slider values
    a = amplitude.value
    b = offset.value
    w = phase.value
    k = freq.value

    # Generate the new curve
    x = np.linspace(0, 4*np.pi, N)
    y = a*np.sin(k*x + w) + b

    source.data = dict(x=x, y=y)

for w in [offset, amplitude, phase, freq]:
    w.on_change('value', update_data)


# Set up layouts and add to document
inputs = widgetbox(text, offset, amplitude, phase, freq)

curdoc().add_root(row(inputs, plot, width=800))
curdoc().title = "Sliders"