Testcontainers配置host网络模式启动MongoDB容器失败问题排查
问题描述
我并非网络领域专家,在理解下述问题的原因时存在困惑。我使用Testcontainers配置MongoDB镜像的代码如下:
func createMongoContainer(ctx context.Context) (testcontainers.Container, error) { req := testcontainers.ContainerRequest{ Image: "mongo:6", ExposedPorts: []string{"27017/tcp"}, WaitingFor: wait.ForAll( wait.ForLog("Waiting for connections"), wait.ForListeningPort("27017/tcp"), ), Name: "mongodb6", HostConfigModifier: func(hc *container.HostConfig) { hc.NetworkMode = "host" }, Env: map[string]string{}, } genericContainerReq := testcontainers.GenericContainerRequest{ ContainerRequest: req, Started: true, Reuse: true, } container, err := testcontainers.GenericContainer(ctx, genericContainerReq) if err != nil { return nil, err } return container, nil }
在Linux机器上运行时出现如下报错:
2024/08/22 20:24:10 start container: started hook: all exposed ports, [27017/tcp], were not mapped in 5s: port 27017/tcp is not mapped yet wait until ready: container exited with code 48
但移除以下代码段后,容器可正常启动:
HostConfigModifier: func(hc *container.HostConfig) { hc.NetworkMode = "host" },
请问这段配置的具体作用是什么?如何在保留host网络模式的前提下让容器正常运行?
回答
一、这段配置的作用
这段代码是让容器直接使用宿主机的网络环境:
- 默认Docker容器有自己独立的网络栈,和宿主机网络隔离开,需要通过端口映射把容器内的端口暴露给宿主机才能访问。
- 设为
host模式后,容器会共享宿主机的网络命名空间,不需要做端口映射——容器里的服务直接用宿主机的端口对外提供服务,相当于容器进程直接跑在宿主机网络里。
二、保留host模式的解决办法
报错有两个核心原因:
- Testcontainers的端口检查逻辑失效:
wait.ForListeningPort默认会去查容器的端口映射关系,但host模式下根本没有端口映射,所以这个检查超时失败。 - MongoDB启动失败:退出码48是MongoDB的标准错误码,说明宿主机的27017端口已经被别的进程占了(比如本地装的MongoDB、其他容器),导致容器里的MongoDB绑不上端口。
1. 调整健康检查逻辑
把依赖端口映射的检查改成直接检查宿主机端口,或者去掉端口检查:
方案一:修改端口检查目标为宿主机
WaitingFor: wait.ForAll( wait.ForLog("Waiting for connections"), // 明确检查宿主机的27017端口 wait.ForListeningPort("27017/tcp").WithHost("localhost"), ),
方案二:只保留日志检查
如果日志检查足够可靠,也可以直接去掉端口检查:
WaitingFor: wait.ForLog("Waiting for connections"),
2. 解决端口冲突
先查宿主机27017端口是否被占用:
lsof -i :27017
- 如果有占用进程,要么停掉该进程,要么让MongoDB容器用其他端口:
比如在Env里指定MongoDB监听27018端口:
同时对应调整暴露端口和健康检查:Env: map[string]string{ "MONGO_PORT": "27018", },ExposedPorts: []string{"27018/tcp"}, WaitingFor: wait.ForAll( wait.ForLog("Waiting for connections"), wait.ForListeningPort("27018/tcp").WithHost("localhost"), ),
3. 额外提醒
host网络模式在Linux下是完全生效的,但在Windows/macOS的Docker Desktop里有兼容性限制,不过你是在Linux机器上运行,不用管这个问题。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

