用 docker compose 做调试的困惑

2024-01-06 11:37:52 +08:00
 raw0xff

服务端开发时,每次调试都先编译程序,和其他相关文件一并都覆盖复制到一个本地临时目录,启动 docker compose,容器内建立目录映射到本机临时目录,容器内再分别把文件复制到容器中相应的位置,容器中启动程序。以上步骤都通过本地脚本和 compose yaml 的 command 实现。

想求教一下彦祖们,这种操作姿势是否正确?有没有更好的调试方式?

为什么我总会遇到明明代码没问题,但在容器中会得到莫名其妙的错误,然后让 docker 重启一下就能恢复正常。当不能确定是代码问题还是环境问题时,每次排查都很浪费时间。

5763 次点击
所在节点    Go 编程语言
28 条回复
admpubcom
2024-01-06 11:48:56 +08:00
是不是包含这个程序依赖了其他容器内的服务?比如 mysql 、redis 之类的,在同时启动的时候,不同容器内的程序启动完成的时候不一致,就会导致失败,如果是这种情况一般在程序里加上重试逻辑可解决
weiweiwitch
2024-01-06 12:01:32 +08:00
看描述,还看不出你说的问题是哪类问题。程序崩溃?资源、配置读取到的数据不对?还是外面能建立的连接到容器内就不行了?

然后你用容器启动调试的过程感觉过于复杂了。
比如“容器内再分别把文件复制到容器中相应的位置”,这个步骤一般是在做镜像时才会做的,build 镜像时,如果有类似操作,还会做一定程度上的验证确保复制正确。实际启动容器后不会做这步。必要的配置或资源,在启动容器时能准确的挂在进容器的任何位置。
程序一般也是和镜像强绑定的。新编译的程序,都会有新的版本的镜像。通过容器使用的镜像版本就能准确确定程序版本。

然后如果你觉得容器有什么问题,可以 docker exec 进容器里面去找线索验证。看看里面的文件版本、程序版本、配置的细节是否和你期望的一致。如果什么都一致,就可能是你的代码有 BUG 。
raw0xff
2024-01-06 12:04:34 +08:00
@admpubcom docker compose 将一个 service 编排了 n 个容器,然后同时启动。每个容器的程序不依赖其他容器的服务。

我想确认一下我用的这种方式是否有问题。
chf007
2024-01-06 12:05:54 +08:00
如果你没有热更新之类的机制的话,要重启很正常吧。
csh010101
2024-01-06 12:06:39 +08:00
@raw0xff 我的建议是你贴出你的 docker-compose 配置文件,以及你使用 dockercompose 的知识,并且把详细的报错信息贴出来。这样大家才能给你对应的意见
raw0xff
2024-01-06 12:10:17 +08:00
@weiweiwitch 问题的关键是,同样的程序代码,出现错误后把 docker 重启一下就好了。我不知道具体原因,但可以确定跟代码本身没有关系。我对 docker 不是很了解,有没有可能是 docker 缓存的问题?因为整个启动过程中有多处需要复制文件。
SenLief
2024-01-06 12:15:43 +08:00
应该给点错误提示啥的。
seers
2024-01-06 12:20:57 +08:00
你需要搭建 CI/CD 了
kneo
2024-01-06 12:23:13 +08:00
compose 里的服务启动顺序是不固定的。也许出错的原因是依赖的服务还没启动好。
没有错误的细节没法深入推测了。
f6x
2024-01-06 12:44:24 +08:00
指令用错?
up - down
start - stop
raw0xff
2024-01-06 12:47:32 +08:00
``` yaml
version: "3.9"
services:
n:
build:
dockerfile: ./Dockerfile.alpine
ports:
- "12300-12310:12380"
- "45600-45610:12381"
volumes:
- ./temp/:/temp/
scale: 1
networks:
- default
command:
- sh
- -c
- |
mkdir /etc/xxxxx
cp /temp/main /etc/xxxxx/main
cp /temp/一些.pem /etc/ssl/certs/
cp -rf /temp/一些目录 /etc/xxxxx/一些目录
cp /temp/获取一些值写入 env.sh /etc/xxxxx/获取一些值写入 env.sh
source /etc/xxxxx/获取一些值写入 env.sh
cp /temp/nginx.conf /etc/nginx/http.d/default.conf
nginx
cd /etc/xxxxx
./main
networks:
default:
driver: bridge
```

启动时`scale =10`

*用临时文件夹是因为启动时需要准备的文件有点多,路径都不同,为了避免麻烦就临时启动时放在同一个目录。
@csh010101
@SenLief
@kneo
都是程序内的错误,docker 本身没有报错。
会不会是文件复制时候偶尔会出错?
raw0xff
2024-01-06 12:48:27 +08:00
@f6x 用的 up down
admpubcom
2024-01-06 12:56:58 +08:00
为啥不把复制操作直接写在 dockerfile 里呢?
kneo
2024-01-06 13:17:10 +08:00
应用程序内的错误也很多种,是 io 错误还是指针错误还是运算逻辑错误。
重启大法任何时候都管用,不排除是你的应用程序的问题。
另外错误发生的时机?手动复制文件到 temp 下,然后重启所有服务,百分百出错?
julyclyde
2024-01-06 13:38:19 +08:00
把要运行的文件 volume 进去?那容器起到啥作用??你直接在外面运行不就得了?
Lax
2024-01-06 13:49:05 +08:00
十年来第一次见这么长的 command ,真的啰嗦,每一行都在藏隐患
Lax
2024-01-06 13:51:23 +08:00
即使写了这么啰嗦,甚至最重要的代码编译过程并没有被容器所管理
Lax
2024-01-06 14:07:49 +08:00
初步建议:
1. 把编译过程写进 dockerfile
2. 把文件夹创建、文件复制过程写进 dockerfile
3. 编译过程的镜像和运行阶段的镜像分离,使用多阶段构建
4. 尽量少用 volume
5. nginx 单独容器,除非是做 nginx 功能相关开发
6. dockerfile 或者 composefile 都有 env 相关的功能
7. compose.yml 里给每个服务取有意义的名字
xianqin
2024-01-06 14:10:39 +08:00
为啥要容器内 cp?
多写几行 volumes ,不是更直观?
raw0xff
2024-01-06 14:52:31 +08:00
@Lax 感谢感谢
初步建议:
1. 把编译过程写进 dockerfile
- 编译过程是指程序的编译吗?我是写入启动脚本.sh 文件中,编译后再 up 。

2. 把文件夹创建、文件复制过程写进 dockerfile
- 文件复制 我是想区别不大,索性都放在 compose 中方便调试。
3. 编译过程的镜像和运行阶段的镜像分离,使用多阶段构建

4. 尽量少用 volume
- 少用 volume 的原因是什么?防止文件 io 冲突吗?之前遇到过,所以就复制进容器内了。

5. nginx 单独容器,除非是做 nginx 功能相关开发
- 项目中有 web 部分,所以 dockerfile 中 add 了安装 nginx ,容器启动时启动 ngixn 。

6. dockerfile 或者 composefile 都有 env 相关的功能
- 对 env 有一些逻辑判断,所以写入 sh 。

7. compose.yml 里给每个服务取有意义的名字
- 好嘞

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://tanronggui.xyz/t/1006370

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX