#python-3.x #docker #flask #tensorflow-serving
Вопрос:
У меня есть очень простое приложение Flask, и я обучил модель делать выводы на изображениях, поэтому я хочу иметь возможность запускать их оба одновременно через docker-compose. Вот как docker-compose.yml
выглядит мой файл
version: "2"
services:
molo:
build:
context: ./
dockerfile: molo/Dockerfile
ports:
- 8003:8003
tensorflow-serving:
image: tensorflow/serving
ports:
- 8500:8500
- 8501:8501
volumes:
- './models:/models'
command:
- '--model_config_file=/models/models.config'
- '--model_config_file_poll_wait_seconds=60'
- '--allow_version_labels_for_unavailable_models=true'
molo
это глупое название, которое я дал сервису приложений Flask. Также здесь находится файл Dockerfile для приложения Flask.
FROM python:3.8-slim-buster
COPY ./molo/ /molo
COPY ./requirements.txt requirements.txt
COPY ./utilities /utilities
RUN python3 -m pip install --upgrade pip
RUN python3 -m pip install -r requirements.txt
RUN python3 -m pip install utilities/
ENV FLASK_DEBUG=False
EXPOSE 8003
RUN ["chmod", " x", "/molo/entrypoint.sh"]
ENTRYPOINT ["/molo/entrypoint.sh"]
Вот в чем дело. Когда я запускаю docker-compose up --build
обе службы, они запускаются без проблем. Я могу получить доступ к приложению flask и отправлять запросы через gRPC в службу обслуживания TensorFlow через консоль python. Однако, когда я пытаюсь попасть в конечную точку в приложении Flask, которое должно делать то же самое, что я делаю в консоли, я получаю кучу InactiveRPC
ошибок и не могу понять, почему это не сработает. Я предполагаю, что, возможно, я указываю неправильный адрес, но это всего лишь предположение.
Вот содержимое приложения Flask (на данный момент это всего один файл).
import os
import grpc
import simplejson as json
from dotenv import load_dotenv
from flask import Flask
from tensorflow_serving.apis import predict_pb2, get_model_metadata_pb2, prediction_service_pb2_grpc
from tensorflow_serving.apis.model_pb2 import ModelSpec
from google.protobuf.json_format import MessageToJson
from utilities.route_decorators import status_code_decorator
load_dotenv()
app = Flask(__name__)
MODEL_URI = "0.0.0.0:8500"
@app.route("/", methods=['GET'])
@status_code_decorator
def home():
return "Welcome to Molo!"
@app.route("/molo/info/<model_name>", defaults={"model_name": "dense_net"}, methods=["GET"])
@status_code_decorator
def molo_info(
model_name: str
):
channel = grpc.insecure_channel(MODEL_URI)
stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)
model_spec = ModelSpec(name=model_name, signature_name="serving_default")
request = get_model_metadata_pb2.GetModelMetadataRequest(model_spec=model_spec)
request.metadata_field.append("signature_def")
result = stub.GetModelMetadata(request, 5.0)
metadata = json.loads(MessageToJson(result))
return metadata
@app.route("/molo/predict", methods=["GET"])
@status_code_decorator
def molo_predict():
return {"prediction": "some label"}
if __name__ == "__main__":
app.run(
host=os.environ.get("FLASK_HOST", "0.0.0.0"),
port=os.environ.get("FLASK_PORT", 8003),
debug=os.environ.get("FLASK_DEBUG", True)
)
Если кто-нибудь испытывал что-то подобное или, возможно, знает, что я делаю не так, я был бы очень благодарен, так как я провел целый день, вероятно, просто пытаясь понять это.
Редактировать
Вот пример ошибки, которую я получаю.
grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
molo_1 | status = StatusCode.UNAVAILABLE
molo_1 | details = "failed to connect to all addresses"
molo_1 | debug_error_string = "{"created":"@1621306525.139840351","description":"Failed to pick subchannel","file":"src/core/ext/filters/client_channel/client_channel.cc","file_line":4133,"referenced_errors":[{"created":"@1621306525.139835546","description":"failed to connect to all addresses","file":"src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc","file_line":397,"grpc_status":14}]}"
Комментарии:
1. Когда вы устанавливаете
MODEL_URI='0.0.0.0:8500'
, вы говорите своему приложению попытаться подключиться к «везде», чтобы найти сервер модели; на самом деле это не имеет смысла. Вы читали такие материалы, как Создание сетей в Compose , в документации Docker, в которой описывается, какие имена хостов необходимы для подключения между контейнерами?