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 · 347 天前 · 5429 次点击
    这是一个创建于 347 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

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

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

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