需求

我想进入容器中执行 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. 从Redis7.0发布看Redis的过去与未来

    简介: 经历接近一年的开发.三个候选版本,Redis 7.0终于正式发布,这是Redis历史上改变最多的一个大版本,它不仅包含了50多个新命令,还有大量核心新特性与改进,这些不仅能够解决用户使用中的诸 ...

  2. 关于CDN的原理、术语和应用场景那些事

    关于CDN,想必你一定看过很多官方的解释.今天,CDN百科第七期,将用一篇3844字的文章,来带你了解CDN的诞生.术语.原理.特征以及应用场景,看完这篇文章,相信你将会对CDN这项互联网基础设施有更 ...

  3. 阿里巴巴开源大规模稀疏模型训练/预测引擎DeepRec

    ​简介:经历6年时间,在各团队的努力下,阿里巴巴集团大规模稀疏模型训练/预测引擎DeepRec正式对外开源,助力开发者提升稀疏模型训练性能和效果. ​ 作者 | 烟秋 来源 | 阿里技术公众号 经历6 ...

  4. 前沿分享|阿里云数据库资深技术专家 姚奕玮:AnalyticDB MySQL离在线一体化技术揭秘

    ​简介: 本篇内容为2021云栖大会-云原生数据仓库AnalyticDB技术与实践峰会分论坛中,阿里云数据库资深技术专家 姚奕玮关于"AnalyticDB MySQL离在线一体化技术揭秘&q ...

  5. 如何开发 Node.js Native Add-on?

    简介: 来一起为 Node.js 的 add-on 生态做贡献吧~ 作者 | 吴成忠(昭朗) 这篇文章是由 Chengzhong Wu (@legendecas),Gabriel Schulhof ( ...

  6. 基于MaxCompute+PAI的用户增长方案实践

    ​简介: 如何通过PAI+MaxCompute完成用户增长模型AARRR全链路,包含拉新.促活.留存.创收.分享. 本文作者 李博 阿里云智能 高级产品专家 在过去一年阿里云PAI机器学习团队做了很多 ...

  7. [Kali] Kali Linux 环境准备

      虚拟机和系统: Mac 的 Vmware Fusion:https://www.vmware.com/cn/products/fusion/fusion-evaluation.html  序列号去 ...

  8. [FAQ] docker-ce depends on containerd.io, docker-ce depends on docker-ce-cli

    安装 docker 缺少依赖会提示你安装,一般是以下两个: Package containerd.io is not installed Package docker-ce-cli is not in ...

  9. [Go] Viper 加载项目配置,go build 打包配置文件进二进制

    Viper 的传统用法局部,加载到某个 package 下的全局变量后,其它 package 可以继续使用. var Conf *viper.Viper func init() { // File n ...

  10. 9.prometheus监控--监控springboot2.x(Java)

    一.环境部署 yum search java | grep jdk yum install -y java-11-openjdk-devel 二.监控java应用(tomcat/jar) JMX ex ...