1 1 # cdebug - experimental container debugger (WIP) 2 2 3 - A handy way of troubleshooting containers lacking a shell and/or debugging tools 4 - (e.g, scratch, slim, or distroless). 3 + A handy way to troubleshoot containers lacking a shell and/or debugging tools 4 + (e.g, scratch, slim, or distroless): 5 + 6 + ```sh 7 + # Simple (busybox) 8 + $ cdebug exec -it <target-container> 9 + 10 + # Advanced (shell + ps + vim) 11 + $ cdebug exec -it --image nixery.dev/shell/ps/vim <target-container> 12 + ``` 5 13 6 14 The `cdebug exec` command is some sort of crossbreeding of `docker exec` and `kubectl debug` commands. 7 15 You point the tool at a running container, say what toolkit image to use, and it starts skipped 6 lines 14 22 15 23 Currently supported toolkit images: 16 24 17 - - `busybox` - a good default choice 18 - - `nixery.dev/shell/...` - [a very powerful way to assemble images on the fly](https://nixery.dev/). 25 + - `busybox` - a good default choice 26 + - `nixery.dev/shell/...` - [a very powerful way to assemble images on the fly](https://nixery.dev/). 19 27 20 28 Supported runtimes: 21 29 skipped 3 lines 25 33 - Kubernetes (via the API server) - coming later 26 34 - runc or alike (via directly invoking the CLI) - coming later. 27 35 28 - ## How it works 29 - 30 - The technique is based on the ideas from this [blog post](https://iximiuz.com/en/posts/docker-debug-slim-containers). 31 - Oversimplifying, the debugger container is started like: 32 - 33 - ```sh 34 - docker run [-it] \ 35 - --network container:<target> \ 36 - --pid container:<target> \ 37 - --uts container:<target> \ 38 - <toolkit-image> 39 - sh -c <<EOF 40 - ln -s /proc/$$/root/bin/ /proc/1/root/.cdebug 41 - 42 - export PATH=$PATH:/.cdebug 43 - chroot /proc/1/root sh 44 - EOF 45 - ``` 46 - 47 - The secret sauce is the symlink + PATH modification + chroot-ing. 48 - 49 36 ## Demo 1: An interactive shell with busybox 50 37 51 38 First, a target container is needed. Let's use a distroless nodejs image for that: skipped 30 lines 82 69 ... 83 70 ``` 84 71 85 - Notice the emoji above - that's where the debugging tools live: 72 + Notice above - that's where the debugging tools live: 86 73 87 74 ```sh 88 75 / $# echo $PATH 89 76 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/.cdebug-c153d669 90 77 ``` 91 78 92 - The process tree is also common: 79 + The process tree of the debugger container is the process tree of the target: 93 80 94 81 ```sh 95 82 / # ps auxf skipped 7 lines 103 90 45 root 0:00 ps auxf 104 91 ``` 105 92 106 - ## Demo 2: An interactive shell with advanced tools 93 + ## Demo 2: An interactive shell with advanced tools and code editor 107 94 108 95 If the tools provided by busybox aren't enough, you can bring your own tools with 109 96 a ~~little~~ huge help of the [nixery](https://nixery.dev/) project: 110 97 111 98 ```sh 112 - cdebug exec -it --image nixery.dev/shell/ps/findutils/tcpdump my-distroless 99 + cdebug exec -it --image nixery.dev/shell/ps/findutils/tcpdump/ vim my-distroless 113 100 ``` 114 101 115 - ## TODO: 102 + ## How it works 103 + 104 + The technique is based on the ideas from this [blog post](https://iximiuz.com/en/posts/docker-debug-slim-containers). 105 + Oversimplifying, the debugger container is started like: 116 106 117 - - Terminal resizing ([example](https://github.com/docker/cli/blob/110c4d92b883357c9fb3edc344c4fbec5f77896f/cli/command/container/tty.go#L71)) 118 - - More `exec` flags (like in `docker run`) 119 - - Helper command(s) suggesting nix(ery) packages 120 - - E2E Tests 121 - - Cross-platform builds 122 - - Non-docker runtimes (containerd, runc, k8s) 107 + ```sh 108 + docker run [-it] \ 109 + --network container:<target> \ 110 + --pid container:<target> \ 111 + --uts container:<target> \ 112 + <toolkit-image> 113 + sh -c <<EOF 114 + ln -s /proc/$$/root/bin/ /proc/1/root/.cdebug 115 + 116 + export PATH=$PATH:/.cdebug 117 + chroot /proc/1/root sh 118 + EOF 119 + ``` 120 + 121 + The secret sauce is the symlink + PATH modification + chroot-ing. 123 122 124 123 ## Similar tools 125 124 skipped 2 lines 128 127 - [`docker-opener`](https://github.com/artemkaxboy/docker-opener) - a multi-purpose tool that in particular can run a shell session into your container (and if there is no shell inside, it'll bring its own busybox). 129 128 - [`cntr`](https://github.com/Mic92/cntr) - is "a replacement for `docker exec` that brings all your developers tools with you" by mounting the file system from one container (or the host) into the target container and creating a nested container with the help of a FUSE filesystem. Supports a huge range of runtimes (docker, podman, LXC/LXD, rkt, systemd-nspawn, containerd) because it operates on the OS level. 130 129 130 + ## TODO: 131 + 132 + - Make exec accept (partial) container IDs (only names are supported at the moment) 133 + - Terminal resizing ([example](https://github.com/docker/cli/blob/110c4d92b883357c9fb3edc344c4fbec5f77896f/cli/command/container/tty.go#L71)) 134 + - More `exec` flags (like in `docker run`): `--privileged`, `--volume`, `--env`, etc. 135 + - Helper command(s) suggesting nix(ery) packages 136 + - E2E Tests 137 + - Cross-platform builds + goreleaser 138 + - Non-docker runtimes (containerd, runc, k8s) 139 + 140 + ## Contributions 141 + 142 + It's a pre-alpha with no sound design yet, so I may not be accepting all PRs. Sorry about that :) 143 +