V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhoudaiyu
V2EX  ›  Docker

想问问大家这两种方式进到 Docker 的容器中有啥区别吗?

  •  
  •   zhoudaiyu · 2021-03-25 14:14:16 +08:00 · 1686 次点击
    这是一个创建于 1340 天前的主题,其中的信息可能已经有所发展或是发生改变。
    containerID="4b74305cb32b9a1913cc96fb0074c27d1d5cc2484f314a69f6058b2168993509"
    
    #使用 docker 命令进到容器中
    docker exec -it $containerID bash
    
    #通过 nsenter 进到容器的进程的命名空间中
    containerPid=`docker inspect -f {{.State.Pid}} containerID`
    nsenter -t $containerPid -n -u -m -i -p 
    
    10 条回复    2021-03-25 17:35:46 +08:00
    baiyi
        1
    baiyi  
       2021-03-25 14:26:06 +08:00
    本质上都是进入到容器所在的 namespace 上执行命令,但 docker exec 可能会有其他的处理,安全等方面的。

    默认情况下推荐使用 docker exec 。除非想突破 exec 中运行命令的限制,比如说 https://www.v2ex.com/t/758750 这个帖子的楼主想改容器的 mac 地址,通过 exec 进入是不能改的。只有通过其他手段进入 namespace 才能改。
    monsterxx03
        2
    monsterxx03  
       2021-03-25 14:38:41 +08:00
    docker exec 是通过 docker daemon 的 api server 转发的, 可以认为 docker daemon 内部实现了 nsenter 的功能
    zhoudaiyu
        3
    zhoudaiyu  
    OP
       2021-03-25 16:07:31 +08:00
    @baiyi 十分感谢!可以理解成 docker exec 是受限的 nsenter 吗?
    @monsterxx03 十分感谢!是对 nsenter 包了一层还是直接重写了一个和 nsenter 功能类似的程序?
    baiyi
        4
    baiyi  
       2021-03-25 16:16:35 +08:00
    @zhoudaiyu #3 应该说 nsenter 是超权限的 docker exec,在大部分的时候首先要考虑的都是使用 docker exec 命令。

    因为容器是由一系列的的技术组合而成,nsenter 或是 ip netns 这样的命令仅仅只是进入 namespace,没考虑到容器其他的内容,这样操作有可能会导致对容器造成损坏的。

    损坏这个描述可能不特别恰当,应该说你的操作可能超出了 docker 的管理,以至于后续 docker 可能无法正常管理容器。
    zhoudaiyu
        5
    zhoudaiyu  
    OP
       2021-03-25 16:29:03 +08:00
    @baiyi 明白了,感谢。其实我是今天想在容器里抓包但是容器里没有 tcpdump 只有宿主机上才有才查到的 nsenter,但是产生了好奇心。
    baiyi
        6
    baiyi  
       2021-03-25 16:48:00 +08:00
    @zhoudaiyu #5 可以学一学容器原理,挺有意思的。我也是之前对容器网络感兴趣,才学习的这方面知识。
    zhoudaiyu
        7
    zhoudaiyu  
    OP
       2021-03-25 17:03:14 +08:00
    @baiyi 的确很有意思,也很神奇
    monsterxx03
        8
    monsterxx03  
       2021-03-25 17:14:28 +08:00
    不是包的, 直接基于 syscall setns 实现的, 代码在 runc 里.

    这里还个挺有意思的事情, go 里没法控制线程, 但是 setns 这个 syscall 必须在单线程环境下执行. runc 里用了个很 hack 的方式在 go runtime 启动前注入了一段 C 代码通过 pipe 来实现 https://github.com/opencontainers/runc/tree/master/libcontainer/nsenter

    我是在 go 里调用 ptrace 这个 syscall 的时候遇到了一样的问题后, 才看到了 runc 的办法. go 做系统编程往底层还是有很多问题的.
    baiyi
        9
    baiyi  
       2021-03-25 17:29:26 +08:00
    @monsterxx03 #8 我觉得 Go 的运行时调度模型实现的挺好的,一个 go 关键字就能用。但毕竟没有暴露底层的线程操作,所以碰到这种情况只能通过 cgo 实现。
    monsterxx03
        10
    monsterxx03  
       2021-03-25 17:35:46 +08:00
    @baiyi 用 cgo 倒没啥, 就没想到还能在 go runtime 启动前执行代码
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2126 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 00:02 · PVG 08:02 · LAX 16:02 · JFK 19:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.