用 docker compose 做调试的困惑

354 天前
 raw0xff

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

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

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

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

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

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

我想确认一下我用的这种方式是否有问题。
chf007
354 天前
如果你没有热更新之类的机制的话,要重启很正常吧。
csh010101
354 天前
@raw0xff 我的建议是你贴出你的 docker-compose 配置文件,以及你使用 dockercompose 的知识,并且把详细的报错信息贴出来。这样大家才能给你对应的意见
raw0xff
354 天前
@weiweiwitch 问题的关键是,同样的程序代码,出现错误后把 docker 重启一下就好了。我不知道具体原因,但可以确定跟代码本身没有关系。我对 docker 不是很了解,有没有可能是 docker 缓存的问题?因为整个启动过程中有多处需要复制文件。
SenLief
354 天前
应该给点错误提示啥的。
seers
354 天前
你需要搭建 CI/CD 了
kneo
354 天前
compose 里的服务启动顺序是不固定的。也许出错的原因是依赖的服务还没启动好。
没有错误的细节没法深入推测了。
f6x
354 天前
指令用错?
up - down
start - stop
raw0xff
354 天前
``` 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
354 天前
@f6x 用的 up down
admpubcom
354 天前
为啥不把复制操作直接写在 dockerfile 里呢?
kneo
354 天前
应用程序内的错误也很多种,是 io 错误还是指针错误还是运算逻辑错误。
重启大法任何时候都管用,不排除是你的应用程序的问题。
另外错误发生的时机?手动复制文件到 temp 下,然后重启所有服务,百分百出错?
julyclyde
354 天前
把要运行的文件 volume 进去?那容器起到啥作用??你直接在外面运行不就得了?
Lax
354 天前
十年来第一次见这么长的 command ,真的啰嗦,每一行都在藏隐患
Lax
354 天前
即使写了这么啰嗦,甚至最重要的代码编译过程并没有被容器所管理
Lax
354 天前
初步建议:
1. 把编译过程写进 dockerfile
2. 把文件夹创建、文件复制过程写进 dockerfile
3. 编译过程的镜像和运行阶段的镜像分离,使用多阶段构建
4. 尽量少用 volume
5. nginx 单独容器,除非是做 nginx 功能相关开发
6. dockerfile 或者 composefile 都有 env 相关的功能
7. compose.yml 里给每个服务取有意义的名字
xianqin
354 天前
为啥要容器内 cp?
多写几行 volumes ,不是更直观?
raw0xff
354 天前
@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://www.v2ex.com/t/1006370

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

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

© 2021 V2EX