您如何对WebSocket服务器进行docker化?

I'm having trouble with putting my WebSocket server in a Docker container.

This is the server code, which writes to a new connection with "connected".

// server.go
func RootHandler(w http.ResponseWriter, r *http.Request) {
    upgrader := websocket.Upgrader{ // (Uses gorilla/websocket)
        ReadBufferSize:  4096,
        WriteBufferSize: 4096,
    }

    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        panic(err)
    }

    if err = conn.WriteMessage(websocket.TextMessage, []byte("connected")); err != nil {
        panic(err)
    }
}

func main() {
    fmt.Println("server is running")

    // For graceful shutdown
    stop := make(chan os.Signal, 1)
    signal.Notify(stop, os.Interrupt)

    server := http.Server{Addr: "localhost:8000"}
    defer server.Close()

    http.HandleFunc("/", RootHandler)

    go func() {
        err := server.ListenAndServe()
        if err != nil && err != http.ErrServerClosed {
            panic(err)
        }
    }()

    <-stop
}

Here is the client:

// client.go
func main() {
    connection, _, err := websocket.DefaultDialer.Dial("ws://localhost:8000", nil)
    if err != nil {
        panic(err)
    }

    _, b, err := connection.ReadMessage()
    if err != nil {
        panic(err)
    }
    fmt.Println(string(b)) // "connected"
}

Running server.go then client.go prints "connected", showing that the code is working. Now I want to put the server in a Docker container. This is dockerfile:

FROM golang:1.11.4-alpine3.8
COPY . $GOPATH/src/websocket-test
WORKDIR $GOPATH/src/websocket-test
RUN ["go", "build", "server.go"]
EXPOSE 8000
CMD ["./server"]

I use these commands to build and start the container, exposing 8000/tcp.

docker build -t websocket-test .
docker run -p 8000:8000 websocket-test

I can confirm that the server is running because it prints "server is running". If I start client.go outside the container, it panics:

panic: read tcp [::1]:60328->[::1]:8000: read: connection reset by peer

What I expect is the same outcome as before—printing "connected" on the client side. The error message means that the server dropped the connection before the handshake. I don't understand the "60328" number. As far as I know, WebSocket doesn't change ports on upgrade, so I should be okay with exposing just 8000.

I do not know what I must change to be able to connect via WebSocket to my server.

duanbi6522
duanbi6522 Docker的可能重复项:在容器中侦听,不在外部应答
一年多之前 回复
doucongqian6644
doucongqian6644 您的服务器需要监听其外部接口,而不是localhost。尝试将服务器代码中的localhost:8000更改为0.0.0.0:8000。
一年多之前 回复

1个回答



当您指定要监听的主机名或IP地址时(在这种情况下为 localhost </ code>解析为< code> 127.0.0.1 </ code>),那么您的服务器将仅侦听该IP地址。</ p>

localhost </ code>上监听并不是您的问题 在Docker容器之外。 如果您的服务器仅侦听 127.0.0.1:8000 </ code>,则您的客户端可以轻松连接至该服务器,因为连接也是通过 127.0.0.1 </ code>进行的。</ p> \ n

在Docker容器中运行服务器时,它只会像以前一样在 127.0.0.1:8000 </ code>上进行侦听。 127.0.0.1 </ code>是本地环回地址,无法在容器外部访问。</ p>

使用 -p 8000启动Docker容器时: 8000 </ code>,它将将前往 127.0.0.1:8000 </ code>的流量转发到容器的IP地址,在我的情况下为 172.17.0.2 </ code>。</ p >

容器在docker0网络接口内获取IP地址(您可以使用 ip addr ls </ code>命令查看)</ p>

,当您的流量转发到 172.17.0.2:8000 </ code>上的容器时,那里没有任何监听,并且连接尝试失败。</ p>

修复:</ h3 >

问题出在侦听地址:</ p>

  server:= http.Server {Addr:“ localhost:8000”} 
</ code > </ pre>

要解决您的问题,请将其更改为</ p>

  server:= http.Server {Addr:“:8000”} 
</ code> </ pre>

这将使您的服务器侦听其所有容器的IP地址。</ p>

其他信息:</ h3>
\ ñ

当 在Docker容器中公开端口后,Docker将创建iptables规则进行实际转发。 看到这个。 您可以使用以下命令查看这些规则:</ p>

  iptables -n -L 
iptables -t nat -n -L
</ code> </ pre>
</ div >

展开原文

原文

When you specify a hostname or IP address​ to listen on (in this case localhost which resolves to 127.0.0.1), then your server will only listen on that IP address.

Listening on localhost isn't a problem when you are outside of a Docker container. If your server only listens on 127.0.0.1:8000, then your client can easily connect to it since the connection is also made from 127.0.0.1.

When you run your server inside a Docker container, it'll only listen on 127.0.0.1:8000 as before. The 127.0.0.1 is a local loopback address and it not accessible outside the container.

When you fire up the docker container with -p 8000:8000, it'll forward traffic heading to 127.0.0.1:8000 to the container's IP address, which in my case is 172.17.0.2.

The container gets an IP addresses within the docker0 network interface (which you can see with the ip addr ls command)

So, when your traffic gets forwarded to the container on 172.17.0.2:8000, there's nothing listening there and the connection attempt fails.

The fix:

The problem is with the listen address:

server := http.Server{Addr: "localhost:8000"}

To fix your problem, change it to

server := http.Server{Addr: ":8000"}

That'll make your server listen on all it container's IP addresses.

Additional info:

When you expose ports in a Docker container, Docker will create iptables rules to do the actual forwarding. See this. You can view these rules with:

iptables -n -L 
iptables -t nat -n -L

Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问