簡體   English   中英

在 Google Cloud 上部署 Bokeh Flask

[英]Bokeh Flask Deployment on Google Cloud

我正在嘗試通過 Flask 將我的 Bokeh 儀表板部署到 Google Cloud。 我正在嘗試將 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>

我知道這可能是 MWE 的一些代碼,但是,這是我迄今為止所做的。 還有一個 app.yaml 文件和一個 requirements.txt 文件,但我不知道他們是否有必要回答這個問題。

如果我運行python hello.py然后我可以查看交互式文檔但是如果我嘗試部署應用程序然后我收到 502 Bad Gateway 錯誤。 關於通過server_document正確部署 Bokeh 儀表板,我是否遺漏了什么?

編輯:

當我使用bokeh serve bokeh-sliders.py --allow-websocket-origin=*時,shell 響應是,

(hello_world) brycechudomelka@cloudshell:~/mlcdashboard (mlcdashboard)$ bokeh serve bokeh-sliders.py --allow-websocket-origin=*
2019-08-06 12:53:31,636 Starting Bokeh server version 1.3.2 (running on Tornado 6.0.3)
2019-08-06 12:53:31,638 Host wildcard '*' will allow connections originating from multiple (or possibly all) hostnames or IPs. Use non-wildcard values to restrict access explicitly
2019-08-06 12:53:31,642 Bokeh app running at: http://localhost:5006/bokeh-sliders
2019-08-06 12:53:31,643 Starting Bokeh server with process id: 421
2019-08-06 12:55:38,205 302 GET /?authuser=0 (127.0.0.1) 1.20ms
2019-08-06 12:55:38,694 200 GET /bokeh-sliders (127.0.0.1) 332.15ms
2019-08-06 12:55:39,369 404 GET /favicon.ico (127.0.0.1) 0.91ms
2019-08-06 12:55:39,796 101 GET /bokeh-sliders/ws?bokeh-protocol-version=1.0&bokeh-session-id=70lK44usV1edkGRZmGWWpKMVn3DxhOsUlM5xSqqw6p5p (127.0.0.1) 1.38ms
2019-08-06 12:55:39,797 WebSocket connection opened
2019-08-06 12:55:39,798 ServerConnection created

因此,Bokeh Serve 工作但未嵌入,因此無法部署它。

我推斷您正在嘗試在 App Engine 中部署此應用程序。

請參閱上一個問題以了解有關在 App Engine 上使用 Bokeh 和 Numpy 的限制的更多信息。

另請參閱此文檔以了解有關在 App 引擎標准中使用套接字限制的更多信息。

以及此文檔以了解有關 App Engine Flex 允許Websockets 連接beta功能的更多信息。

總之,由於持久連接的限制,在 App Engine 上部署需要套接字連接的應用程序可能會很棘手。 您最好使用 Compute Engine Instance 來為您的應用程序提供服務(或 Kubernetes,具體取決於您的用例,這是關於如何使用 Bokeh 和 BigQuery創建自定義交互式儀表板的示例)

為了部署到 Google Cloud Platform,您必須創建一個自定義的 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

並且dashboard和上面一樣,所以我們可以參考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"

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM