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.