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  ```