[转帖]nsenter 工具的使用

nsenter,工具,使用 · 浏览次数 : 0

小编点评

**命名空间** * **net**命名空间:用于网络通信,每个容器都有自己的独立网络设备和 IP 地址。 * **ipc**命名空间:用于进程间通信,每个容器可以设置自己的共享内存空间。 * **docker**命名空间:用于容器内部通信,例如启动 Docker 服务。 * **container**命名空间:用于容器本身的名称和标识符。 **脚本** 这些脚本通常用于执行以下操作: * 启动或停止 Docker 服务。 * 启动或停止容器。 * 连接或关闭容器中的终端。 * 执行命令或脚本。 * 访问容器中的文件系统。 **示例脚本** ```bash # 启动 Docker 服务 docker run -d --name docker-container ubuntu:latest # 启动一个容器 docker run -d --name container-name ubuntu:latest # 连接容器中的终端 docker exec -it container-name bash # 执行命令 docker exec -it container-name echo "Hello world!" # 关闭容器 docker kill container-name ```

正文

一、背景

对于运行在后台的docker容器,我们经常需要做的事情是进入到容器中,docker为我们提供了docker exec 、docker attach 命令,并且还提供了nsenter工具,外部工具供我们使用。

docker attach存在的问题是:当多个窗口同时attach到同一个容器时,所有的窗口都会同步的显示,假如其中的一个窗口发生阻塞时,其它的窗口也会阻塞,docker attach命令可以说是最不方便的进入后台docker容器的方法。

docker exec命令是在docker 1.3之后增加的一个比docker attach命令更加方便的命令。

和docker exec差不多方便的命令是nsenter工具。

nsenter 是一个可以用来进入到目标程序说在 namespace 中运行命令的工具,一般可以用于在容器外 debug 容器中运行的程序。

二、安装

  1. 源码安装 nsenter
$ cd /tmp;
$ curl https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz | tar -zxf-; cd util-linux-2.24;
$ ./configure  --without-ncurses
$ make nsenter && sudo cp nsenter /usr/local/bin
    1. yum安装

    util-linux 是一个开放源码的软件包,是一个对任何 Linux 系统的基本工具套件。含有一些标准 Unix 工具,如 login。
    util-linux 软件包包含许多工具。其中比较重要的是加载、卸载、格式化、分区和管理硬盘驱动器,打开 tty 端口和得到内核消息。

    sudo yum install -y util-linux
    

      三、nsenter使用

      1. 查看帮助
      $ nsenter --help
      

      用法:
      nsenter [options] <program> [<argument>...]
      Run a program with namespaces of other processes.

      选项:
      -t, --target <pid> 要获取名字空间的目标进程
      -m, --mount[=<file>] enter mountnamespace
      -u, --uts[=<file>] enter UTSnamespace (hostname etc)
      -i, --ipc[=<file>] enter System V IPCnamespace
      -n, --net[=<file>] enter networknamespace
      -p, --pid[=<file>] enter pidnamespace
      -U, --user[=<file>] enter usernamespace
      -S, --setuid <uid> set uid in enterednamespace
      -G, --setgid <gid> set gid in enterednamespace
      --preserve-credentialsdo not touch uids or gids
      -r, --root[=<dir>] set the root directory
      -w, --wd[=<dir>] set the working directory
      -F, --no-fork 执行 <程序> 前不 fork
      -Z, --follow-context set SELinux context according to --target PID

      -h, --help 显示此帮助并退出
      -V, --version 输出版本信息并退出

        更多信息请参阅 nsenter(1)。
        $ nsenter -V
        nsenter,来自 util-linux 2.23.2
        在使用nsenter命令之前需要获取到docker容器的进程,然后再使用nsenter工具进去到docker容器中
        每一个容器都有.State.Pid,所以这个命令除了容器的id需要我们根据docker ps -a去查找,其他的全部为固定的格式

        $ docker inspect -f {{.State.Pid}} 容器名或者容器id 
        

        如下:
        $ docker inspect -f {{.State.Pid}} 7b7af641a02d
        20560
        $ docker inspect -f {{.State.Pid}} consul_client
        20560
        输入该命令便进入到容器中

        $ nsenter --target 上面查到的进程id --mount --uts --ipc --net --pid
        解释nsenter指令中进程id之后的参数的含义:
        –mount参数是进去到mount namespace中 (文件系统)
        –uts参数是进入到uts namespace中 (主机名与域名)
        –ipc参数是进入到System V IPC namaspace中 (信号量、消息队列和共享内容)
        –net参数是进入到network namespace中 (网络设备、网络栈、端口)
        –pid参数是进入到pid namespace中 (进程编号)
        –user参数是进入到user namespace中 (用户和用户组)

          docker隔离应用应用涉及到的六大名称空间
          1、pid 命名空间(进程ID)
          不同用户的进程就是通过 pid 命名空间隔离开的,且不同命名空间中可以有相同 pid。所有的 LXC 进程在 Docker 中的父进程为 Docker 进程,每个 LXC 进程具有不同的命名空间。同时由于允许嵌套,因此可以很方便的实现嵌套的 Docker 容器。

          2、net 命名空间(网络)
          有了 pid 命名空间,每个命名空间中的 pid 能够相互隔离,但是网络端口还是共享 host 的端口。网络隔离是通过 net 命名空间实现的, 每个 net 命名空间有独立的 网络设备,IP 地址,路由表,/proc/net 目录。这样每个容器的网络就能隔离开来。Docker 默认采用 veth 的方式,将容器中的虚拟网卡同 host 上的一 个Docker 网桥 docker0 连接在一起。

          3、ipc 命名空间(进程间通信)
          容器中进程交互还是采用了 Linux 常见的进程间交互方法(interprocess communication - IPC), 包括信号量、消息队列和共享内存等。然而同 VM 不同的是,容器的进程间交互实际上还是 host 上具有相同 pid 命名空间中的进程间交互,因此需要在 IPC 资源申请时加入命名空间信息,每个 IPC 资源有一个唯一的 32 位 id。

          4、mnt 命名空间(挂载文件系统)
          类似 chroot,将一个进程放到一个特定的目录执行。mnt 命名空间允许不同命名空间的进程看到的文件结构不同,这样每个命名空间 中的进程所看到的文件目录就被隔离开了。同 chroot 不同,每个命名空间中的容器在 /proc/mounts 的信息只包含所在命名空间的 mount point。

          5、UTS 命名空间(主机名/域名)
          UTS(“UNIX Time-sharing System”) 命名空间允许每个容器拥有独立的 hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非 主机上的一个进程。

          6、user 命名空间(用户)
          每个容器可以有不同的用户和组 id, 也就是说可以在容器内用容器内部的用户执行程序而非主机上的用户。

          查看docker的连接
          由于使用DOCKER的时候,ESTABLISHED连接不会出现在netstat中,在运行中的docker容器中列出打开的套接字的方法 ,查找docker的进程号 :

          $ docker inspect -f'{{.State.Pid}}' <containerid>  
          $ docker inspect -f'{{.State.Pid}}' 1746bf8c10aa 
          1829
          

            查看连接:

            $ sudo nsenter -t <pid> -n netstat | grep ESTABLISHED 
            

            示例:
            $ nsenter -t 1829 -n netstat |grep ESTABLISHED
            tcp 0 0 localhost:60353 localhost:epmd ESTABLISHED
            tcp 0 0 localhost:epmd localhost:60353 ESTABLISHED
            tcp 0 0 localhost.localdo:15672 192.168.56.1:59679 ESTABLISHED
            tcp6 0 0 172.17.0.2:amqp 192.168.56.1:59898 ESTABLISHED
            tcp6 21 0 172.17.0.2:amqp 192.168.56.1:59571 ESTABLISHED

              结合 docker 使用用于在某个容器的 namespace 中运行指定程序的常用命令是:

              PID=$(docker inspect --format {{.State.Pid}} <container_name_or_ID>)
              

              nsenter -m -u -i -n -p -t $PID <command>

                例子:

                $ docker run --rm --name test -d busybox  sleep 10000
                8115009baccc53a2a5f6dfff642e0d8ab1dfb95dde473d14fb9a06ce4e89364c
                

                $ docker ps |grep busybox
                8115009baccc busybox "sleep 10000" 9 seconds ago Up 8 seconds test

                $ PID=$(docker inspect --format {{.State.Pid}} 8115009baccc)

                $ nsenter -m -u -i -n -p -t $PID ps aux
                PID USER TIME COMMAND
                1 root 0:00 sleep 10000
                7 root 0:00 ps aux

                $ nsenter -m -u -i -n -p -t $PID hostname
                8115009bacc

                  创建docker-enter并置于$PATH下(将shell脚本放到环境变量中,任意路径可执行)

                  脚本放置:

                  cd ~
                  #创建bin文件夹,也可以按自己喜好在指定位置下创建目录(目录名也可以自定义)
                  mkdir bin
                  

                  vim ~/.bashrc

                  移到最后一行,添加以下命令,其中:表示路径分隔符,~/bin就是我们刚才创建的文件路径

                  export PATH=$PATH:~/bin

                  source ~/.bashrc

                  ~/bin 目录下创建自己的脚本

                    #chmod +x xxx.sh

                    脚本:vim docker-enter 
                    #!/bin/bash
                    

                    if [ -e $(dirname"\(0"</span><span class="token punctuation">)</span><span class="token operator">/</span>nsenter <span class="token punctuation">]</span><span class="token punctuation">;</span> then <span class="token macro property"><span class="token directive-hash">#</span> <span class="token directive keyword">with</span> <span class="token expression">boot2docker<span class="token punctuation">,</span> nsenter is <span class="token operator">not</span> in the PATH but it is in the same folder</span></span> NSENTER<span class="token operator">=</span>\)(dirname"$0")/nsenter
                    else
                    NSENTER=nsenter
                    fi

                    if [ -z"\(1"</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> then echo<span class="token string">"Usage: `basename "</span>\)0"` CONTAINER [COMMAND [ARG]...]"
                    echo""
                    echo"Enters the Docker CONTAINER and executes the specified COMMAND."
                    echo"If COMMAND is not specified, runs an interactive shell in CONTAINER."
                    else
                    PID=$(docker inspect --format"{{.State.Pid}}" "\(1"</span><span class="token punctuation">)</span> <span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token operator">-</span>z<span class="token string">"\)PID" ]; then
                    exit 1
                    fi
                    shift

                    OPTS="--target $PID --mount --uts --ipc --net --pid /bin/bash"

                    if [ -z"$1" ]; then
                    # No command given.
                    # Use su to clear all host environment variables except for TERM,
                    # initialize the environment variables HOME, SHELL, USER, LOGNAME, PATH,
                    # and start a login shell.

                    "$NSENTER" $OPTS su - root

                    "$NSENTER" \(OPTS <span class="token keyword">else</span> <span class="token macro property"><span class="token directive-hash">#</span> <span class="token expression">Use env to clear all host environment variables<span class="token punctuation">.</span></span></span> <span class="token string">"\)NSENTER" \(OPTS env <span class="token operator">--</span>ignore<span class="token operator">-</span>environment <span class="token operator">--</span><span class="token string">"\)@"
                    fi
                    fi

                      常见问题

                       
                      $ sudo nsenter -t 31340 -n netstat | grep ESTABLISHED
                      nsenter: failed to execute netstat: 没有那个文件或目录
                      
                        >
                      </article>
                      

                      与[转帖]nsenter 工具的使用相似的内容:

                      [转帖]nsenter 工具的使用

                      一、背景 对于运行在后台的docker容器,我们经常需要做的事情是进入到容器中,docker为我们提供了docker exec 、docker attach 命令,并且还提供了nsenter工具,外部工具供我们使用。 docker attach存在的问题是:当多个窗口同时attach到同一个容器时,

                      [转帖]nsenter使用

                      https://www.cnblogs.com/edeny/p/15247306.html 这个工具应该不错. 介绍 nsenter是用来进入容器内部的一个命令,它的优势之处在于可以自己选择加载容器的那些namespaces。 说直白一点就是 排查docker容器可以具备inux宿主命令的的方法。

                      [转帖]使用 nsenter、dig 和 tcpdump 调试 Kubernetes 网络问题

                      https://zhuanlan.zhihu.com/p/410217354 使用 nsenter、dig 和 tcpdump 调试 Kubernetes 网络问题 作为 Kubernetes 管理员,我经常发现自己需要调试应用程序和系统问题。我遇到的大多数问题都可以通过 Grafana 仪表板和

                      [转帖]

                      Linux ubuntu20.04 网络配置(图文教程) 因为我是刚装好的最小系统,所以很多东西都没有,在开始配置之前需要做下准备 环境准备 系统:ubuntu20.04网卡:双网卡 网卡一:供连接互联网使用网卡二:供连接内网使用(看情况,如果一张网卡足够,没必要做第二张网卡) 工具: net-to

                      [转帖]

                      https://cloud.tencent.com/developer/article/2168105?areaSource=104001.13&traceId=zcVNsKTUApF9rNJSkcCbB 前言 Redis作为高性能的内存数据库,在大数据量的情况下也会遇到性能瓶颈,日常开发中只有时刻

                      [转帖]ISV 、OSV、 SIG 概念

                      ISV 、OSV、 SIG 概念 2022-10-14 12:29530原创大杂烩 本文链接:https://www.cndba.cn/dave/article/108699 1. ISV: Independent Software Vendors “独立软件开发商”,特指专门从事软件的开发、生产、

                      [转帖]Redis 7 参数 修改 说明

                      2022-06-16 14:491800原创Redis 本文链接:https://www.cndba.cn/dave/article/108066 在之前的博客我们介绍了Redis 7 的安装和配置,如下: Linux 7.8 平台 Redis 7 安装并配置开机自启动 操作手册https://ww

                      [转帖]HTTPS中间人攻击原理

                      https://www.zhihu.com/people/bei-ji-85/posts 背景 前一段时间,公司北京地区上线了一个HTTPS防火墙,用来监听HTTPS流量。防火墙上线之前,邮件通知给管理层,我从我老大那里听说这个事情的时候,说这个有风险,然后意外地发现,很多人原来都不知道HTTPS防

                      [转帖]关于字节序(大小端)的一点想法

                      https://www.zhihu.com/people/bei-ji-85/posts 今天在一个技术群里有人问起来了,当时有一些讨论(不完全都是我个人的观点),整理一下: 为什么网络字节序(多数情况下)是大端? 早年设备的缓存很小,先接收高字节能快速的判断报文信息:包长度(需要准备多大缓存)、地

                      [转帖]awk提取某一行某一列的数据

                      https://www.jianshu.com/p/dbcb7fe2da56 1、提取文件中第1列数据 awk '{print $1}' filename > out.txt 2、提取前2列的文件 awk `{print $1,$2}' filename > out.txt 3、打印完第一列,然后打