• Stars
    star
    542
  • Rank 81,982 (Top 2 %)
  • Language
    Rust
  • License
    MIT License
  • Created over 8 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A container debugging tool based on FUSE

cntr

Say no to $ apt install vim in containers! cntr is a replacement for docker exec that brings all your developers tools with you. This is done by mounting the file system from one container or the host into the target container by creating a nested container with the help of a FUSE filesystem. This allows to ship minimal runtime image in production and limit the surface for exploits.

Cntr was also published in Usenix ATC 2018. See bibtex for citation.

Demo

In this two minute recording you learn all the basics of cntr:

asciicast

Features

  • For convenience cntr supports container names/identifier for the following container engines natively:
    • docker
    • podman
    • LXC
    • LXD
    • rkt
    • systemd-nspawn
    • containerd
  • For other container engines cntr also takes process ids (PIDs) instead of container names.

Installation

Cntr can be only supports linux.

Pre-build static-linked binary

For linux x86_64 we build static binaries for every release. More platforms can added on request. See the release tab for pre-build tarballs. At runtime only commandline utils of the container engine in questions are required.

Build from source

All you need for compilation is rust + cargo. Checkout rustup.rs on how to get a working rust toolchain. Then run:

Either:

$ cargo install cntr

Or the latest master:

$ cargo install --git https://github.com/Mic92/cntr

For offline builds we also provided a tarball with all dependencies bundled here for compilation with cargo-vendor.

Usage

At a high-level cntr provides two subcommands: attach and exec:

  • attach: Allows you to attach to a container with your own native shell/commands. Cntr will mount the container at /var/lib/cntr. The container itself will run unaffected as the mount changes are not visible to container processes.
    • Example: cntr attach <container_id> where container_id can be a container identifier or process id (see examples below).
  • exec: Once you are in the container, you can also run commands from the container filesystem itself. Since those might need their native mount layout at / instead of /var/lib/cntr, cntr provides exec subcommand to chroot to container again and also resets the environment variables that might have been changed by the shell.
    • Example: cntr exec <command> where command is an executable in the container

Note: Cntr needs to run on the same host as the container. It does not work if the container is running in a virtual machine while cntr is running on the hypervisor.

$ cntr --help
Cntr 1.5.1
Jörg Thalheim <[email protected]>
Enter or executed in container

USAGE:
    cntr <SUBCOMMAND>

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    attach    Enter container
    exec      Execute command in container filesystem
    help      Prints this message or the help of the given subcommand(s)
$ cntr attach --help
cntr-attach 1.5.1
Jörg Thalheim <[email protected]>
Enter container

USAGE:
    cntr attach [OPTIONS] <id> [command]...

FLAGS:
    -h, --help    Prints help information

OPTIONS:
        --effective-user <EFFECTIVE_USER>    effective username that should be owner of new created files on the host
    -t, --type <TYPE>                        Container types to try (sperated by ','). [default: all but command]
                                             [possible values: process_id, rkt, podman, docker, nspawn, lxc, lxd,
                                             containerd, command]

ARGS:
    <id>            container id, container name or process id
    <command>...    Command and its arguments to execute after attach. Consider prepending it with '-- ' to prevent
                    parsing of '-x'-like flags. [default: $SHELL]
$ cntr exec --help
cntr-exec 1.5.1
Jörg Thalheim <[email protected]>
Execute command in container filesystem

USAGE:
    cntr exec [command]...

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

ARGS:
    <command>...    Command and its arguments to execute after attach. Consider prepending it with '-- ' to prevent
                    parsing of '-x'-like flags. [default: $SHELL]

Docker

1: Find out the container name/container id:

$ docker run --name boxbusy -ti busybox
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
55a93d71b53b        busybox             "sh"                22 seconds ago      Up 20 seconds                           boxbusy

Either provide a container id...

$ cntr attach 55a93d71b53b
[root@55a93d71b53b:/var/lib/cntr]# echo "I am in a container!"
[root@55a93d71b53b:/var/lib/cntr]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
40: eth0@if41: <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
[root@55a93d71b53b:/var/lib/cntr]# vim etc/resolv.conf

...or the container name. Use cntr exec to execute container native commands (while running in the cntr shell).

$ cntr attach boxbusy
[root@55a93d71b53b:/var/lib/cntr]# cntr exec -- sh -c 'busybox | head -1'

You can also use Dockerfile from this repo to build a docker container with cntr:

$ docker build -f Dockerfile . -t cntr
# boxbusy here is the name of the target container to attach to
$ docker run --pid=host --privileged=true -v /var/run/docker.sock:/var/run/docker.sock -ti --rm cntr attach boxbusy /bin/sh

Podman

See docker usage, just replace docker with the podman command.

LXD

1: Create a container and start it

$ lxc image import images:/alpine/edge
$ lxc launch images:alpine/edge
$ lxc list
+-----------------+---------+------+------+------------+-----------+
|      NAME       |  STATE  | IPV4 | IPV6 |    TYPE    | SNAPSHOTS |
+-----------------+---------+------+------+------------+-----------+
| amazed-sailfish | RUNNING |      |      | PERSISTENT | 0         |
+-----------------+---------+------+------+------------+-----------+

2: Attach to the container with cntr

$ cntr attach amazed-sailfish
$ cat etc/hostname
amazed-sailfish

LXC

1: Create a container and start it

$ lxc-create --name ubuntu -t download -- -d ubuntu -r xenial -a amd64
$ lxc-start --name ubuntu -F
...
Ubuntu 16.04.4 LTS ubuntu console
ubuntu login:
$ lxc-ls
ubuntu

2: Attach to container with cntr:

$ cntr attach ubuntu
[root@ubuntu2:/var/lib/cntr]# cat etc/os-release
NAME="Ubuntu"
VERSION="16.04.4 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.4 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial

rkt

1: Find out the container uuid:

$ rkt run --interactive=true docker://busybox
$ rkt list
UUID            APP     IMAGE NAME                                      STATE   CREATED         STARTED         NETWORKS
c2d2e87e        busybox registry-1.docker.io/library/busybox:latest     running 6 minutes ago   6 minutes ago   default:ip4=172.16.28.3

2: Attach with cntr

# make sure your container is still running!
$ cntr attach c2d2e87e
# Finally not the old ugly top!
[gen0@rkt-c2d2e87e-e798-4341-ae93-26f6cbb7c017:/var/lib/cntr]# htop
...

With cntr you can also debug stage1 of rkt - even there is no support from rkt itself.

$ ps aux | grep stage1
joerg    13546  0.0  0.0 120808  1608 pts/12   S+   11:10   0:00 grep --binary-files=without-match --directories=skip --color=auto stage1
root     22232  0.0  0.0  54208  2656 pts/7    S+   10:54   0:00 stage1/rootfs/usr/lib/ld-linux-x86-64.so.2 stage1/rootfs/usr/bin/systemd-nspawn --boot --notify-ready=yes --register=true --link-journal=try-guest --quiet --uuid=c2d2e87e-e798-4341-ae93-26f6cbb7c017 --machine=rkt-c2d2e87e-e798-4341-ae93-26f6cbb7c017 --directory=stage1/rootfs --capability=CAP_AUDIT_WRITE,CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FSETID,CAP_FOWNER,CAP_KILL,CAP_MKNOD,CAP_NET_RAW,CAP_NET_BIND_SERVICE,CAP_SETUID,CAP_SETGID,CAP_SETPCAP,CAP_SETFCAP,CAP_SYS_CHROOT -- --default-standard-output=tty --log-target=null --show-status=0

Therefore we use the process id instead of the container uuid:

$ cntr attach 22232
# new and exiting territory!
[root@turingmachine:/var/lib/cntr]# mount | grep pods
sysfs on /var/lib/cntr/var/lib/rkt/pods/run/c2d2e87e-e798-4341-ae93-26f6cbb7c017/stage1/rootfs/sys type sysfs (ro,nosuid,nodev,noexec,relatime)
tmpfs on /var/lib/cntr/var/lib/rkt/pods/run/c2d2e87e-e798-4341-ae93-26f6cbb7c017/stage1/rootfs/sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
cgroup on /var/lib/cntr/var/lib/rkt/pods/run/c2d2e87e-e798-4341-ae93-26f6cbb7c017/stage1/rootfs/sys/fs/cgroup/memory type cgroup (ro,nosuid,nodev,noexec,relatime,memory)

systemd-nspawn

1: Start container

$ wget https://cloud-images.ubuntu.com/releases/16.04/release/ubuntu-16.04-server-cloudimg-amd64-root.tar.xz
$ mkdir /var/lib/machines/ubuntu
$ tar -xf ubuntu-16.04-server-cloudimg-amd64-root.tar.xz -C /var/lib/machines/ubuntu
$ systemd-nspawn -b -M ubuntu
$ machinectl list
MACHINE CLASS     SERVICE        OS     VERSION ADDRESSES
ubuntu  container systemd-nspawn ubuntu 16.04   -

2: Attach

$ cntr attach ubuntu

Generic process id

The minimal information needed by cntr is the process id of a container process you want to attach to.

# Did you now chromium uses namespaces too?
$ ps aux | grep 'chromium --type=renderer'
joerg    17498 11.7  1.0 1394504 174256 ?      Sl   15:16   0:08 /usr/bin/chromium

In this case 17498 is the pid we are looking for.

$ cntr attach 17498
# looks quite similar to our system, but with less users
[joerg@turingmachine cntr]$ ls -la /
total 240
drwxr-xr-x   23 nobody nogroup    23 Mar 13 15:05 .
drwxr-xr-x   23 nobody nogroup    23 Mar 13 15:05 ..
drwxr-xr-x    2 nobody nogroup     3 Mar 13 15:14 bin
drwxr-xr-x    4 nobody nogroup 16384 Jan  1  1970 boot
drwxr-xr-x   24 nobody nogroup  4120 Mar 13 14:56 dev
drwxr-xr-x   52 nobody nogroup   125 Mar 13 15:14 etc
drwxr-xr-x    3 nobody nogroup     3 Jan  8 16:17 home
drwxr-xr-x    8 nobody nogroup     8 Feb  9 22:10 mnt
dr-xr-xr-x  306 nobody nogroup     0 Mar 13 09:38 proc
drwx------   22 nobody nogroup    43 Mar 13 15:09 root
...

Containerd

For containerd integration the ctr binary is required. You can get a binary by running:

$ GOPATH=$(mktemp -d)
$ go get github.com/containerd/containerd/cmd/ctr
$ $GOPATH/bin/ctr --help

Put the resulting ctr binary in your $PATH

1: Start container

$ ctr images pull docker.io/library/busybox:latest
$ ctr run docker.io/library/busybox:latest boxbusy
$ ctr tasks lists
TASK        PID      STATUS
boxbusy    24310    RUNNING

2: Attach

$ cntr attach boxbusy

It's also possible to run cntr from a container itself. This repository contains a example Dockerfile for that:

$ docker build -f Dockerfile.example . -t cntr
$ docker save cntr > cntr.tar
$ ctr images import --base-name cntr ./cntr.tar

In this example we attach to containerd by process id. The proccess id of a task is given in ctr tasks list.

$ ctr run --privileged --with-ns pid:/proc/1/ns/pid --tty docker.io/library/cntr:latest cntr /usr/bin/cntr attach 31523 /bin/sh

To resolve containerd names one also would need to add the ctr binary (~12mb) to the Dockerfile.

Additional Config

ZFS

cntr requires POSIX ACLs be enabled under ZFS. By default, Linux ZFS doesn't have POSIX ACLs enabled. This results in the following error when trying to attach:

unable to move container mounts to new mountpoint: EOPNOTSUPP: Operation not supported on transport endpoint

To enable POSIX ACLs on the ZFS dataset:

$ zfs set acltype=posixacl zpool/media
$ zfs set xattr=sa zpool/media              #  optional, but encouraged for best perfomance

How it works

Cntr is container-agnostic: Instead of interfacing with container engines, it implements the underlying operating system API. It treats every container as a group of processes, that it can inherit properties from.

Cntr inherits the following container properties:

  • Namespaces (mount, uts, pid, net, cgroup, ipc)
  • Cgroups
  • Apparamor/selinux
  • Capabilities
  • User/group ids
  • Environment variables
  • The following files: /etc/passwd, /etc/hostname, /etc/hosts, /etc/resolv.conf

Under the hood it spawns a shell or user defined program that inherits the full context of the container and mount itself as a fuse filesystem.

We extensively evaluated the correctness and performance of cntr's filesystem using xfstests and a wide range of filesystem performance benchmarks (iozone, pgbench, dbench, fio, fs-mark, postmark, ...)

Related projects

  • nsenter
    • Only covers linux namespaces and the user is limited to tools installed in the containers
  • toolbox
    • Does attach from a container to the host, this is the opposite of what Cntr is doing

Bibtex

We published a paper with all technical details about Cntr in Usenix ATC 2018.

@inproceedings{cntr-atc18,
  author = {J{\"o}rg Thalheim and Pramod Bhatotia and Pedro Fonseca and Baris Kasikci},
  title = {Cntr: Lightweight {OS} Containers},
  booktitle = {2018 {USENIX} Annual Technical Conference ({USENIX} {ATC} 18)},
  year = {2018},
}

More Repositories

1

sops-nix

Atomic secret provisioning for NixOS based on sops
Nix
1,439
star
2

nix-update

Swiss-knife for updating nix packages.
Python
459
star
3

nixos-shell

Spawns lightweight nixos vms in a shell
Nix
423
star
4

nix-ld

Run unpatched dynamic binaries on NixOS
C
422
star
5

nixpkgs-review

Review pull-requests on https://github.com/NixOS/nixpkgs
Python
383
star
6

python-mpd2

Python library which provides a client interface for the Music Player Daemon.
Python
353
star
7

dotfiles

My NixOS dotfiles
Nix
299
star
8

nix-fast-build

Combine the power of nix-eval-jobs with nix-output-monitor to speed-up your evaluation and building process.
Python
210
star
9

envfs

Fuse filesystem that returns symlinks to executables based on the PATH of the requesting process.
Rust
133
star
10

vmsh

Shell into a virtualized linux, with your own tools
Rust
132
star
11

mina-sidekiq

Tasks to deploy Sidekiq with mina.
Ruby
91
star
12

nix-build-uncached

A CI friendly wrapper around nix-build.
Go
72
star
13

zig.ko

Linux kernel module written in Zig
Makefile
70
star
14

nixos-aarch64-images

Build NixOS images for various ARM single computer boards
Python
49
star
15

x86_64-linux-cheatsheats

Plain files for syscalls, errnos, signals, registers and x86_64 instructions
Python
49
star
16

pry.py

pry.py - an interactive drop in shell for python, similar to binding.pry in ruby
Python
49
star
17

ssh-to-age

Convert SSH Ed25519 keys to age keys. This is useful for usage in sops-nix and sops
Go
47
star
18

hue-ble-ctl

Control your Phillips Hue light bulb over bluetooth
Python
33
star
19

pythonix

Eval nix code from python
C++
32
star
20

awesome-dotfiles

Configuration files of the window manager awesome
Lua
28
star
21

fast-flake-update

Update flake.lock with the latest commit of a local checkout
Python
27
star
22

nur-packages

My personal NUR repository
Nix
23
star
23

flake-linter

Find duplicate dependencies in flakes
Python
18
star
24

ansible-lxc

Ansible Connection Plugin for lxc containers (https://linuxcontainers.org/)
Python
17
star
25

iana-etc

Build /etc/protocols and /etc/services files from IANA's Assigned Internet Protocol Numbers
Python
17
star
26

lognotify

log watcher for awesome wm
Lua
14
star
27

nix-sysdig

Wrapper to debug sysdig builds
Python
13
star
28

github-tags

sinatra app to generate rss feeds with the latest git tags of a project on github
Ruby
12
star
29

nixican-standoff

Benchmark between nix, lix and tvix
Python
12
star
30

whois42d

Whois server for the dn42 registry
Go
11
star
31

ssh-to-pgp

Convert SSH RSA keys to GPG keys
Go
11
star
32

utils

A set of lua modules I use in awesome wm.
Lua
9
star
33

stockholm

Mirror of https://git.thalheim.io/Mic92/stockholm/
Nix
9
star
34

bing-gpt-server

HTML
8
star
35

flake-templates

Personal templates i like to use.
Nix
7
star
36

valauncher

A fast dmenu-like gtk3 application launcher
CMake
7
star
37

dlopen-resolver

Python
7
star
38

openvpn-ddns

Maintain dns records for connecting openvpn clients
Ruby
7
star
39

dream2nix-home-assistant

Packaging experiments with dream2nix to package home-assistant with all dependencies.
Nix
5
star
40

kvm-pirate

Attach to kvm-based VMs
Python
5
star
41

mechanical-keyboards

Configuration of my collections of keyboards
Nix
4
star
42

systemd-ta

http://c3d2.de/news/ta-systemd.html
JavaScript
4
star
43

nix-build-shell

Rust
4
star
44

robolab

Simulator for the course Robolab at TU Dresden
4
star
45

nixos-test-example

Nix
4
star
46

retiolum

Mirror of https://git.thalheim.io/Mic92/retiolum
Nix
4
star
47

server-bookings

Rust
3
star
48

Algebra-I

Das inoffizielle Skript zur Vorlesung bei Prof. Schmidt
Ruby
3
star
49

nix-fmt

abandoned in favor of https://github.com/orivej/go-nix and https://gitlab.com/jD91mZM2/rnix
OCaml
3
star
50

imap-notify

IMAP notifier using IMAP's NOTIFY SET
Python
3
star
51

docker-pid

Resolve container id/name to container's process id
Go
3
star
52

nftables

Mirror of netfilter/nftables
C
3
star
53

nixos-configuration

The content of this repo has been integrated into https://github.com/Mic92/dotfiles/
3
star
54

mpdtools

Usefull tools for MPD: mpdadd - Link and play files outside of the MPD directory to MPD. mpdmark - bookmark songs
Ruby
3
star
55

nsattach

attach to linux namespaces
C
3
star
56

bors-gen-config

Generate bors.toml for github repositories
Python
2
star
57

int3

Better debugger breakpoints
Python
2
star
58

vtune-nix

Vtune nix package
Nix
2
star
59

live-net-info

My adventures using the bubbletea framework.
Go
2
star
60

blog

Source of my blog
Shell
2
star
61

themenabend-nixos

Folien und Code zum Themenabend über Nix/Nixos
JavaScript
2
star
62

lxc-machined-start

Integrate lxc container into machined
M4
2
star
63

company-tmux

emacs auto complete with content of tmux panes
Emacs Lisp
2
star
64

pgp-verify

Verify pgp signatures of files.
Go
2
star
65

build-system-koans

C
2
star
66

SWT_And_Programming

Programs/Stubs created during exercises at university.
Java
2
star
67

mpdstated

Auto restore recent position for each podcast in mpd.
Vala
2
star
68

bme680-mqtt

Publish BME680 sensor data to home-assistant via MQTT
Python
2
star
69

container-pid

Rust crate to resolve a container names/ids to PID
Rust
2
star
70

nixcon2023-nixos-anywhere

Presentation slides for NixCon 2023 presentation on nixos-anywhere
JavaScript
2
star
71

systemd-user-units

2
star
72

nixos-wiki-redirector

JavaScript
2
star
73

disko-yubikey-demo

Nix
2
star
74

scripts

All my tiny scripts and stubs
Shell
1
star
75

lualdap

fork of https://git.zx2c4.com/lualdap/ with lua5.3 support
C
1
star
76

pcap-preload

Rust
1
star
77

nixpkgs-committers

Repository for nominating maintainers for Nixpkgs commit access
1
star
78

mic92.github.com

1
star
79

phd-website

HTML
1
star
80

ports

my freebsd ports
Makefile
1
star
81

drone-convert-nix

Go
1
star
82

webscraping-workshop

Folien und Code zum Webscraping workshop auf den Datenspuren 2015
JavaScript
1
star
83

qtile-config

Python
1
star
84

semeion

A DynDNS Server interface in Haskell and Yesod
Haskell
1
star
85

hadoop-exercise

MapReduce Assignment 2015 at System Engineering II (TU Dresden)
Java
1
star
86

xfstests-cntr

Fork of xfstests with support for cntr
Shell
1
star
87

fuidshift

Move Filesystem ownership into other subordinated uid ranges
Go
1
star
88

android-notifier

Automatically exported from code.google.com/p/android-notifier
Java
1
star
89

fft

FFT Implementation for Tensilica DSP Processors
C
1
star
90

userborn-with-impermanence

Nix
1
star
91

drone-nix-scheduler

Schedule nix jobsets in drone ci
Python
1
star
92

arch-package-feed

bottle.py based project to provide a more advanced arch package feed.
Python
1
star
93

PKGBUILDs

My PKGBUILDs of Packages I maintain in Archlinux AUR
Shell
1
star
94

tracedump

System service to dump Intel processor trace + memory after a crash.
Python
1
star
95

Japanese-sum-solver

A solver for the logic game Japsum
JavaScript
1
star
96

clusterssh

wrapper arround go-ssh to execute commands in a cluster
Go
1
star