GradioとStreamlitのアプリをnginxでサブディレクトリにルーティングさせる
Posted On 2024-01-15
1つのドメイン直下にサブディレクトリを作り、複数のGradio、Streamlitのアプリを配置するパターンをコンテナベースで実装してみます。nginxによるリバースプロキシを使います。
目次
やりたいこと
1つのドメイン直下にサブディレクトリを作り、複数のGradio、Streamlitのアプリを配置したい。
- ドメイン
- /app1/ : Gradioのアプリ1
- /app2/ : Gradioのアプリ2
- /app3/ : Streamlitのアプリ3
として、全部を1個のdocker-composeで起動するというもの
nginxのコンテナにトップのindex.htmlの配信と、各アプリのリバースプロキシの両方を持たせる。
ディレクトリ構造
+ gradio1
+ src
- app.py
- Dockerfile
- requirements.txt
+ gradio2
+ src
- app.py
- Dockerfile
- requirements.txt
+ streamlit1
+ src
- app.py
- Dockerfile
- requirements.txt
+ nginx
- default.conf
- Dockerfile
- index.html
- docker-compose.yaml
動かしてみる
docker-compose.yamlのあるディレクトリで起動
docker-compose build
docker-compose up
上からトップページ、「/app1/」、「/app2/」、「/app3/」のサブディレクトリ
コード
docker-compose
services:
reverse_proxy:
build: nginx
image: multiple_image_nginx
stdin_open: true
tty: true
ports:
- "5001:80"
extra_hosts:
- "host.docker.internal:host-gateway"
gradio1:
build: gradio1
image: multiple_image_gradio1
stdin_open: true
tty: true
ports:
- "30001:8080"
environment:
- APP_ENV=docker
- GRADIO_ROOT_PATH=/app1
gradio2:
build: gradio2
image: multiple_image_gradio2
stdin_open: true
tty: true
ports:
- "30002:8080"
environment:
- APP_ENV=docker
- GRADIO_ROOT_PATH=/app2
streamlit1:
build: streamlit1
image: multiple_image_streamlit1
stdin_open: true
tty: true
ports:
- "30003:8080"
gradio1
Dockerfile
FROM ubuntu:22.04
RUN apt-get update
ENV TZ=Asia/Tokyo
ENV LANG=en_US.UTF-8
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get install -yq --no-install-recommends python3-pip \
python3-dev \
build-essential \
openssh-server \
git \
wget \
tzdata && apt-get upgrade -y && apt-get clean
RUN ln -s /usr/bin/python3 /usr/bin/python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
EXPOSE 8080
COPY src /src
WORKDIR /src
ENTRYPOINT ["python", "app.py"]
マウントとか使えばもっとスマートにできるけど、とりあえずこれで動くからOKということで
requirements.txt
gradio==4.14.0
src/app.py
import gradio as gr
import os
with gr.Blocks() as demo:
gr.Markdown("# This is App 1")
gr.Button("Click me", variant="primary")
if __name__ == "__main__":
if "APP_ENV" in os.environ.keys():
demo.launch(server_port=8080, server_name="0.0.0.0")
else:
demo.launch()
gradio2
Dockerfile
gradio1と同じなので省略
requirements.txt
gradio1と同じなので省略
src/app.py
import gradio as gr
import os
with gr.Blocks() as demo:
gr.Markdown("# This is App 2")
gr.Button("Click me", variant="primary")
if __name__ == "__main__":
if "APP_ENV" in os.environ.keys():
demo.launch(server_port=8080, server_name="0.0.0.0")
else:
demo.launch()
streamlit1
Dockerfile
FROM ubuntu:22.04
RUN apt-get update
ENV TZ=Asia/Tokyo
ENV LANG=en_US.UTF-8
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get install -yq --no-install-recommends python3-pip \
python3-dev \
build-essential \
openssh-server \
git \
wget \
tzdata && apt-get upgrade -y && apt-get clean
RUN ln -s /usr/bin/python3 /usr/bin/python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
EXPOSE 8080
COPY src /src
WORKDIR /src
ENTRYPOINT ["streamlit", "run", "app.py", "--server.port=8080", "--server.address=0.0.0.0"]
requirements.txt
streamlit==1.30.0
src/app.py
import streamlit as st
def main():
st.markdown("# This is App 3")
st.button("Click me")
if __name__ == "__main__":
main()
nginx
Dockerfile
FROM nginx:latest
COPY default.conf /etc/nginx/conf.d/default.conf
COPY index.html /var/www/html/index.html
default.conf
server {
listen 80;
server_name localhost;
location / {
root /var/www/html;
index index.html;
}
location /app1/ {
proxy_pass http://host.docker.internal:30001/;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
location /app2/ {
proxy_pass http://host.docker.internal:30002/;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
location /app3/ {
proxy_pass http://host.docker.internal:30003/;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
docker-compose.yamlでextra_hosts: - "host.docker.internal:host-gateway"
を指定し、ホスト側のポートを読めるようにしておいて、default.confでhttp://host.docker.internal:30001/
のようにするのがポイント。
index.html
<html>
<body>
<h1>App 1</h1>
<a href="./app1/">link</a>
<h1>App 2</h1>
<a href="./app2/">link</a>
<h1>App 3</h1>
<a href="./app3/">link</a>
</body>
</html>
参考情報
- 【docker-compose】nginxでリバースプロキシを実装する
- [初心者向け] Nginxの設定ファイルの書き方について
- nginxをインストールしてオリジナルのhtmlを表示させるまで
- 【Techの道も一歩から】第47回「StreamlitのアプリをNginxで複数ホスティングする」
- Nginx について纏めてみる
- Running a Gradio App on your Web Server with Nginx
Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内
技術書コーナー
北海道の駅巡りコーナー