Не удается подключиться к серверу Go в контейнере Docker

#docker #go #networking #ubuntu-20.04

#docker #Вперед #сеть #ubuntu-20.04

Вопрос:

Я пытаюсь запустить HTTP-сервер, написанный на Golang внутри контейнера docker, и я продолжаю получать отказ в подключении. Все выполняется внутри виртуальной машины сервера Ubuntu 20.04, работающей на моем компьютере с Windows 10.

Код сервера Go:

 package main

import "github.com/lkelly93/scheduler/internal/server"

func main() {
    server := server.NewHTTPServer()
    server.Start(3000)
}
  
 package server

import (
    "context"
    "fmt"
    "net/http"
)

type HTTPServer interface {
    Start(port int) error

    Stop() error
}

func NewHTTPServer() HTTPServer {
    return amp;httpServer{}
}

type httpServer struct {
    server *http.Server
}

func (server *httpServer) Start(port int) error {
    serveMux := newServeMux()
    server.server = amp;http.Server {
        Addr: fmt.Sprintf(":%d", port),
        Handler: serveMux,
    }
    return server.server.ListenAndServe()
}

func (server *httpServer) Stop() error {
    return server.server.Shutdown(context.Background())
}
  

Мой файл Dockerfile:

 FROM ubuntu:20.04

RUN apt-get update -y

#Install needed packages
RUN apt-get install software-properties-common -y
RUN apt-get install python3 -y
RUN apt-get update -y 
RUN apt-get install python3-pip -y
RUN apt-get install default-jre -y

#Install language dependacies
    #Python
    RUN pip3 install numpy

#Reduce VM size
# RUN rm -rf /var/lib/apt/lists/*

#Setup working DIRs
RUN mkdir secure
RUN mkdir secure/runner_files

COPY scheduler /secure
WORKDIR /secure

EXPOSE 3000

CMD ["./scheduler"] <-- The go server is compiled into a binary called scheduler
  

Я создаю данный файл Dockerfile, а затем запускаю:

 docker run -d --name scheduler -p 3000:3000 scheduler:latest
  

Затем я беру адрес контейнера с:

 docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' scheduler
->172.17.0.2
  

Наконец, я использую cURL для отправки http-запроса:

 curl http://172.17.0.2:3000/execute/python --data '{"Code":"print("Hello")"}'
  

Я получаю

 curl: (7) Failed to connect to 172.17.0.2 port 3000: Connection refused
  

но должен получать

 {"Stdout":"Hellon"}%
  

Если я запускаю сервер Go на виртуальной машине Ubuntu, у меня нет проблем с вызовом его с моего компьютера Win10, но, похоже, я не могу вызвать сервер Go, когда он существует внутри контейнера docker с компьютера Ubuntu.

Код Go сложнее, чем просто это, но его слишком много, чтобы публиковать все здесь, не стесняйтесь просматривать все репозитории наhttps://github.com/lkelly93/scheduler.

В конечном итоге это будет серверная часть веб-сайта, который я хочу создать, который запускает код. Что-то вроде LeetCode или Repl.it .

Спасибо!

Редактировать:

 docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
2a56a973040f        scheduler:latest    "./scheduler"       37 seconds ago      Up 36 seconds       0.0.0.0:3000->3000/tcp   scheduler
  

журналы контейнера docker 2a56a973040f не выдали выходных данных.

Редактировать 2:

 docker run -it --net container:2a56a973040f nicolaka/netshoot ss -lnt
State  Recv-Q Send-Q Local Address:Port Peer Address:PortProcess
LISTEN 0      4096               *:3000            *:*
  

Редактировать 3:

После прочтения справочных страниц я обнаружил, что если бы у меня был тег —network =host для моего изображения, а затем запустить.

 curl http://localhost:3000/execute/python --data '{"Code":"print("Hello")"}'
  

Я получаю правильный вывод. Пока это работает, я хотел бы, чтобы несколько образов docker работали параллельно. Поэтому я бы предпочел использовать IP-адрес для их всех. Поэтому я не думаю, что это постоянное исправление.

Комментарии:

1. docker говорит, что ваш сервер находится на 172.17.0.2, но вы, похоже, используете 172.17.0.1

2. Выполнить копирование неправильной команды. Это должно быть 172.17.0.2, я изменю это.

3. Возможно, это проблема сервера, а не проблема docker. Что выводят журналы сервера?

4. Кроме того, вы пробовали обычный старый localhost?

5. @pygeek Я не думаю, что это сервер, потому что у меня нет проблем, когда я запускаю его вне docker.

Ответ №1:

Чтобы исправить это на моем сервере, я установил IP-адрес 0.0.0.0: 4000. Я использую gin, поэтому пример будет выглядеть так:

 r := gin.Default()
r.run("0.0.0.0:4000")
  

После этого я, наконец, смог получить к нему доступ через свой браузер.

Комментарии:

1. Спасатель жизни. Кто знал, что r.run («localhost: 4000») был моей проблемой с самого начала

2. Я поддерживаю это…. вы заслуживаете медали!

3. r.run(:4000) также работает

Ответ №2:

Вы опубликовали порт, который перенаправляет порт с хоста docker на контейнер. Поэтому вы хотите подключиться к http://localhost:3000 . Подключение к контейнерному IP может завершиться ошибкой при установке на рабочий стол, поскольку docker запускается внутри виртуальной машины, а эти частные IP-адреса видны только в виртуальной машине.

Если вы работаете docker-machine (это относится к более старым установкам docker toolbox), вам нужно будет получить IP-адрес виртуальной машины. Запустите echo $DOCKER_HOST , чтобы увидеть IP-адрес и настроить порт на порт 3000.

Комментарии:

1. Я попробовал это, и я получаю curl: (56) Сбой Recv: сброс соединения одноранговым узлом

2. Когда я запускаю «echo $ DOCKER_HOST», я ничего не получаю. Означает ли это, что я что-то настроил неправильно?

3. @LukeKelly нет, это означает, что вы используете последнюю (за последние несколько лет) версию docker.

4. @LukeKelly контейнер все еще запущен? Включите docker container ls -a в свой вопрос. Также укажите, docker container logs $id где $id находится ваш идентификатор контейнера.

5. Спасибо за вашу помощь! Я добавил запрошенную информацию выше.

Ответ №3:

После дополнительных поисковых запросов я последовал этому руководству и создал свою собственную «определяемую пользователем мостовую сеть».

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

Комментарии:

1. Похоже, что вы запускаете curl из другого контейнера, а не с хоста на опубликованный порт. Сетевые правила сильно отличаются для этого сценария.