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