docker exec进入容器的原理

容器就是一个特殊的进程,想要进入容器,先要找到容器的进程

# docker inspect --format '{{ .State.Pid }}' c054b1ef5034
5962

找到进程对应的namespace

# cd /proc/5962/ns
# ls -l
lrwxrwxrwx 1 root root 0 4月   5 12:18 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 4月   5 12:18 ipc -> 'ipc:[4026532766]'
lrwxrwxrwx 1 root root 0 4月   5 12:18 mnt -> 'mnt:[4026532764]'
lrwxrwxrwx 1 root root 0 4月   5 12:15 net -> 'net:[4026532769]'
lrwxrwxrwx 1 root root 0 4月   5 12:18 pid -> 'pid:[4026532767]'
lrwxrwxrwx 1 root root 0 4月   5 12:18 pid_for_children -> 'pid:[4026532767]'
lrwxrwxrwx 1 root root 0 4月   5 12:18 time -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 4月   5 12:18 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 4月   5 12:18 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 4月   5 12:18 uts -> 'uts:[4026532765]'

所谓进入容器(docker exec),就是在新建一个进程的时候使用容器的namespace,这个过程是使用setns()这个linux系统调用完成的。

#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE);} while (0)

int main(int argc, char *argv[]) {
    int fd;
    
    fd = open(argv[1], O_RDONLY);
    if (setns(fd, 0) == -1) {
        errExit("setns");
    }
    execvp(argv[2], &argv[2]); 
    errExit("execvp");
}

这段代码是摘抄自极客时间张磊老师《深入剖析Kubernetes》,代码作用在argv[2]进程中加入argv[1]的namespace。

# gcc -o set_ns set_ns.c
# ./set_ns /proc/5962/ns/net /bin/bash
# echo $$
6132

新进程为6132,容器进程为5962,两个进程使用的是同一个网络namespace。

# ls -l /proc/5962/ns/net 
lrwxrwxrwx 1 root root 0 4月   5 12:15 /proc/5962/ns/net -> 'net:[4026532769]'
# ls -l /proc/6132/ns/net 
lrwxrwxrwx 1 root root 0 4月   5 12:31 /proc/6132/ns/net -> 'net:[4026532769]'

在6132这个终端下查看网络,6号网卡@if7

# echo $$
6132
# ip a6: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

在宿主机上查看容器网络,7号网卡@if6

# ip a
7: vethff5a318@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether ae:34:ac:46:40:25 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::ac34:acff:fe46:4025/64 scope link 
       valid_lft forever preferred_lft forever

与docker命令行--net方式获得结果一致

# docker run -it --net container:c054b1ef5034 busybox ip a
6: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

 

posted @ 2022-04-05 13:04  沄持的学习记录  阅读(1290)  评论(0编辑  收藏  举报