Les conteneurs rootless
Elements des stack
- containerd
- runc
- cgroup v2
- Fakeroot : RootlessKit
- newuidmap/newgidmap
- Réseau : slirp4ns
Isolation Fakeroot avec rootlesskit
exemples pris sur RootKit
On est root et on garde les variables d'env
(host)$ rootlesskit bash
(rootlesskit)# echo $USER
penguin
(rootlesskit)# echo $HOME
/home/penguin
(rootlesskit)# echo $XDG_RUNTIME_DIR
/run/user/1001
On peut protéger des espaces disques
(host)$ rootlesskit --copy-up=/etc bash
(rootlesskit)# rm /etc/resolv.conf
(rootlesskit)# vi /etc/resolv.conf
Comment créer un accès réseau
(host)$ rootlesskit --copy-up=/etc --copy-up=/run --net=slirp4netns --disable-host-loopback bash
(rootleesskit)# ip netns add foo
Pour aller plus loin, RTFM rootlesskit --help
on décortique rootlesskit
Ce qui est lancé par docker-rootless
rootlesskit \
--state-dir=/run/user/1000/dockerd-rootless \
# Le réseau \
--net=slirp4netns \
--mtu=65520 \
--slirp4netns-sandbox=auto \
--slirp4netns-seccomp=auto \
--disable-host-loopback \
--port-driver=builtin \
# On fait une copie des fichiers de conf \
--copy-up=/etc \
--copy-up=/run \
--propagation=rslave \
/home/fccagou/src/docker/docker-rootless/dockerd-rootless.sh
state-dir, contient les éléments d'état
/run/user/1000/dockerd-rootless/
├── api.sock # socket utilisée par rootlessctl
├── child_pid # Pid du fork de rootlesskit
├── hosts # Copie du /etc/hosts de l'hôte
├── lock # lock posé par le fork de rootlesskit
└── resolv.conf # Généré par rootlesskit
Avoir des infos avec rootlessctl
rootlessctl --socket /run/user/1000/dockerd-rootless/api.sock list-ports
ID PROTO PARENTIP PARENTPORT CHILDIP CHILDPORT
7 tcp4 0.0.0.0 5000 127.0.0.1 5000
8 tcp6 :: 5000 ::1 5000
11 tcp4 0.0.0.0 5080 127.0.0.1 5080
12 tcp6 :: 5080 ::1 5080
Schéma général
%%{init: { 'logLevel': 'debug', 'theme': 'forest' } }%%
flowchart
style rootlesskit fill:#ddddff
style network fill:none,stroke-dasharray: 5 5
rootlesskit --> slirp4ns
rootlesskit --> port
rootlesskit --> mount
subgraph network
slirp4ns
port
end
subgraph mount
localmount("/etc, /run")
end
Le réseau avec slirp4ns
En rootless, slirp4ns fait actuellement l'hunanimité. Il utilise libslirp venant de qemu
# dans main.c
#define DEFAULT_CIDR ("10.0.2.0/24")
%%{init: { 'logLevel': 'debug', 'theme': 'forest' } }%%
flowchart
style slirp4ns fill:none,stroke-dasharray: 5 5
style fork fill:#ffddff,stroke-dasharray: 5 5
style parent fill:#ffeeff,stroke-dasharray: 5 5
style child fill:#ffeeff,stroke-dasharray: 5 5
style network_namespace fill:#ffddff,stroke-dasharray: 5 5
style sendmsg fill:#ffddaa
style recvmsg fill:#ffeeaa
style loop fill:#aaaaff
sendmsg([sendmsg]) -.tapfd.-> recvmsg([recvmsg])
subgraph slirp4ns
direction TB
socketpair --> fork{{fork}}
fork --> child & parent
end
subgraph child
user_namespace
network_namespace
end
subgraph network_namespace
tapc[tap] --> config_network --> sendmsg
end
subgraph config_network
lo
mac[@mac]
ip[@ip]
mtu
netmask
route
end
subgraph parent
recvmsg -->
tapp[tap] --> do_slirp["do_slirp(tapfd)"]
do_slirp --> create_sandbox --> enable_seccomp
do_slirp --> tapfd & create_slirp & create_api_socket
loop((forever send/recv msg))
tapfd --> loop
create_slirp --> loop
create_api_socket --> loop
end