Docker Compose + air 无法替代 Tilt,因为 Tilt 专精于多服务协同构建状态可视化与跨阶段依赖感知,整合构建日志、容器状态、健康检查、资源依赖图等信息到统一 Web UI,并支持一键重启、暂停构建等操作,而 Compose 和 air 分别只解决编排和热重载问题。

为什么不用 Docker Compose + air 就直接上 Tilt?
Tilt 不是替代 Docker Compose 或 air,而是补足它们缺失的「多服务协同构建状态可视化」和「跨阶段依赖感知」。当你本地跑 5+ 个 Go 微服务(比如 auth-svc、order-svc、payment-svc、gateway、jaeger),每个都带自己的 Dockerfile 和 docker-compose.yml 片段,手动 docker compose up -d + air + curl http://localhost:8080/health 查状态,很快就会迷失在 terminal 标签页里。Tilt 把构建日志、容器状态、端口映射、健康检查结果、甚至自定义指标(比如 build_duration_ms)全收进一个 Web 页面,且支持一键重启单个服务、暂停构建、查看资源依赖图。
Tiltfile 必须写清楚三件事:Go 构建命令、Docker 构建上下文、服务间依赖
别把 Tiltfile 当成 YAML 配置文件来写——它是 Python 脚本,执行顺序敏感。常见错误是只写 docker_build 却漏掉 k8s_yaml 或 local_resource 的联动逻辑,导致 Tilt 显示“构建成功”但容器根本没起来。
-
docker_build的context必须指向含Dockerfile的目录,不是项目根目录(比如./cmd/auth-svc,不是.) - Go 服务用多阶段构建时,Tilt 默认不缓存 builder 阶段;加
fast_build可提速:docker_build('auth-svc', './cmd/auth-svc', fast_build=True) - 服务间调用依赖要用
resource显式声明,否则 Tilt 不知道哪个服务启动失败会导致下游卡住:resource('order-svc', depends_on=['auth-svc', 'postgres']) - 本地调试需暴露端口,别只靠
docker_build;必须配k8s_yaml或port_forward:port_forward('auth-svc', 8081, 8081)
Go 微服务的 Tilt 构建失败,90% 是环境变量或 GOPROXY 没透传
Tilt 在独立构建环境中执行 go build,默认不继承 shell 的 $GOPROXY、$GOOS、$CGO_ENABLED。你 go run 没问题,Tilt 里却报 cannot find package "github.com/grpc-ecosystem/go-grpc-middleware",大概率是这个原因。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 所有 Go 构建命令前加环境变量前缀:
docker_build('auth-svc', './cmd/auth-svc', env={'GOPROXY': 'https://goproxy.cn', 'CGO_ENABLED': '0'}) - 若用
local_resource直接运行go run(跳过 Docker),必须显式设env,且注意 Windows/macOS/Linux 路径分隔符差异(GO111MODULE=on在 Linux 下有效,在 macOS 上可能需额外export) - 检查
go.mod是否含 replace 语句(如replace example.com/internal => ./internal)——Tilt 构建时路径上下文变了,replace 会失效;改用相对路径或统一用 module path 引用
Tilt Web UI 里看到 “Waiting for readiness probe” 却一直转圈?查这三处
这不是 Tilt 的 bug,而是 Go 微服务健康检查逻辑与容器生命周期没对齐。Tilt 默认用 Kubernetes 的 readiness probe 机制判断服务就绪,但很多 Go 服务只实现了 HTTP /health,没设超时或没处理 probe 并发请求。
立即学习“go语言免费学习笔记(深入)”;
- 确保
http.ListenAndServe启动后,/healthhandler 立即可响应(别在main()开头连 DB 或初始化 heavy cache) - probe 请求默认无超时,Go 的
http.Server若未设ReadTimeout/WriteTimeout,可能卡住;加一行:srv := &http.Server{Addr: addr, ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second} - Tilt 的 probe 默认走容器内网(如
http://auth-svc:8080/health),不是宿主机localhost;确认你的 handler 绑定的是:8080,不是127.0.0.1:8080(后者在容器内不可达)
真正麻烦的是那些隐式依赖:比如 order-svc 启动时去连 consul,但 Tilt 没声明这个依赖,就先报 readiness 失败,再等 30 秒才拉起 consul —— 这种链式延迟得靠 depends_on 和 readiness_probe 的 timeout 参数手工对齐,没法全自动。

















