服务端开发时,每次调试都先编译程序,和其他相关文件一并都覆盖复制到一个本地临时目录,启动 docker compose,容器内建立目录映射到本机临时目录,容器内再分别把文件复制到容器中相应的位置,容器中启动程序。以上步骤都通过本地脚本和 compose yaml 的 command 实现。
想求教一下彦祖们,这种操作姿势是否正确?有没有更好的调试方式?
为什么我总会遇到明明代码没问题,但在容器中会得到莫名其妙的错误,然后让 docker 重启一下就能恢复正常。当不能确定是代码问题还是环境问题时,每次排查都很浪费时间。
1
admpubcom 307 天前 via iPhone
是不是包含这个程序依赖了其他容器内的服务?比如 mysql 、redis 之类的,在同时启动的时候,不同容器内的程序启动完成的时候不一致,就会导致失败,如果是这种情况一般在程序里加上重试逻辑可解决
|
2
weiweiwitch 307 天前
看描述,还看不出你说的问题是哪类问题。程序崩溃?资源、配置读取到的数据不对?还是外面能建立的连接到容器内就不行了?
然后你用容器启动调试的过程感觉过于复杂了。 比如“容器内再分别把文件复制到容器中相应的位置”,这个步骤一般是在做镜像时才会做的,build 镜像时,如果有类似操作,还会做一定程度上的验证确保复制正确。实际启动容器后不会做这步。必要的配置或资源,在启动容器时能准确的挂在进容器的任何位置。 程序一般也是和镜像强绑定的。新编译的程序,都会有新的版本的镜像。通过容器使用的镜像版本就能准确确定程序版本。 然后如果你觉得容器有什么问题,可以 docker exec 进容器里面去找线索验证。看看里面的文件版本、程序版本、配置的细节是否和你期望的一致。如果什么都一致,就可能是你的代码有 BUG 。 |
3
raw0xff OP |
4
chf007 307 天前
如果你没有热更新之类的机制的话,要重启很正常吧。
|
5
csh010101 307 天前
@raw0xff 我的建议是你贴出你的 docker-compose 配置文件,以及你使用 dockercompose 的知识,并且把详细的报错信息贴出来。这样大家才能给你对应的意见
|
6
raw0xff OP @weiweiwitch 问题的关键是,同样的程序代码,出现错误后把 docker 重启一下就好了。我不知道具体原因,但可以确定跟代码本身没有关系。我对 docker 不是很了解,有没有可能是 docker 缓存的问题?因为整个启动过程中有多处需要复制文件。
|
7
SenLief 307 天前
应该给点错误提示啥的。
|
8
seers 307 天前
你需要搭建 CI/CD 了
|
9
kneo 307 天前 via Android
compose 里的服务启动顺序是不固定的。也许出错的原因是依赖的服务还没启动好。
没有错误的细节没法深入推测了。 |
10
f6x 307 天前
指令用错?
up - down start - stop |
11
raw0xff OP ``` 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 本身没有报错。 会不会是文件复制时候偶尔会出错? |
13
admpubcom 307 天前 via iPhone
为啥不把复制操作直接写在 dockerfile 里呢?
|
14
kneo 307 天前 via Android
应用程序内的错误也很多种,是 io 错误还是指针错误还是运算逻辑错误。
重启大法任何时候都管用,不排除是你的应用程序的问题。 另外错误发生的时机?手动复制文件到 temp 下,然后重启所有服务,百分百出错? |
15
julyclyde 307 天前
把要运行的文件 volume 进去?那容器起到啥作用??你直接在外面运行不就得了?
|
16
Lax 307 天前
十年来第一次见这么长的 command ,真的啰嗦,每一行都在藏隐患
|
17
Lax 307 天前
即使写了这么啰嗦,甚至最重要的代码编译过程并没有被容器所管理
|
18
Lax 307 天前
初步建议:
1. 把编译过程写进 dockerfile 2. 把文件夹创建、文件复制过程写进 dockerfile 3. 编译过程的镜像和运行阶段的镜像分离,使用多阶段构建 4. 尽量少用 volume 5. nginx 单独容器,除非是做 nginx 功能相关开发 6. dockerfile 或者 composefile 都有 env 相关的功能 7. compose.yml 里给每个服务取有意义的名字 |
19
xianqin 307 天前
为啥要容器内 cp?
多写几行 volumes ,不是更直观? |
20
raw0xff OP @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 里给每个服务取有意义的名字 - 好嘞 |
21
SenLief 307 天前
@raw0xff compose 主要是编排,让多容器可以容易组合,你不应该让他参与过多的事物,如果容器启动前需要处理事务,我觉得还是用启动脚本比较好。另外容器应该是最小化的应用,你这个是把 nginx 也打包到 dockerfile 中去吗?为何不用单独的 nginx 容器呢?
|
22
Lax 307 天前
1. 把编译过程写进 dockerfile
- 编译过程是指程序的编译吗?我是写入启动脚本.sh 文件中,编译后再 up 。 ---- 指的就是程序的编译( go build 或者 java 之类的 build )。编译软件的版本对生成结果有影响,本机编译和环境一致的目标相悖,这是第一个隐患。 2. 把文件夹创建、文件复制过程写进 dockerfile - 文件复制 我是想区别不大,索性都放在 compose 中方便调试。 ---- 不认同这条,可以放弃使用容器了。 3. 编译过程的镜像和运行阶段的镜像分离,使用多阶段构建 ---- 补充:多阶段构建和上面第一条有关。 4. 尽量少用 volume - 少用 volume 的原因是什么?防止文件 io 冲突吗?之前遇到过,所以就复制进容器内了。 ---- 跟 io 没关系。具体去看文档 5. nginx 单独容器,除非是做 nginx 功能相关开发 - 项目中有 web 部分,所以 dockerfile 中 add 了安装 nginx ,容器启动时启动 ngixn 。 ---- 没有因果关系,“所以”没意义。巨大的单个容器可以只用 docker 没必要 compose 。既然用了 compose ,就要考虑多容器的优势,拆分 nginx 、Redis 、MySQL 等基础组件容器,拆开后也很容易支持动态和静态。 6. dockerfile 或者 composefile 都有 env 相关的功能 - 对 env 有一些逻辑判断,所以写入 sh 。 ---- compose 的 env 功能支持简单逻辑。env 只存环境相关变量。少量逻辑放在启动脚本完全没问题。 7. compose.yml 里给每个服务取有意义的名字 - 好嘞 ---- 好嘞 |
23
klo424 307 天前
dockerfile + docker-compose.yml + gitlab ci/cd ,最后 docker ps 查看状态,docker log [container id] 查看日志。
|
25
raw0xff OP @Lax 用 compose 是为了模拟网络环境,生产环境是应用程序和 nginx 直接运行在节点上没有用到 docker ,所以选择容器中装 nginx 而没有单独用 nginx 容器,不知道这样做对不对请指教。
|
27
cdlnls 307 天前
所以有没有可能,在你的这种场景下并不适合用 docker-compose 来调试程序,程序调试的时候,直接在本机跑和调试,应该是最方便的。看了你的 docker-compose.yml ,也是感觉不用 docker-compose 应该是一个更好的选择。
|
28
Lax 307 天前
这种很基础的应用场景,compose 文档讲的很清楚,花两三个小时通读一遍,很多问题自然就能解决了
|