使用 github.com/docker/docker/api/types 构建合法容器配置时,需严格区分 container.Config(含 Image、Cmd 等)与 container.HostConfig(含 PortBindings、NetworkMode 等);Image 必须带 tag,Cmd/Entrypoint 需为 []string;HostConfig.NetworkMode="host" 时 ContainerStart 不可传 Platform;销毁容器应设 ContainerRemoveOptions{Force: true, RemoveVolumes: true};流式接口如 ContainerLogs 必须显式 Close()。

怎么用 github.com/docker/docker/api/types 构建合法容器配置
Go 调 Docker API 时,ContainerCreate 第二个参数是 *container.Config,但直接填字段容易漏掉关键约束。比如 Image 字段必须带 tag(写 "nginx" 会拉 latest,但写 "nginx:1.25" 才稳定);Cmd 和 Entrypoint 类型都是 []string,传 "sh -c 'echo hello'" 这种字符串会静默失败——得拆成 []string{"sh", "-c", "echo hello"}。
常见错误现象:docker.ContainerCreate 返回 status=400,Body 里有 "invalid reference format" 或 "No command specified"。
-
HostConfig不能和Config混在一起传,它得单独作为第三个参数(*container.HostConfig) - 端口映射要写在
HostConfig.PortBindings,格式是map[string][]nat.PortBinding{"80/tcp": {{HostIP: "0.0.0.0", HostPort: "8080"}}},不是Config.ExposedPorts - 如果容器要访问宿主机网络(比如连本地数据库),
HostConfig.NetworkMode设为"host",而不是留空或填"bridge"
为什么 Client.ContainerStart 报 "configured for host network" 错误
这个错误不是网络配置本身有问题,而是你在调用 ContainerCreate 时用了 HostConfig.NetworkMode = "host",但创建后又调了 Client.ContainerStart 带了 types.ContainerStartOptions{Platform: "..."} —— Docker Go SDK 1.14+ 对 host 网络模式做了校验,不允许显式传 Platform。
使用场景:本地开发环境快速启停测试容器,依赖宿主机的 Redis 或 PostgreSQL。
立即学习“go语言免费学习笔记(深入)”;
- 删掉
ContainerStart调用里的Platform字段,它只在跨架构拉镜像时需要(如 arm64 容器跑在 amd64 主机) - 如果真要指定平台,改用
Client.ImagePull时加image.PullOptions{Platform: "linux/amd64"},再 create/start 分开做 - 注意
HostConfig中的AutoRemove: true和RestartPolicy互斥,设了前者再设后者会触发 API 400
如何安全销毁容器并避免 "No such container" panic
直接调 Client.ContainerRemove 并不保险:容器可能已退出但没被自动清理,也可能根本不存在,而默认行为是遇到不存在就 panic(SDK 默认 force=false, removeVolumes=false)。
性能影响:频繁调 ContainerList 查状态再删,会多一次 HTTP 请求,拖慢批量操作。
- 始终传
types.ContainerRemoveOptions{Force: true, RemoveVolumes: true},Force=true 能覆盖“正在运行”和“不存在”两种边界态 - 如果只是想清现场,优先用
Client.ContainerStop+Client.ContainerRemove组合,比Force: true更可控 - 不要依赖
err == nil判断容器是否删干净——Docker API 的 204 响应体为空,SDK 会返回nil,但网络超时也可能返回nil,建议加context.WithTimeout控制调用周期
用 Client.ContainerLogs 实时读日志时卡住怎么办
调用后没返回、goroutine 挂起,大概率是因为没消费完响应流,或者没关 io.ReadCloser。Docker 日志接口是 streaming HTTP,服务端不会主动断连。
可给出简短示例:
logs, _ := client.ContainerLogs(ctx, id, types.ContainerLogsOptions{
ShowStdout: true,
Follow: true,
})
defer logs.Close() // 必须!否则连接泄漏
scanner := bufio.NewScanner(logs)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
-
Follow: true时,logs.Close()是唯一能终止流的方式,别指望 context 超时自动关 - 如果只要最后 100 行,加
Tail: "100",避免拉全量日志阻塞 - Windows 上用
io.Copy(os.Stdout, logs)可能乱码,因为原始日志带 Docker 的 frame header,得用stdcopy.StdCopy解帧
最常被忽略的是:所有 ContainerLogs、ContainerExecAttach 这类流式接口,返回的 io.ReadCloser 都必须显式 Close(),Go 的 GC 不管它。










