V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
raw0xff
V2EX  ›  Go 编程语言

用 docker compose 做调试的困惑

  •  1
     
  •   raw0xff · 2024-01-06 11:37:52 +08:00 · 5598 次点击
    这是一个创建于 369 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

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

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

    我想确认一下我用的这种方式是否有问题。
    chf007
        4
    chf007  
       2024-01-06 12:05:54 +08:00
    如果你没有热更新之类的机制的话,要重启很正常吧。
    csh010101
        5
    csh010101  
       2024-01-06 12:06:39 +08:00
    @raw0xff 我的建议是你贴出你的 docker-compose 配置文件,以及你使用 dockercompose 的知识,并且把详细的报错信息贴出来。这样大家才能给你对应的意见
    raw0xff
        6
    raw0xff  
    OP
       2024-01-06 12:10:17 +08:00
    @weiweiwitch 问题的关键是,同样的程序代码,出现错误后把 docker 重启一下就好了。我不知道具体原因,但可以确定跟代码本身没有关系。我对 docker 不是很了解,有没有可能是 docker 缓存的问题?因为整个启动过程中有多处需要复制文件。
    SenLief
        7
    SenLief  
       2024-01-06 12:15:43 +08:00
    应该给点错误提示啥的。
    seers
        8
    seers  
       2024-01-06 12:20:57 +08:00
    你需要搭建 CI/CD 了
    kneo
        9
    kneo  
       2024-01-06 12:23:13 +08:00 via Android
    compose 里的服务启动顺序是不固定的。也许出错的原因是依赖的服务还没启动好。
    没有错误的细节没法深入推测了。
    f6x
        10
    f6x  
       2024-01-06 12:44:24 +08:00
    指令用错?
    up - down
    start - stop
    raw0xff
        11
    raw0xff  
    OP
       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
        12
    raw0xff  
    OP
       2024-01-06 12:48:27 +08:00
    @f6x 用的 up down
    admpubcom
        13
    admpubcom  
       2024-01-06 12:56:58 +08:00 via iPhone
    为啥不把复制操作直接写在 dockerfile 里呢?
    kneo
        14
    kneo  
       2024-01-06 13:17:10 +08:00 via Android
    应用程序内的错误也很多种,是 io 错误还是指针错误还是运算逻辑错误。
    重启大法任何时候都管用,不排除是你的应用程序的问题。
    另外错误发生的时机?手动复制文件到 temp 下,然后重启所有服务,百分百出错?
    julyclyde
        15
    julyclyde  
       2024-01-06 13:38:19 +08:00
    把要运行的文件 volume 进去?那容器起到啥作用??你直接在外面运行不就得了?
    Lax
        16
    Lax  
       2024-01-06 13:49:05 +08:00
    十年来第一次见这么长的 command ,真的啰嗦,每一行都在藏隐患
    Lax
        17
    Lax  
       2024-01-06 13:51:23 +08:00
    即使写了这么啰嗦,甚至最重要的代码编译过程并没有被容器所管理
    Lax
        18
    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
        19
    xianqin  
       2024-01-06 14:10:39 +08:00
    为啥要容器内 cp?
    多写几行 volumes ,不是更直观?
    raw0xff
        20
    raw0xff  
    OP
       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 里给每个服务取有意义的名字
    - 好嘞
    SenLief
        21
    SenLief  
       2024-01-06 15:28:36 +08:00
    @raw0xff compose 主要是编排,让多容器可以容易组合,你不应该让他参与过多的事物,如果容器启动前需要处理事务,我觉得还是用启动脚本比较好。另外容器应该是最小化的应用,你这个是把 nginx 也打包到 dockerfile 中去吗?为何不用单独的 nginx 容器呢?
    Lax
        22
    Lax  
       2024-01-06 15:32:07 +08:00
    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 里给每个服务取有意义的名字
    - 好嘞
    ---- 好嘞
    klo424
        23
    klo424  
       2024-01-06 16:55:52 +08:00
    dockerfile + docker-compose.yml + gitlab ci/cd ,最后 docker ps 查看状态,docker log [container id] 查看日志。
    raw0xff
        24
    raw0xff  
    OP
       2024-01-06 17:08:16 +08:00
    @SenLief 不好意思的说,主要是不懂怎样单独用 nginx 容器:)只会用已知的方式实现。
    raw0xff
        25
    raw0xff  
    OP
       2024-01-06 17:18:17 +08:00
    @Lax 用 compose 是为了模拟网络环境,生产环境是应用程序和 nginx 直接运行在节点上没有用到 docker ,所以选择容器中装 nginx 而没有单独用 nginx 容器,不知道这样做对不对请指教。
    SenLief
        26
    SenLief  
       2024-01-06 17:24:02 +08:00
    @raw0xff compose 编排多容器,nginx 作为一个容器,依赖 web 应用就可以。
    cdlnls
        27
    cdlnls  
       2024-01-06 21:58:57 +08:00
    所以有没有可能,在你的这种场景下并不适合用 docker-compose 来调试程序,程序调试的时候,直接在本机跑和调试,应该是最方便的。看了你的 docker-compose.yml ,也是感觉不用 docker-compose 应该是一个更好的选择。
    Lax
        28
    Lax  
       2024-01-06 22:58:47 +08:00
    这种很基础的应用场景,compose 文档讲的很清楚,花两三个小时通读一遍,很多问题自然就能解决了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3218 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 12:22 · PVG 20:22 · LAX 04:22 · JFK 07:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.