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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM