你如何 dockerize 一个 WebSocket 服务器? [英] How do you dockerize a WebSocket Server?

查看:22
本文介绍了你如何 dockerize 一个 WebSocket 服务器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在将 WebSocket 服务器放入 Docker 容器时遇到问题.

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

这是服务器代码,它写入一个带有connected"的新连接.

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
}

这是客户:

// 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"
}

运行 server.go 然后 client.go 打印connected",表明代码正在运行.现在我想把服务器放在一个 Docker 容器中.这是dockerfile:

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"]

我使用这些命令来构建和启动容器,暴露 8000/tcp.

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

我可以确认服务器正在运行,因为它打印服务器正在运行".如果我在容器外启动 client.go,它会崩溃:

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

我期望的结果与之前相同——在客户端打印已连接".该错误消息意味着服务器在握手之前断开了连接.我不明白60328"这个数字.据我所知,WebSocket 在升级时不会改变端口,所以我应该只暴露 8000.

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.

我不知道我必须改变什么才能通过 WebSocket 连接到我的服务器.

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

推荐答案

当您指定要侦听的主机名或 IP 地址时(在这种情况下 localhost 解析为 127.0.0.1),那么您的服务器将只侦听该 IP 地址.

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.

当您在 Docker 容器之外时,侦听 localhost 不是问题.如果您的服务器只侦听 127.0.0.1:8000,那么您的客户端可以轻松连接到它,因为连接也是从 127.0.0.1 建立的.

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.

当您在 Docker 容器中运行服务器时,它只会像以前一样侦听 127.0.0.1:8000.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.

当您使用 -p 8000:8000 启动 docker 容器时,它会将前往 127.0.0.1:8000 的流量转发到容器的 IP 地址,其中在我的例子中是 172.17.0.2.

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.

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

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

因此,当您的流量被转发到 172.17.0.2:8000 上的容器时,那里没有任何东西在监听并且连接尝试失败.

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.

问题在于监听地址:

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

要解决您的问题,请将其更改为

To fix your problem, change it to

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

这将使您的服务器侦听所有容器的 IP 地址.

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

当您在 Docker 容器中公开端口时,Docker 将创建 iptables 规则来执行实际转发.看到这个.您可以通过以下方式查看这些规则:

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

这篇关于你如何 dockerize 一个 WebSocket 服务器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆