使用Golang Air时Postgres本地卷执行docker compose down后被删除
问题分析与解决方案
核心问题1:docker compose down删除Postgres数据目录
原因是Air配置中tmp_dir="tmp"与Postgres数据卷挂载的./tmp目录重合,且misc.clean_on_exit=true会在Air进程退出时清理指定的临时目录。当执行docker compose down时,app容器内的Air进程退出,触发清理操作,直接删掉了本地的./tmp目录(也就是Postgres的数据存储目录)。
解决步骤:
- 修改
air.toml,将Air的临时目录与Postgres数据目录分离:
root="." # 把Air的临时目录改成独立的,比如.airtmp tmp_dir=".airtmp" [build] cmd="go build -gcflags=\"all=-N -l\" -o ./bin/main ." bin="/app/bin" full_bin="/app/bin/main" log="air_errors.log" include_ext=["go", "yaml"] # 排除新的临时目录和Postgres数据目录 exclude_dir=[".airtmp", "tmp"] delay=1000 [log] time=true [misc] clean_on_exit=true
- 手动删除原有的
./tmp目录,重新执行docker compose up -d,让Postgres重新初始化数据目录,此时Air的清理操作只会影响.airtmp,不会再删除Postgres的数据目录。
核心问题2:容器启动failed to initialize错误
结合你的配置和代码,大概率是以下两种原因:
原因A:Postgres未完成初始化,App提前尝试连接
depends_on: [db]仅保证db容器启动,但Postgres服务需要几秒时间完成初始化,此时App(通过Air启动)尝试连接DB会失败,触发Cannot connect to DB panic,进而导致容器failed to initialize。
解决方法:
在App的启动流程中添加DB连接等待逻辑,或者在local.Dockerfile中引入等待脚本:
- 在项目根目录创建
wait-for-db.sh脚本:
#!/bin/bash set -e host="$1" shift cmd="$@" until pg_isready -h "$host" -p 5432 -U "admin"; do >&2 echo "Postgres is unavailable - sleeping" sleep 1 done >&2 echo "Postgres is up - executing command" exec $cmd
- 给脚本加执行权限:
chmod +x wait-for-db.sh - 修改
air.toml的cmd,先执行等待脚本再构建:
[build] cmd="./wait-for-db.sh db && go build -gcflags=\"all=-N -l\" -o ./bin/main ."
- 确保
local.Dockerfile中安装了postgresql-client(提供pg_isready命令),比如在Dockerfile中添加:
RUN apt-get update && apt-get install -y postgresql-client && rm -rf /var/lib/apt/lists/*
原因B:Postgres数据目录权限问题
如果./tmp目录被Air删除后重新创建,本地目录的权限可能是root用户所有,而Postgres容器内运行的是postgres用户(UID=999),无法写入该目录,导致Postgres启动失败,进而App连接失败。
解决方法:
- 手动设置本地
./tmp目录的权限:
sudo chown -R 999:999 ./tmp
- 或者在
docker-compose.yml的db服务中添加user配置,指定用root用户运行(仅本地开发临时使用):
db: image: postgres container_name: db ports: - "5432:5432" environment: POSTGRES_USER: "admin" POSTGRES_PASSWORD: "pass" POSTGRES_DB: "test" TZ: "UTC" PGTZ: "UTC" volumes: - ./tmp:/var/lib/postgresql/data # 临时用root用户运行,避免权限问题 user: "root"
验证步骤
- 停止并清理现有容器:
docker compose down -v - 删除原
./tmp和.airtmp目录(如果存在) - 应用上述所有配置修改
- 启动容器:
docker compose up --build - 检查容器日志:
docker compose logs app和docker compose logs db,确认无错误后测试API连接。
内容的提问来源于stack exchange,提问作者HexaCrop
相关产品推荐
相关产品推荐

