Невозможно запустить BaseHTTPServer в Docker - PullRequest
0 голосов
/ 30 апреля 2018

У меня есть следующий код на Python, где я написал простой HTTP-сервер, расширяя HTTPBaseServer:

class ApiError(Exception):
    def __init__(self, code, msg=None, desc=None):
        self.code = code
        self.msg = msg
        self.desc = desc

    def __str__(self):
        return f"ApiError({self.code}, {self.msg})"


def ApiRoute(path):
    def outer(func):
        if not hasattr(func, "_routes"):
            setattr(func, "_routes", [])
        func._routes += [path]
        return func
    return outer


class ApiServer(HTTPServer):
    def __init__(self, addr, port):
        server_address = (addr, port)
        self.__addr = addr

        class handler_class(ApiHandler):
            pass

        self.handler_class = handler_class

        # routed methods map into handler
        for meth in type(self).__dict__.values():
            if hasattr(meth, "_routes"):
                for route in meth._routes:
                    self.add_route(route, meth)

        super().__init__(server_address, handler_class)

    def add_route(self, path, meth):
        self.handler_class._routes[path] = meth

    def port(self):
        "Get my port"
        sa = self.socket.getsockname()
        return sa[1]

    def address(self):
        "Get my ip address"
        sa = self.socket.getsockname()
        return sa[0]

    def uri(self, path):
        "Make a URI pointing at myself"
        if path[0] == "/":
            path = path[1:]
        return "http://"+self.__addr + ":"+ str(self.port()) + "/" + path

    def shutdown(self):
        super().shutdown()
        self.socket.close()


class ApiHandler(BaseHTTPRequestHandler):
    _routes={}

    def do_GET(self):
        self.do_XXX()

    def do_XXX(self, info={}):
        url=urlparse.urlparse(self.path)

        handler = self._routes.get(url.path)

        if handler:
            response=handler(info)
            self.send_response(200)
            response = json.dumps(response)
            response = bytes(str(response),"utf-8")
            self.send_header("Content-Length", len(response))
            self.end_headers()
            self.wfile.write(response)


class MyServer(ApiServer):
    @ApiRoute("/popup")
    def popup(req):
        return "HERE"


httpd = MyServer('127.0.0.1', 5000)
print("serving on ", httpd.address(), httpd.port())
threading.Thread(target=httpd.serve_forever).start()

Выше отлично работает, когда я,

python serv.py

на терминале.

Однако я хочу запустить это в контейнере докера. Dockerfile выглядит так:

FROM python:3.6-alpine3.7

COPY . /serv

WORKDIR /serv

ENTRYPOINT ["python"]
CMD ["serv.py"]

Затем я создаю образ Docker, используя:

сборка докера. -t custom-serv

И запустить его как контейнер, используя:

docker run --rm -p 5000: 5000 custom-serv

Я получаю сообщение журнала, указывающее на успешный запуск сервера, однако указатель на URL возвращает следующее:

curl: (56) Ошибка записи: сброс соединения по одноранговому каналу

Я понимаю, что есть много рамок, которые могут упростить жизнь, однако это скорее эксперимент, который я проводил, и было бы здорово, если бы кто-то мог указать мне правильное направление!

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

Ваш сервер прослушивает localhost и не отвечает ни на какие другие соединения, кроме localhost. Если бы вы подключились к вашему серверу из в контейнере, это бы сработало. Но для подключения извне необходимо назначить серверу прослушивание всех соединений из всех доступных мест.

Следовательно, вам нужно изменить

httpd = MyServer('127.0.0.1', 5000)

до

httpd = MyServer('0.0.0.0', 5000)
0 голосов
/ 30 апреля 2018

Измените эту строку:

httpd = MyServer('127.0.0.1', 5000)

до:

httpd = MyServer('0.0.0.0', 5000)

О разнице: https://www.howtogeek.com/225487/what-is-the-difference-between-127.0.0.1-and-0.0.0.0/

...