• 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
  • 相关阅读:
    安装 Panda3D 并使用原有的Python
    Jupyter Notebook PDF输出的中文支持
    lua的文件管理
    elasticsearch-hadoop.jar, 适用于spark3,hadoop3
    shell中递归遍历指定文件夹下的文件
    JDBC的ResultSet游标转spark的DataFrame,数据类型的映射以TeraData数据库为例
    Pandas一些小技巧
    用c++后缀自动机实现最大公共字符串算法,并封装成Python库
    后缀自动机的python实现
    PYTHON调用C接口(基于Ctypes)实现stein算法最大公约数的计算
  • 原文地址:https://www.cnblogs.com/maxgongzuo/p/16101986.html
Copyright © 2020-2023  润新知