]> git.ipfire.org Git - thirdparty/systemd.git/blame - docs/PORTABLE_SERVICES.md
man: add self-contained example of notify protocol
[thirdparty/systemd.git] / docs / PORTABLE_SERVICES.md
CommitLineData
c3e270f4
FB
1---
2title: Portable Services Introduction
4cdca0af 3category: Concepts
b41a3f66 4layout: default
0aff7b75 5SPDX-License-Identifier: LGPL-2.1-or-later
c3e270f4
FB
6---
7
f04aac3d 8# Portable Services
44d565ed 9
66e093de
LB
10systemd (since version 239) supports a concept of "Portable Services".
11"Portable Services" are a delivery method for system services that uses
12two specific features of container management:
44d565ed 13
66e093de
LB
141. Applications are bundled. I.e. multiple services, their binaries and all
15 their dependencies are packaged in an image, and are run directly from it.
44d565ed
LP
16
172. Stricter default security policies, i.e. sand-boxing of applications.
18
66e093de
LB
19The primary tool for interacting with Portable Services is `portablectl`,
20and they are managed by the `systemd-portabled` service.
44d565ed
LP
21
22Portable services don't bring anything inherently new to the table. All they do
8c7e2b48 23is put together known concepts to cover a specific set of use-cases in a
ba669952 24slightly nicer way.
44d565ed 25
991b4350 26## So, what *is* a "Portable Service"?
44d565ed 27
8c7e2b48
ZJS
28A portable service is ultimately just an OS tree, either inside of a directory,
29or inside a raw disk image containing a Linux file system. This tree is called
30the "image". It can be "attached" or "detached" from the system. When
31"attached", specific systemd units from the image are made available on the
32host system, then behaving pretty much exactly like locally installed system
33services. When "detached", these units are removed again from the host, leaving
34no artifacts around (except maybe messages they might have logged).
44d565ed
LP
35
36The OS tree/image can be created with any tool of your choice. For example, you
37can use `dnf --installroot=` if you like, or `debootstrap`, the image format is
38entirely generic, and doesn't have to carry any specific metadata beyond what
39distribution images carry anyway. Or to say this differently: the image format
40doesn't define any new metadata as unit files and OS tree directories or disk
41images are already sufficient, and pretty universally available these days. One
42particularly nice tool for creating suitable images is
43[mkosi](https://github.com/systemd/mkosi), but many other existing tools will
44do too.
45
8c7e2b48
ZJS
46Portable services may also be constructed from layers, similarly to container
47environments. See [Extension Images](#extension-images) below.
48
44d565ed
LP
49If you so will, "Portable Services" are a nicer way to manage chroot()
50environments, with better security, tooling and behavior.
51
991b4350 52## Where's the difference to a "Container"?
44d565ed
LP
53
54"Container" is a very vague term, after all it is used for
55systemd-nspawn/LXC-type OS containers, for Docker/rkt-like micro service
56containers, and even certain 'lightweight' VM runtimes.
57
8c7e2b48
ZJS
58"Portable services" do not provide a fully isolated environment to the payload,
59like containers mostly intend to. Instead, they are more like regular system
60services, can be controlled with the same tools, are exposed the same way in
61all infrastructure, and so on. The main difference is that they use a different
62root directory than the rest of the system. Hence, the intent is not to run
63code in a different, isolated environment from the host — like most containers
64would — but to run it in the same environment, but with stricter access
65controls on what the service can see and do.
66
67One point of differentiation: since programs running as "portable services" are
68pretty much regular system services, they won't run as PID 1 (like they would
69under Docker), but as normal processes. A corollary of that is that they aren't
70supposed to manage anything in their own environment (such as the network) as
71the execution environment is mostly shared with the rest of the system.
44d565ed 72
da95494c
CW
73The primary focus of "portable services" is to extend the host system
74with encapsulated extensions that provide almost full integration with the rest
8c7e2b48
ZJS
75of the system, though possibly restricted by security knobs. This focus
76includes system extensions otherwise sometimes called "super-privileged
44d565ed
LP
77containers".
78
79Note that portable services are only available for system services, not for
00473ac8
PL
80user services (i.e. the functionality cannot be used for the stuff
81bubblewrap/flatpak is focusing on).
44d565ed 82
991b4350 83## Mode of Operation
44d565ed 84
00473ac8 85If you have a portable service image, maybe in a raw disk image called
44d565ed
LP
86`foobar_0.7.23.raw`, then attaching the services to the host is as easy as:
87
88```
a00ff671 89# portablectl attach foobar_0.7.23.raw
44d565ed
LP
90```
91
92This command does the following:
93
8c7e2b48
ZJS
941. It dissects the image, checks and validates the `os-release` file of the
95 image, and looks for all included unit files.
44d565ed
LP
96
972. It copies out all unit files with a suffix of `.service`, `.socket`,
d8b67e05 98 `.target`, `.timer` and `.path`, whose name begins with the image's name
8c7e2b48
ZJS
99 (with `.raw` removed), truncated at the first underscore if there is one.
100 This prefix name generated from the image name must be followed by a ".",
101 "-" or "@" character in the unit name. Or in other words, given the image
102 name of `foobar_0.7.23.raw` all unit files matching
44d565ed
LP
103 `foobar-*.{service|socket|target|timer|path}`,
104 `foobar@.{service|socket|target|timer|path}` as well as
105 `foobar.*.{service|socket|target|timer|path}` and
106 `foobar.{service|socket|target|timer|path}` are copied out. These unit files
83f72cd6
LP
107 are placed in `/etc/systemd/system.attached/` (which is part of the normal
108 unit file search path of PID 1, and thus loaded exactly like regular unit
109 files). Within the images the unit files are looked for at the usual
110 locations, i.e. in `/usr/lib/systemd/system/` and `/etc/systemd/system/` and
111 so on, relative to the image's root.
44d565ed
LP
112
1133. For each such unit file a drop-in file is created. Let's say
114 `foobar-waldo.service` was one of the unit files copied to
83f72cd6
LP
115 `/etc/systemd/system.attached/`, then a drop-in file
116 `/etc/systemd/system.attached/foobar-waldo.service.d/20-portable.conf` is
117 created, containing a few lines of additional configuration:
44d565ed
LP
118
119 ```
120 [Service]
121 RootImage=/path/to/foobar.raw
122 Environment=PORTABLE=foobar
123 LogExtraFields=PORTABLE=foobar
124 ```
125
1264. For each such unit a "profile" drop-in is linked in. This "profile" drop-in
127 generally contains security options that lock down the service. By default
8c7e2b48
ZJS
128 the `default` profile is used, which provides a medium level of security.
129 There's also `trusted`, which runs the service with no restrictions, i.e. in
130 the host file system root and with full privileges. The `strict` profile
131 comes with the toughest security restrictions. Finally, `nonetwork` is like
132 `default` but without network access. Users may define their own profiles
133 too (or modify the existing ones).
44d565ed
LP
134
135And that's already it.
136
00473ac8 137Note that the images need to stay around (and in the same location) as long as the
44d565ed 138portable service is attached. If an image is moved, the `RootImage=` line
8c7e2b48
ZJS
139written to the unit drop-in would point to an non-existent path, and break
140access to the image.
44d565ed
LP
141
142The `portablectl detach` command executes the reverse operation: it looks for
8c7e2b48 143the drop-ins and the unit files associated with the image, and removes them.
44d565ed 144
00473ac8 145Note that `portablectl attach` won't enable or start any of the units it copies
5d55791e
LB
146out by default, but `--enable` and `--now` parameter are available as shortcuts.
147The same is true for the opposite `detach` operation.
148
8c7e2b48
ZJS
149The `portablectl reattach` command combines a `detach` with an `attach`. It is
150useful in case an image gets upgraded, as it allows performing a `restart`
151operation on the units instead of `stop` plus `start`, thus providing lower
152downtime and avoiding losing runtime state associated with the unit such as the
153file descriptor store.
44d565ed 154
991b4350 155## Requirements on Images
44d565ed
LP
156
157Note that portable services don't introduce any new image format, but most OS
158images should just work the way they are. Specifically, the following
159requirements are made for an image that can be attached/detached with
160`portablectl`.
161
957848db 1621. It must contain an executable that shall be invoked, along with all its
8c7e2b48
ZJS
163 dependencies. Any binary code needs to be compiled for an architecture
164 compatible with the host.
44d565ed
LP
165
1662. The image must either be a plain sub-directory (or btrfs subvolume)
167 containing the binaries and its dependencies in a classic Linux OS tree, or
168 must be a raw disk image either containing only one, naked file system, or
169 an image with a partition table understood by the Linux kernel with only a
170 single partition defined, or alternatively, a GPT partition table with a set
5c90c67a 171 of properly marked partitions following the
db811444 172 [Discoverable Partitions Specification](https://uapi-group.org/specifications/specs/discoverable_partitions_specification).
44d565ed
LP
173
1743. The image must at least contain one matching unit file, with the right name
175 prefix and suffix (see above). The unit file is searched in the usual paths,
176 i.e. primarily /etc/systemd/system/ and /usr/lib/systemd/system/ within the
177 image. (The implementation will check a couple of other paths too, but it's
178 recommended to use these two paths.)
179
6f61b14d
ДГ
1804. The image must contain an os-release file, either in `/etc/os-release` or
181 `/usr/lib/os-release`. The file should follow the standard format.
182
1835. The image must contain the files `/etc/resolv.conf` and `/etc/machine-id`
184 (empty files are ok), they will be bind mounted from the host at runtime.
44d565ed 185
957848db
LP
1866. The image must contain directories `/proc/`, `/sys/`, `/dev/`, `/run/`,
187 `/tmp/`, `/var/tmp/` that can be mounted over with the corresponding version
188 from the host.
189
1907. The OS might require other files or directories to be in place. For example,
191 if the image is built based on glibc, the dynamic loader needs to be
192 available in `/lib/ld-linux.so.2` or `/lib64/ld-linux-x86-64.so.2` (or
193 similar, depending on architecture), and if the distribution implements a
194 merged `/usr/` tree, this means `/lib` and/or `/lib64` need to be symlinks
195 to their respective counterparts below `/usr/`. For details see your
196 distribution's documentation.
197
198Note that images created by tools such as `debootstrap`, `dnf --installroot=`
8c7e2b48
ZJS
199or `mkosi` generally satisfy all of the above. If you wonder what the most
200minimal image would be that complies with the requirements above, it could
201consist of this:
44d565ed
LP
202
203```
570ee29c
LP
204/usr/bin/minimald # a statically compiled binary
205/usr/lib/systemd/system/minimal-test.service # the unit file for the service, with ExecStart=/usr/bin/minimald
206/usr/lib/os-release # an os-release file explaining what this is
207/etc/resolv.conf # empty file to mount over with host's version
208/etc/machine-id # ditto
209/proc/ # empty directory to use as mount point for host's API fs
210/sys/ # ditto
211/dev/ # ditto
212/run/ # ditto
213/tmp/ # ditto
214/var/tmp/ # ditto
44d565ed
LP
215```
216
217And that's it.
218
219Note that qualifying images do not have to contain an init system of their
220own. If they do, it's fine, it will be ignored by the portable service logic,
221but they generally don't have to, and it might make sense to avoid any, to keep
222images minimal.
223
957848db 224If the image is writable, and some of the files or directories that are
8c7e2b48 225overmounted from the host do not exist yet they will be automatically created.
09e917ea
LP
226On read-only, immutable images (e.g. `erofs` or `squashfs` images) all files
227and directories to over-mount must exist already.
957848db 228
44d565ed 229Note that as no new image format or metadata is defined, it's very
00473ac8 230straightforward to define images than can be made use of in a number of
44d565ed
LP
231different ways. For example, by using `mkosi -b` you can trivially build a
232single, unified image that:
233
2341. Can be attached as portable service, to run any container services natively
235 on the host.
236
2372. Can be run as OS container, using `systemd-nspawn`, by booting the image
238 with `systemd-nspawn -i -b`.
239
2403. Can be booted directly as VM image, using a generic VM executor such as
241 `virtualbox`/`qemu`/`kvm`
242
2434. Can be booted directly on bare-metal systems.
244
245Of course, to facilitate 2, 3 and 4 you need to include an init system in the
8c7e2b48
ZJS
246image. To facilitate 3 and 4 you also need to include a boot loader in the
247image. As mentioned, `mkosi -b` takes care of all of that for you, but any
248other image generator should work too.
44d565ed 249
8a129c80
LP
250The
251[os-release(5)](https://www.freedesktop.org/software/systemd/man/os-release.html)
252file may optionally be extended with a `PORTABLE_PREFIXES=` field listing all
253supported portable service prefixes for the image (see above). This is useful
254for informational purposes (as it allows recognizing portable service images
255from their contents as such), but is also useful to protect the image from
256being used under a wrong name and prefix. This is particularly relevant if the
257images are cryptographically authenticated (via Verity or a similar mechanism)
258as this way the (not necessarily authenticated) image file name can be
259validated against the (authenticated) image contents. If the field is not
260specified the image will work fine, but is not necessarily recognizable as
261portable service image, and any set of units included in the image may be
262attached, there are no restrictions enforced.
263
5d55791e
LB
264## Extension Images
265
266Portable services can be delivered as one or multiple images that extend the base
267image, and are combined with OverlayFS at runtime, when they are attached. This
268enables a workflow that splits the base 'runtime' from the daemon, so that multiple
269portable services can share the same 'runtime' image (libraries, tools) without
270having to include everything each time, with the layering happening only at runtime.
271The `--extension` parameter of `portablectl` can be used to specify as many upper
272layers as desired. On top of the requirements listed in the previous section, the
8c7e2b48 273following must be also be observed:
5d55791e 274
8c7e2b48
ZJS
2751. The base/OS image must contain an `os-release file`, either in `/etc/os-release`
276 or `/usr/lib/os-release`, in the standard format.
5d55791e 277
0923b425 2782. The upper extension images must contain an extension-release file in
5d55791e 279 `/usr/lib/extension-release.d/`, with an `ID=` and `SYSEXT_LEVEL=`/`VERSION_ID=`
db776f69
MG
280 matching the base image for sysexts, or `/etc/extension-release.d/`, with an
281 `ID=` and `CONFEXT_LEVEL=`/`VERSION_ID=` matching the base image for confexts.
5d55791e
LB
282
2833. The base/OS image does not need to have any unit files.
284
db776f69
MG
2854. The upper sysext images must contain at least one matching unit file each,
286 with the right name prefix and suffix (see above). Confext images do not have
287 to contain units.
5d55791e 288
0923b425
ZJS
2895. As with the base/OS image, each upper extension image must be a plain
290 sub-directory, btrfs subvolume, or a raw disk image.
2ef20244 291
5d55791e 292```
a00ff671 293# portablectl attach --extension foobar_0.7.23.raw debian-runtime_11.1.raw foobar
2ef20244 294# portablectl attach --extension barbaz_7.0.23/ debian-runtime_11.1.raw barbaz
5d55791e
LB
295```
296
991b4350 297## Execution Environment
44d565ed
LP
298
299Note that the code in portable service images is run exactly like regular
8c7e2b48 300services. Hence there's no new execution environment to consider. And, unlike
44d565ed
LP
301Docker would do it, as these are regular system services they aren't run as PID
3021 either, but with regular PID values.
303
991b4350 304## Access to host resources
44d565ed
LP
305
306If services shipped with this mechanism shall be able to access host resources
307(such as files or AF_UNIX sockets for IPC), use the normal `BindPaths=` and
e347d53a 308`BindReadOnlyPaths=` settings in unit files to mount them in. In fact, the
44d565ed
LP
309`default` profile mentioned above makes use of this to ensure
310`/etc/resolv.conf`, the D-Bus system bus socket or write access to the logging
311subsystem are available to the service.
312
991b4350 313## Instantiation
44d565ed
LP
314
315Sometimes it makes sense to instantiate the same set of services multiple
316times. The portable service concept does not introduce a new logic for this. It
8c7e2b48 317is recommended to use the regular systemd unit templating for this, i.e. to
44d565ed
LP
318include template units such as `foobar@.service`, so that instantiation is as
319simple as:
320
321```
a00ff671 322# portablectl attach foobar_0.7.23.raw
44d565ed
LP
323# systemctl enable --now foobar@instancea.service
324# systemctl enable --now foobar@instanceb.service
325
326```
327
328The benefit of this approach is that templating works exactly the same for
329units shipped with the OS itself as for attached portable services.
330
991b4350 331## Immutable images with local data
44d565ed
LP
332
333It's a good idea to keep portable service images read-only during normal
e347d53a 334operation. In fact, all but the `trusted` profile will default to this kind of
44d565ed
LP
335behaviour, by setting the `ProtectSystem=strict` option. In this case writable
336service data may be placed on the host file system. Use `StateDirectory=` in
337the unit files to enable such behaviour and add a local data directory to the
338services copied onto the host.
6d6104e0 339
8c8331fc
LB
340## Logging
341
342Several fields are autotmatically added to log messages generated by a portable
343service (or about a portable service, e.g.: start/stop logs from systemd).
344The `PORTABLE=` field will refer to the name of the portable image where the unit
345was loaded from. In case extensions are used, additionally there will be a
346`PORTABLE_ROOT=` field, referring to the name of image used as the base layer
347(i.e.: `RootImage=` or `RootDirectory=`), and one `PORTABLE_EXTENSION=` field per
348each extension image used.
349
e8114a4f
LB
350The `os-release` file from the portable image will be parsed and added as structured
351metadata to the journal log entries. The parsed fields will be the first ID field which
352is set from the set of `IMAGE_ID` and `ID` in this order of preference, and the first
353version field which is set from a set of `IMAGE_VERSION`, `VERSION_ID`, and `BUILD_ID`
354in this order of preference. The ID and version, if any, are concatenated with an
355underscore (`_`) as separator. If only either one is found, it will be used by itself.
356The field will be named `PORTABLE_NAME_AND_VERSION=`.
357
358In case extensions are used, the same fields in the same order are, but prefixed by
db776f69
MG
359`SYSEXT_`/`CONFEXT_`, are parsed from each `extension-release` file, and are appended
360to the journal as log entries, using `PORTABLE_EXTENSION_NAME_AND_VERSION=` as the
361field name. The base layer's field will be named `PORTABLE_ROOT_NAME_AND_VERSION=`
362instead of `PORTABLE_NAME_AND_VERSION=` in this case.
e8114a4f 363
8c8331fc 364For example, a portable service `app0` using two extensions `app0.raw` and
e8114a4f
LB
365`app1.raw` (with `SYSEXT_ID=app`, and `SYSEXT_VERSION_ID=` `0` and `1` in their
366respective extension-releases), and a base layer `base.raw` (with `VERSION_ID=10` and
367`ID=debian` in `os-release`), will create log entries with the following fields:
8c8331fc
LB
368
369```
370PORTABLE=app0.raw
371PORTABLE_ROOT=base.raw
e8114a4f 372PORTABLE_ROOT_NAME_AND_VERSION=debian_10
8c8331fc 373PORTABLE_EXTENSION=app0.raw
e8114a4f 374PORTABLE_EXTENSION_NAME_AND_VERSION=app_0
8c8331fc 375PORTABLE_EXTENSION=app1.raw
e8114a4f 376PORTABLE_EXTENSION_NAME_AND_VERSION=app_1
8c8331fc
LB
377```
378
6d6104e0
ZJS
379## Links
380
a43d2229
LP
381[`portablectl(1)`](https://www.freedesktop.org/software/systemd/man/portablectl.html)<br>
382[`systemd-portabled.service(8)`](https://www.freedesktop.org/software/systemd/man/systemd-portabled.service.html)<br>
6d6104e0
ZJS
383[Walkthrough for Portable Services](https://0pointer.net/blog/walkthrough-for-portable-services.html)<br>
384[Repo with examples](https://github.com/systemd/portable-walkthrough)