需求

我想进入容器中执行 curl 命令探测某个地址的连通性,但是容器镜像里默认没有 curl 命令。我这里是一个内网环境不太方便使用 yum 或者 apt 安装,怎么办?

这个需求比较典型,这里教大家一个简单的方法,使用 nsenter 进入容器的 net namespace,即可使用宿主机的 curl、ip、ifconfig 等命令,其效果,就跟进入容器中执行是一样的。

原理

容器像是一个轻量级虚拟机,有自己的 IP,宿主机如果已经监听了 8080 端口,容器里的进程仍然可以重复监听 8080 端口。核心就是因为容器有自己的 namespace,和宿主机的 net namespace 互不影响。关于容器的 namespace 相关知识,可以 Google 一下关键字:「容器 namespace 原理」。

nsenter,是个关键工具。其用法如下:

nsenter --help

用法:
 nsenter [选项] [<程序> [<参数>...]] 以其他程序的名字空间运行某个程序。 选项:
 -a, --all              enter all namespaces
 -t, --target <pid>     要获取名字空间的目标进程
 -m, --mount[=<文件>]   进入 mount 名字空间
 -u, --uts[=<文件>]     进入 UTS 名字空间(主机名等)
 -i, --ipc[=<文件>]     进入 System V IPC 名字空间
 -n, --net[=<文件>]     进入网络名字空间
 -p, --pid[=<文件>]     进入 pid 名字空间
 -C, --cgroup[=<文件>]  进入 cgroup 名字空间
 -U, --user[=<文件>]    进入用户名字空间
 -S, --setuid <uid>     设置进入空间中的 uid
 -G, --setgid <gid>     设置进入名字空间中的 gid
     --preserve-credentials 不干涉 uid 或 gid
 -r, --root[=<目录>]     设置根目录
 -w, --wd[=<dir>]       设置工作目录
 -F, --no-fork          执行 <程序> 前不 fork
 -Z, --follow-context  根据 --target PID 设置 SELinux 环境  -h, --help             display this help
 -V, --version          display version 更多信息请参阅 nsenter(1)。

通过 nsenter -t <pid> -n bash 即可进入 pid 指向的进程的 net namespace,并在这个 namespace 执行 bash 命令,之后,在这个 bash session 里执行 curl、ip、ifconfig 等命令,看到的网络信息就都是容器内部的网络信息。

实战

在 Linux 上,通过夜莺的 docker-compose 拉起一套夜莺,使用 bridge 模式,做个演示。

1. 拉起夜莺

[root@aliyun-2c2g40g3m compose-bridge]# docker compose up -d
[+] Running 7/7
  Network compose-bridge_nightingale  Created                                                                                                                                                                                                                                                                                     0.1s
  Container redis                     Started                                                                                                                                                                                                                                                                                     0.1s
  Container victoriametrics           Started                                                                                                                                                                                                                                                                                     0.1s
  Container mysql                     Started                                                                                                                                                                                                                                                                                     0.1s
  Container ibex                      Started                                                                                                                                                                                                                                                                                     0.1s
  Container nightingale               Started                                                                                                                                                                                                                                                                                     0.1s
  Container categraf                  Started

然后,inspect 一下 nightingale 容器,拿到其 Pid:

[root@aliyun-2c2g40g3m compose-bridge]# docker ps |grep nigh
0500a886538e   flashcatcloud/nightingale:latest            "sh -c /app/n9e"          31 minutes ago   Up 31 minutes   0.0.0.0:17000->17000/tcp, :::17000->17000/tcp                                                  nightingale
[root@aliyun-2c2g40g3m compose-bridge]# docker inspect 0500a886538e |grep Pid
            "Pid": 1619207,
            "PidMode": "",
            "PidsLimit": null,

2.根据 Pid 进入 net namespace

1619207 就是 Pid,根据此 Pid 进入容器的 net namespace:

[root@aliyun-2c2g40g3m compose-bridge]# nsenter -t 1619207 -n bash
[root@aliyun-2c2g40g3m compose-bridge]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.22.0.6  netmask 255.255.0.0  broadcast 172.22.255.255
        ether 02:42:ac:16:00:06  txqueuelen 0  (Ethernet)
        RX packets 104463  bytes 33707078 (32.1 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 89615  bytes 10817199 (10.3 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 112  bytes 7096 (6.9 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 112  bytes 7096 (6.9 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

如上,使用 bash 命令进入 net namespace,然后执行 ifconfig,看到 IP:172.22.0.6,显然这就是容器的 IP,说明 nsenter 达成所愿,之后在这个 bash session 内执行 curl、telnet 之类的,就相当于在容器里执行一样的效果。完事执行 exit 命令可以退出这个 net namespace。

补充知识

上面的 1619207 这个 Pid 其实就是容器的一号进程的 Pid,在宿主机上执行下面的命令可以看出:

[root@aliyun-2c2g40g3m compose-bridge]# ps aux|grep n9e
root     1619207  0.0  0.0   2576   888 ?        Ss   15:22   0:00 sh -c /app/n9e
root     1619327  0.4  4.0 741264 78720 ?        Sl   15:22   0:09 /app/n9e
root     1620612  0.0  0.0 221528   864 pts/0    S+   16:01   0:00 grep --color=auto n9e

夜莺这个容器,核心执行的命令是 /app/n9e,不过在 docker-compose.yaml 中 command 写的是:

sh -c "/app/n9e"

所以这个容器的一号进程就是 sh 了。1619207 和 1619327 这俩进程是在一个容器里的,也就是在一个 net namespace 中的,这俩 Pid 都可以用于 nsenter,效果是一样的。

补充知识2

除了 nsenter,使用 ip netns exec 也可以达到类似的效果。通过 ip netns help 可以看到相关帮助信息。

[root@aliyun-2c2g40g3m compose-bridge]# ip netns help
Usage: ip netns list
 ip netns add NAME
 ip netns attach NAME PID
 ip netns set NAME NETNSID
 ip [-all] netns delete [NAME]
 ip netns identify [PID]
 ip netns pids NAME
 ip [-all] netns exec [NAME] cmd ...
 ip netns monitor
 ip netns list-id [target-nsid POSITIVE-INT] [nsid POSITIVE-INT]
NETNSID := auto | POSITIVE-INT

从上面的 help 信息可以看出,要执行 ip netns exec,需要知道 net namespace 的 NAME,如何找到容器的 net namespace name 呢?

实际上,在 Linux 中,每个进程只要知道其 Pid 了,根据 Pid 就可以找到 net namespace 了,比如上面的例子,我们知道进程的 Pid 是:1619207,其 net namespace 就是:/proc/1619207/ns/net

但是,执行 ip netns list 却看不到,这是因为,ip netns list 是罗列的 /var/run/netns/ 下面的内容,而容器的 net namespace 并未挂到这里,此时,我们只需要做个软链挂过去即可:

ln -s /proc/1619207/ns/net /var/run/netns/1619207

如果发现 /var/run/netns 目录不存在,使用 root 账号 mkdir 一下即可。之后,我们就可以使用 ip netns exec 了:

ip netns exec 1619207 ifconfig

看到的输出和 nsenter 方式看到的输出是一样的。

如上,希望这个小知识可以帮到大家。


本公众号主理人:秦晓辉,极客时间《运维监控系统实战笔记》作者,Open-Falcon、夜莺、Categraf、Cprobe 等开源项目的创始人,当前在创业,为客户提供可观测性相关的产品。如下是我们两款核心产品,欢迎访问我们的官网了解详情:
我们主要提供两款产品:
 
欢迎加我好友,交流可观测性相关话题或了解我们的商业产品,如下是我的联系方式,加好友请备注您的公司、姓名、来意
 
扩展阅读:

使用 nsenter 排查容器网络问题的更多相关文章

  1. 理解Docker(6):若干企业生产环境中的容器网络方案

    本系列文章将介绍 Docker的相关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...

  2. 容器网络——从CNI到Calico

    从容器诞生开始,存储和网络这两个话题就一直为大家津津乐道.我们今天这个环境下讲网络这个问题,其实是因为容器对网络的需求,和传统物理.虚拟环境对网络环境需求是有差别的,主要面临以下两个问题: 过去Iaa ...

  3. Kubernetes & Docker 容器网络终极之战(十四)

    目录 一.单主机 Docker 网络通信 1.1.host 模式 1.2 Bridge 模式 1.3 Container 模式 1.4.None 模式 二.跨主机 Docker 网络通信分类 2.1 ...

  4. kubernetes/k8s CNI分析-容器网络接口分析

    关联博客:kubernetes/k8s CSI分析-容器存储接口分析 kubernetes/k8s CRI分析-容器运行时接口分析 概述 kubernetes的设计初衷是支持可插拔架构,从而利于扩展k ...

  5. Linux namespace技术应用实践--调用宿主机命令(tcpdump/ip/ps/top)检查docker容器网络、进程状态

    背景 最近偶然听了几堂极客时间的云原生免费公开课程,首次接触到了Linux namespace技术,并了解到这正是现在风头正劲的容器技术基石,引起了自己探究一二的兴趣,结合课程+网络搜索+实践操作,也 ...

  6. Docker的单主机容器网络

    作者:杨冬 欢迎转载,也请保留这段声明.谢谢! 出处: https://andyyoung01.github.io/ 或 http://andyyoung01.16mb.com/ 本篇文章主要探索Do ...

  7. 理解Docker单机容器网络

    在” 理解Docker单机容器网络 “一文中,还有一个Docker容器网络的功能尚未提及,那就是Docker容器的端口映射.即将容器的服务端口P’ 绑定到宿主机的端口P上,最终达到一种效果:外部程序通 ...

  8. 【Networking】容器网络大观 && SDN 资料汇总

    SDNLAB技术分享(十五):容器网络大观   SDNLAB君• 16-06-17 •2957 人围观 编者按:本文系SDNLAB技术分享系列,本次分享来自SDN撕X群(群主:大猫猫)群直播,我们希望 ...

  9. docker1.12在cento7里的跨多主机容器网络

    docker1.12在cento7里的跨多主机容器网络

  10. 从 Kubernetes 谈容器网络

    基本概念 在 Kubernetes 中.资源从管理粒度上分为三级:容器.Pod.Service. 容器 即 Docker 或者 Rocket 容器(1.0 中仅支持这两种容器). 容器是最低粒度的资源 ...

随机推荐

  1. 力扣5(java)-最长回文串(中等)

    题目: 给你一个字符串 s,找到 s 中最长的回文子串. 示例 1: 输入:s = "babad"输出:"bab"解释:"aba" 同样是符 ...

  2. 牛客网-SQL专项训练7

    ①SQL语言可以分为多个类别,那么不属于数据操纵语言DML的是(B) 解析: SQL语言共分为四大类:数据查询语言DQL,数据操纵语言DML,数据定义语言DDL,数据控制语言DCL. 1. 数据查询语 ...

  3. 科普达人丨漫画图解SGX加密计算黑科技

    介: 运行态的数据也可以被加密,实现数据可用不可见. 01 从一场朋友圈的"赛富"说起 最近,小明买基金赚了不少钱,开始膨胀了,开始在朋友圈里晒豪车.晒爱马仕.小红表示不服,&qu ...

  4. KubeDL HostNetwork:加速分布式训练通信效率

    ​简介:ubeDL 为分布式训练作业带来了 HostNetwork 网络模式,支持计算节点之间通过宿主机网络相互通信以提升网络性能,同时适应 RDMA/SCC 等新型高性能数据中心架构的网络环境,此外 ...

  5. 阿里云边缘云全新架构升级,助力CDN操控新体验

    ​简介: 本次升级根据上万企业客户的使用反馈和行业应用特征,从简单开通到个性化定制,从内容分发到边缘计算完整解决方案,对客户侧的使用体验进行了全局梳理和全链路优化,推进边缘云CDN操控革新,并逐步构建 ...

  6. WPF 基于 .NET 5 框架和 .NET 6 的 SDK 进行完全单文件发布

    本文来告诉大家如何基于 .NET 5 框架和 .NET 6 SDK 进行完全单文件发布,这是对 WPF 应用程序进行独立发布,生成的是完全单文件的方法 在之前的版本,尽管也是基于 .NET 5 框架的 ...

  7. C#的基于.net framework的Dll模块编程(四) - 编程手把手系列文章

    这次继续这个系列的介绍: 一.命名空间的起名: 对于C#来说,一般命名空间的建议是:公司名(或个人名称).产品名.分类名,比如我这边是用的这个:Lzhdim.LPF.Helper,意思是个人名Lzhd ...

  8. 为什么我反对过度使用TypeScript?

    前言 在2024年, TypeScript肯定算不上什么新鲜的技术. 但是经过长时间的使用, 我认为可以使用, 但是要适度. 类型跟不上业务的变化 我们知道TypeScript的类型定义是业务的体现. ...

  9. 02. rails安装

    rails安装 ruby 1.8.6 对应的rails是2.3.2 Ruby 1.8.7 或 1.9.2 对应的rails 2.3.x ruby1.9.3,对应的rails是3.2.12, ruby2 ...

  10. CentOS加载yum源时报错 [Errno 14] HTTP Error 404 - Not Found Trying other mirror.

    报错内容: [root@192 yum.repos.d]# yum repolist Loaded plugins: fastestmirror, product-id, search-disable ...