github.com/coreos/rocket@v1.30.1-0.20200224141603-171c416fac02/Documentation/devel/log-attach-design.md (about)

     1  # Logging and attaching design
     2  
     3  ## Overview
     4  
     5  rkt can run multiple applications in a pod, under a supervising process and alongside with a sidecar service which takes care of multiplexing its I/O toward the outside world.
     6  
     7  Historically this has been done via systemd-journald only, meaning that all logging was handled via journald and interactive applications had to re-use a parent TTY.
     8  
     9  Starting from systemd v232, it is possible to connect a service streams to arbitrary socket units and let custom sidecar multiplex all the I/O.
    10  
    11  This document describes the architectural design for the current logging and attaching subsystem, which allows custom logging and attaching logic.
    12  
    13  ## Runtime modes
    14  
    15  In order to be able to attach or apply custom logging logic to applications, an appropriate runtime mode must be specified when adding/preparing an application inside a pod.
    16  
    17  This is done via stage0 CLI arguments (`--stdin`, `--stdout`, and `--stder`) which translate into per-application stage2 annotations.
    18  
    19  ### Interactive mode
    20  
    21  This mode results in the application having the corresponding stream attached to the parent terminal.
    22  
    23  For historical reasons and backward compatibility, this is a special mode activated via `--interactive` and only supports single-app pods.
    24  
    25  Interactive mode does not support attaching and ties the runtime to the lifetime of the parent terminal.
    26  
    27  Internally, this translates to an annotation at the app level:
    28  
    29  ```
    30  {
    31      "name": "coreos.com/rkt/stage2/stdin",
    32      "value": "interactive"
    33  },
    34  {
    35      "name": "coreos.com/rkt/stage2/stdout",
    36      "value": "interactive"
    37  },
    38  {
    39      "name": "coreos.com/rkt/stage2/stderr",
    40      "value": "interactive"
    41  }
    42  ```
    43  
    44  In this case, the corresponding service unit file gains the following properties:
    45  
    46  ```
    47  [Service]
    48  StandardInput=tty
    49  StandardOutput=tty
    50  StandardError=tty
    51  ...
    52  ```
    53  
    54  No further sidecar dependencies are introduced in this case.
    55  
    56  ### TTY mode
    57  
    58  This mode results in the application having the corresponding stream attached to a dedicated pseudo-terminal.
    59  
    60  This is different from the "interactive" mode because:
    61   * it allocates a new pseudo-terminal accounted towards pod resources
    62   * it supports external attaching/detaching
    63   * it supports multiple applications running inside a single pod
    64   * it does not tie the pod lifetime to the parent terminal one
    65  
    66  Internally, this translates to an annotation at the app level:
    67  
    68  ```
    69  {
    70      "name": "coreos.com/rkt/stage2/stdin",
    71      "value": "tty"
    72  },
    73  {
    74      "name": "coreos.com/rkt/stage2/stdout",
    75      "value": "tty"
    76  },
    77  {
    78      "name": "coreos.com/rkt/stage2/stderr",
    79      "value": "tty"
    80  }
    81  ```
    82  
    83  In this case, the corresponding service unit file gains the following properties:
    84  
    85  ```
    86  [Service]
    87  TTYPath=/rkt/iomux/<appname>/stage2-pts
    88  StandardInput=tty
    89  StandardOutput=tty
    90  StandardError=tty
    91  ...
    92  ```
    93  
    94  A sidecar dependency to `ttymux@.service` is introduced in this case. Application has a `Wants=` and `After=` relationship to it.
    95  
    96  ### Streaming mode
    97  
    98  This mode results in the application having each of the corresponding streams separately handled by a muxing service.
    99  
   100  This is different from the "interactive" and "tty" modes because:
   101   * it does not allocate any terminal for the application
   102   * single streams can be separately handled
   103   * it supports multiple applications running inside a single pod
   104  
   105  
   106  Internally, this translates to an annotation at the app level:
   107  
   108  ```
   109  {
   110      "name": "coreos.com/rkt/stage2/stdin",
   111      "value": "stream"
   112  },
   113  {
   114      "name": "coreos.com/rkt/stage2/stdout",
   115      "value": "stream"
   116  },
   117  {
   118      "name": "coreos.com/rkt/stage2/stderr",
   119      "value": "stream"
   120  }
   121  ```
   122  
   123  In this case, the corresponding service unit file gains the following properties:
   124  
   125  ```
   126  [Service]
   127  StandardInput=fd
   128  Sockets=<appname>-stdin.socket
   129  StandardOutput=fd
   130  Sockets=<appname>-stdout.socket
   131  StandardError=fd
   132  Sockets=<appname>-stderr.socket
   133  ...
   134  ```
   135  
   136  A sidecar dependency to `iomux@.service` is introduced in this case. Application has a `Wants=` and `Before=` relationship to it.
   137  
   138  Additional per-stream socket units are generated, as follows:
   139  
   140  ```
   141  [Unit]
   142  Description=<stream> socket for <appname>
   143  DefaultDependencies=no
   144  StopWhenUnneeded=yes
   145  RefuseManualStart=yes
   146  RefuseManualStop=yes
   147  BindsTo=<appname>.service
   148  
   149  [Socket]
   150  RemoveOnStop=yes
   151  Service=<appname>.service
   152  FileDescriptorName=<stream>
   153  ListenFIFO=/rkt/iottymux/<appname>/stage2-<stream>
   154  ```
   155  
   156  ### Logging mode
   157  
   158  This mode results in the application having the corresponding stream attached to systemd-journald.
   159  
   160  This is the default mode for stdout/stderr, for historical reasons and backward compatibility.
   161  
   162  Internally, this translates to an annotation at the app level:
   163  
   164  ```
   165  {
   166      "name": "coreos.com/rkt/stage2/stdout",
   167      "value": "log"
   168  },
   169  {
   170      "name": "coreos.com/rkt/stage2/stderr",
   171      "value": "log"
   172  }
   173  ```
   174  
   175  In this case, the corresponding service unit file gains the following properties:
   176  
   177  ```
   178  [Service]
   179  StandardOutput=journal
   180  StandardError=journal
   181  ...
   182  ```
   183  
   184  A sidecar dependency to `systemd-journald.service` is introduced in this case. Application has a `Wants=` and `After=` relationship to it.
   185  
   186  Logging is not a valid mode for stdin.
   187  
   188  ### Null mode
   189  
   190  This mode results in the application having the corresponding stream closed.
   191  
   192  This is the default mode for stdin, for historical reasons and backward compatibility.
   193  
   194  Internally, this translates to an annotation at the app level:
   195  
   196  ```
   197  {
   198      "name": "coreos.com/rkt/stage2/stdin",
   199      "value": "null"
   200  },
   201  {
   202      "name": "coreos.com/rkt/stage2/stdout",
   203      "value": "null"
   204  },
   205  {
   206      "name": "coreos.com/rkt/stage2/stderr",
   207      "value": "null"
   208  }
   209  ```
   210  
   211  In this case, the corresponding service unit file gains the following properties:
   212  
   213  ```
   214  [Service]
   215  StandardInput=null
   216  StandardOutput=null
   217  StandardError=null
   218  [...]
   219  ```
   220  
   221  No further sidecar dependencies are introduced in this case.
   222  
   223  ## Annotations
   224  
   225  The following per-app annotations are defined for internal use, with the corresponding set of allowed values:
   226  
   227   * `coreos.com/rkt/stage2/stdin`
   228     - `interactive`
   229     - `null`
   230     - `stream`
   231     - `tty`
   232   * `coreos.com/rkt/stage2/stdout`
   233     - `interactive`
   234     - `log`
   235     - `null`
   236     - `stream`
   237     - `tty`
   238   * `coreos.com/rkt/stage2/stderr`
   239     - `interactive`
   240     - `log`
   241     - `null`
   242     - `stream`
   243     - `tty`
   244  
   245  
   246  ## Stage1 internals
   247  
   248  All the logging and attaching logic is handled by the stage1 `iottymux` binary.
   249  
   250  Each main application may additionally have a dedicated sidecar for I/O multiplexing, which proxies I/O to external clients over sockets.
   251  
   252  Sidecar state is persisted at `/rkt/iottymux/<appname>` while the main application is running.
   253  
   254  
   255  ## Attaching
   256  
   257  `rkt attach` can auto-discover endpoints, by reading the content of status file located at `/rkt/iottymux/<appname>/endpoints`.
   258  
   259  This file provides a versioned JSON document, whose content varies depending on the I/O for the specific application.
   260  
   261  For example, an application with all streams available for attaching will have a status file similar to the following:
   262  
   263  ```
   264  {
   265      "version": 1,
   266      "targets": [
   267          {
   268              "name": "stdin",
   269              "domain": "unix",
   270              "address": "/rkt/iottymux/alpine-sh/sock-stdin"
   271          },
   272          {
   273              "name": "stdout",
   274              "domain": "unix",
   275              "address": "/rkt/iottymux/alpine-sh/sock-stdout"
   276          },
   277          {
   278              "name": "stderr",
   279              "domain": "unix",
   280              "address": "/rkt/iottymux/alpine-sh/sock-stderr"
   281          }
   282      ]
   283  }
   284  ```
   285  
   286  ### Endpoint listing
   287  
   288  
   289  Its `--mode=list` option just read the file and print it back to the user.
   290  
   291  ### Automatic attaching
   292  
   293  `rkt attach --mode=auto` performs the auto-discovery mechanism described above, and the proceed to attach stdin/stdour/stderr of the current process (itself) to all available corresponding endpoints.
   294  
   295  This the default attaching mode.
   296  
   297  ### Custom attaching
   298  
   299  `rkt attach --mode=<stream>` performs the auto-discovery mechanism described above, and the proceed to the corresponding available endpoints.
   300  
   301  ## Logging
   302  
   303  ### Journald
   304  
   305  This is the default output multiplexer for stdout/stderr in logging mode, for historical reasons and backward compatibility.
   306  
   307  Restrictions:
   308   * requires journalctl (or similar libsystemd-based helper) to decode output entries
   309   * requires a libsystemd on the host compiled with LZ4 support
   310   * systemd-journald does not support distinguishing between entries from stdout and stderr
   311  
   312  ### Experimental logging modes
   313  
   314  TODO(lucab): k8s logmode
   315  
   316  ## Sidecars
   317  
   318  ### systemd-journald
   319  
   320  
   321  This is the standard systemd-journald service. It is the default output handler for the "logging" mode.
   322  
   323  ### iottymux
   324  
   325  iottymux is a multi-purpose stage1 binary. It currently serves the following purposes:
   326   * Multiplex I/O over TTY (in TTY mode)
   327   * Multiplex I/O from streams (in streaming mode)
   328   * Attach to existing attachable applications (in TTY or streaming mode)
   329  
   330  #### iomux
   331  
   332  This component takes care of multiplexing dedicated streams and receiving clients for attaching.
   333  
   334  It is started as an instance of the templated `iomux@.service` service by a `Before=` dependency from the application.
   335  
   336  Internally, it attaches to available FIFOs and proxies them to separate sockets for external clients.
   337  
   338  It is implemented as a sub-action of the main `iottymux` binary and completely run in stage1 context.
   339  
   340  #### ttymux
   341  
   342  This component takes care of multiplexing TTY and receiving clients for attaching.
   343  
   344  It is started as an instance of the templated `ttymux@.service` service by a `After=` dependency from the application.
   345  
   346  Internally, it creates a pesudo-tty pair (whose slave is used by the main application) and proxies the master to a socket for external clients.
   347  
   348  It is implemented as a sub-action of the main `iottymux` binary and completely run in stage1 context.
   349  
   350  #### iottymux-attach
   351  
   352  This component takes care of discovering endpoints and attaching to them, both for TTY and streaming modes.
   353  
   354  It is invoked by the "stage1" attach entrypoint and completely run in stage1 context. It is implemented as a sub-action of the main `iottymux` binary.