github.com/coreos/rocket@v1.30.1-0.20200224141603-171c416fac02/Documentation/devel/debugging.md (about) 1 # Debugging rkt 2 3 This guide gives an overview of the debugging techniques that can be used to pinpoint problems with rkt itself or with particular images. 4 5 ## rkt enter 6 7 [enter](../subcommands/enter.md) is the most straight-forward technique. 8 It allows you to enter the namespaces of an app within a pod so you can explore its filesystem and see what's running. 9 10 By default it tries to run `/bin/bash` if it's present in the app's filesystem but you can specify a command to run if the app doesn't provide a bash binary. 11 12 ```bash 13 $ rkt list 14 UUID APP IMAGE NAME STATE CREATED STARTED NETWORKS 15 54ca5d22 busybox kinvolk.io/aci/busybox:1.24 running 1 hour ago 1 hour ago default:ip4=172.16.28.114 16 $ sudo rkt enter 54ca5d22 sh 17 / # ls 18 bin dev etc home proc root run sys tmp usr var 19 / # ps 20 PID USER TIME COMMAND 21 1 root 0:00 /usr/lib/systemd/systemd --default-standard-output=tty --log-target=null --show-status=0 22 3 root 0:00 /usr/lib/systemd/systemd-journald 23 6 root 0:00 /bin/sh 24 40 root 0:00 sh 25 44 root 0:00 ps 26 ``` 27 28 This works well for images that have a shell baked in but a common practice is creating minimal images with only a statically compiled binary or a binary plus its needed libraries, which limits the usefulness of `rkt enter`. 29 We'll later see how to overcome this limitation. 30 31 ## Entering stage1 32 33 As explained in [rkt architecture](architecture.md), execution with rkt is divided into several distinct stages. 34 While with `rkt enter` you enter stage2, it is sometimes useful to see what happens in stage1. 35 For example, you might want to check what options are passed to the unit file of an app, or interact with stage1 systemd. 36 37 rkt doesn't include a subcommand you can use to enter stage1, but you can use [`nsenter`](http://man7.org/linux/man-pages/man1/nsenter.1.html) for that purpose. 38 Note that this only applies for container stage1 images: kvm pods run in an isolated VM and `nsenter` can't enter its stage1, and fly only allows one app per pod and it doesn't have long-running processes on stage1 so there's nothing to enter. 39 40 Let's enter a pod's stage1. 41 We'll need to find stage1 systemd's PID, which is the child of the PID shown in `rkt status`. 42 Then we can just call nsenter with it: 43 44 ```bash 45 $ rkt status 86e6df38 46 state=running 47 created=2017-12-19 14:49:00.376 +0100 CET 48 started=2017-12-19 14:49:00.466 +0100 CET 49 networks=default:ip4=172.16.28.27 50 pid=8469 51 exited=false 52 $ ps auxf | grep -A1 [8]469 53 root 8469 0.1 0.0 54204 5076 pts/1 S+ 14:48 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=86e6df38-0762-4261-af21-d2b265555179 --machine=rkt-86e6df38-0762-4261-af21-d2b265555179 --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 54 root 8505 0.0 0.0 62276 7300 ? Ss 14:48 0:00 \_ /usr/lib/systemd/systemd --default-standard-output=tty --log-target=null --show-status=0 55 $ sudo nsenter -m -u -i -p -t 8505 56 -bash-4.3# 57 ``` 58 59 However, the stage1 environment doesn't include basic binaries necessary for debugging: 60 61 ```bash 62 -bash-4.3# ls 63 -bash: ls: command not found 64 -bash-4.3# cat 65 -bash: cat: command not found 66 ``` 67 68 If you only need to inspect the stage1 filesystem, you can check `/proc/$PID/root/` from the host: 69 70 ```bash 71 # ls /proc/27107/root/ 72 app_add app_start attach dev enter etc gc iottymux lib64 prepare-app reaper.sh root stop systemd-version usr 73 app_rm app_stop bin diagnostic enterexec flavor init lib opt proc rkt run sys tmp var 74 ``` 75 76 Luckily, rkt includes a helper script that injects a static busybox binary and makes entering stage1 easier. 77 It can be found in `scripts/debug/stage1_install_busybox.sh`. 78 It takes a pod UUID as a parameter and it outputs the right nsenter command: 79 80 ```bash 81 $ rkt list --full 82 UUID APP IMAGE NAME IMAGE ID STATE CREATED STARTED NETWORKS 83 86e6df38-0762-4261-af21-d2b265555179 busybox kinvolk.io/aci/busybox:1.24 sha512-140375b2a2bd running 2017-12-19 14:49:00.376 +0100 CET 2017-12-19 14:49:00.466 +0100 CET default:ip4=172.16.28.27 84 $ ./scripts/debug/stage1_install_busybox.sh 86e6df38-0762-4261-af21-d2b265555179 85 Busybox installed. Use the following command to enter pod's stage1: 86 sudo nsenter -m -u -i -p -t 8505 87 -bash-4.3# cat rkt/env/busybox 88 SHELL=/bin/sh 89 USER=root 90 LOGNAME=root 91 HOME=/root 92 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 93 AC_APP_NAME=busybox 94 ``` 95 96 By default, the script creates links for common busybox programs, but if you need to run more commands you can call busybox accordingly: 97 98 ```bash 99 -bash-4.3# busybox head -n2 /lib/systemd/system/busybox.service 100 [Unit] 101 After=systemd-journald.service 102 ``` 103 104 Run `busybox` without arguments to see a list of available commands. 105 106 If you need custom tools you can add them by copying them to `/proc/$PID/root/bin`. 107 It's easier if they're static binaries to avoid complications with dynamic libraries. 108 109 ## Debugging images 110 111 As mentioned, `rkt enter` has limitations when the image to debug doesn't ship with tools to debug it or even a shell. 112 One possible way to debug those images is to use the ACI dependencies mechanism to add a custom tools image to your container. 113 114 Let's use [actool](https://github.com/appc/spec/tree/v0.8.11/actool) to patch the manifest. 115 116 ```bash 117 $ rkt fetch debug-image.aci 118 sha512-847f2ca60e473121311fac62d014a4f1 119 $ actool cat-manifest --pretty-print image-to-patch.aci > manifest.json 120 ``` 121 122 We'll now add the dependency to the manifest, right before the "app" section: 123 124 ```json 125 ], 126 "dependencies": [ 127 { 128 "imageID": "sha512-847f2ca60e473121311fac62d014a4f1" 129 } 130 ], 131 "app": { 132 ``` 133 134 Then we'll patch the image and run it: 135 136 ```bash 137 $ actool patch-manifest --manifest manifest.json --replace image-to-patch.aci 138 $ sudo rkt --insecure-options=image run --interactive image-to-patch.aci 139 (...) 140 ``` 141 142 You'll have your favorite debugging tools available. 143 144 For examples of how to build images, check out [Build container examples](../build-container-examples). 145 Creating images with statically built binaries is preferred to avoid complications with shared libraries. 146 147 As an alternative to adding a dependency in the ACI, you can also add a volume after a container has been started using [`machinectl bind`](https://www.freedesktop.org/software/systemd/man/machinectl.html#bind%20NAME%20PATH%20%5BPATH%5D): 148 149 ```bash 150 $ sudo mkdir /proc/$PID/root/opt/stage2/$APP_NAME/rootfs/tools 151 $ machinectl 152 MACHINE CLASS SERVICE OS VERSION ADDRESSES 153 rkt-b7458bf5-8e19-40c1-a7dc-7c5aa25e4970 container rkt - - 172.16.28.27... 154 155 1 machines listed. 156 $ sudo machinectl bind $PWD/tools /opt/stage2/$APP_NAME/rootfs/tools 157 ``` 158 159 Where `$PID` is still the PID of systemd in the pod. 160 161 ## strace 162 163 [Strace](http://man7.org/linux/man-pages/man1/strace.1.html) is a very powerful tool to inspect what applications are doing. 164 For container stage1 images or fly, you can just attach strace to processes running inside pods like any other process on the host: 165 166 Let's trace the shell process running in our example busybox container. 167 We'll also follow forks to trace new processes created by the shell: 168 169 ```bash 170 $ ps auxf | grep -A3 [8]469 171 root 8469 0.1 0.0 54204 5076 pts/1 S+ 14:48 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=86e6df38-0762-4261-af21-d2b265555179 --machine=rkt-86e6df38-0762-4261-af21-d2b265555179 --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 172 root 8505 0.0 0.0 62276 7300 ? Ss 14:48 0:00 \_ /usr/lib/systemd/systemd --default-standard-output=tty --log-target=null --show-status=0 173 root 8507 0.0 0.0 66408 8740 ? Ss 14:48 0:00 \_ /usr/lib/systemd/systemd-journald 174 root 8510 0.0 0.0 1212 672 pts/3 Ss+ 14:48 0:00 \_ /bin/sh 175 $ sudo strace -f -p 8510 176 wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WSTOPPED, NULL) = 2646 177 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=2646, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- 178 ioctl(10, TIOCSPGRP, [6]) = 0 179 wait4(-1, 0x7ffc0226b918, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes) 180 wait4(-1, 0x7ffc0226b7b8, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes) 181 write(1, "This is the current date: ", 26) = 26 182 clone(strace: Process 12807 attached 183 (...) 184 ``` 185 186 To find out more about strace, check out Julia Evans' [strace zine](https://jvns.ca/zines/#strace-zine). 187 188 ## Debugging applications with gdb 189 190 Sometimes strace is not enough to figure out problems with your applications. 191 From version 7.10, it is possible to use [gdb](https://www.gnu.org/software/gdb/) to debug processes running in containers from the host. 192 Same as with strace, you need to find the PID of the process you want to debug and then just run: 193 194 ``` 195 $ sudo gdb -p $PID 196 ```