【问题标题】:How do you dockerize a WebSocket Server?你如何 dockerize 一个 WebSocket 服务器?
【发布时间】:2019-06-03 17:14:59
【问题描述】:

我无法将 WebSocket 服务器放入 Docker 容器中。

这是服务器代码,它使用“已连接”写入新连接。

// 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 打印“已连接”,表明代码正在运行。现在我想把服务器放在一个 Docker 容器中。这是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。

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

我可以确认服务器正在运行,因为它打印“服务器正在运行”。如果我在容器外启动client.go,它会恐慌:

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

我期望的结果与以前相同——在客户端打印“已连接”。错误消息意味着服务器在握手之前断开了连接。我不明白“60328”号码。据我所知,WebSocket 在升级时不会更改端口,所以我应该可以只公开 8000。

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

【问题讨论】:

标签: docker go websocket dockerfile


【解决方案1】:

当您指定要侦听的主机名或 IP 地址(在本例中为 localhost 解析为 127.0.0.1)时,您的服务器将仅侦听该 IP 地址。

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

当您在 Docker 容器中运行服务器时,它只会像以前一样侦听 127.0.0.1:8000127.0.0.1 是本地环回地址,无法在容器外访问。

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

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

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

修复:

问题出在监听地址上:

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

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

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

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

附加信息:

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

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

【讨论】:

  • 只是想分享我的经验,即使是在完全不同的语言/框架(飞镖)中。这个答案(和问题)是“现场”理解 docker 内的服务端口和地址。谢谢
  • 谢谢你,很好的解释,只是想补充一点,根据所使用的语言/框架,可能需要 IP 地址。在这种情况下,IP 0.0.0.0 表示所有 IP
猜你喜欢
  • 2020-11-29
  • 1970-01-01
  • 2019-06-23
  • 1970-01-01
  • 2012-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多