使用 Docker Compose 配置文件,新建了一个 alpine 镜像的容器。 里面运行了一个 golang gin 开发的 web 应用。没想到,又踩了一个 docker 配置的坑 🥲 我感觉踩的 docker 坑多得数不过来啦
相对目录问题
我发现了一个线上的 bug,线上服务器中,使用 golang 创建的相对路径的目录,结果发现目录创建在了根目录 / 下,而不是预期的 /app 目录下。
- 本地开发机,没有使用 docker,目录位置都是正常的
- 线上服务器,使用 docker 部署的,目录位置不对。全部到了根目录下。
- 线上服务器,不使用 docker,使用 systemd 直接运行的,目录位置也是正常的。(后来发现是我设置了 systemd WorkingDirectory 参数)
查了一下,原来 docker 也是需要设置工作目录的。至少 alpine 镜像是这样的。
原 docker-compose.yml 配置
sunzhongwei.com:
image: alpine:3.20.3
restart: always
ports:
- "9000:9000"
volumes:
- /var/www/sunzhongwei.com:/app
command: /app/main
确认当前的工作目录:
> docker compose exec sunzhongwei.com pwd
/
可以看到当前目录是 / 根目录,而不是 /app 目录。
修改后的 docker-compose.yml 配置
增加了 working_dir 参数:
sunzhongwei.com:
image: alpine:3.20.3
restart: always
ports:
- "9000:9000"
volumes:
- /var/www/sunzhongwei.com:/app
working_dir: /app
command: /app/main
数据目录备份
修改完配置,不要着急使配置生效。因为如果重新构建容器,容器内的数据目录会丢失。 即,没有映射到宿主机的目录数据,会丢失。例如,如果有两个目录 upload 和 sitemap,需要先备份出来。
docker compose exec sunzhongwei.com sh
# cp -R upload app/upload
# cp -R sitemap app/sitemap
因为原配置里,已经把 /var/www/sunzhongwei.com 映射到了 /app 目录下,所以备份到 /app/upload 和 /app/sitemap 下即可。
备份完成后,从宿主机的目录里就能看到 upload 和 sitemap 两个目录了。
如何使 working_dir 的配置生效
执行:
docker compose up -d <容器名>
即可。不需要先 stop,因为当你对正在运行的服务执行 docker compose up -d 时,Docker Compose 会自动按顺序执行以下操作:
- 构建上下文:检查镜像等依赖(如果配置了build)。
- 停止容器:自动停止指定服务(例如 sunzhongwei.com)当前正在运行的容器。
- 删除容器:移除刚才停止的旧容器。
- 创建新容器:根据 docker-compose.yml 中的最新配置(包含你新加的 working_dir)创建一个全新的容器。
- 启动容器:启动这个新容器。
所以只需执行一条命令即可。
需要注意的是:
docker compose restart <容器名>
只是重启现有容器,不会重新加载 docker-compose.yml 的变更。所以,如果只是执行 restart,新配置是不会生效的。
操作流程总结
完整且正确的操作步骤:
- 备份数据目录(如果有需要保留的数据目录)。
- 修改配置:在 docker-compose.yml 中为指定服务添加 working_dir: /app。
- 执行一条命令:在 docker-compose.yml 目录下运行 docker compose up -d <容器名>
验证
# docker compose exec sunzhongwei.com pwd
/app
或者进入容器:
docker compose exec sunzhongwei.com sh
会发现默认的目录已经不是 / 而变成了 /app.
并且之前存在 docker 中的那两个目录也消失了。
关于作者 🌱
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式