]> git.ipfire.org Git - thirdparty/systemd.git/blame - docs/PORTABLE_SERVICES.md
test: udev storage tests
[thirdparty/systemd.git] / docs / PORTABLE_SERVICES.md
CommitLineData
c3e270f4
FB
1---
2title: Portable Services Introduction
4cdca0af 3category: Concepts
b41a3f66 4layout: default
c3e270f4
FB
5---
6
44d565ed
LP
7# Portable Services Introduction
8
66e093de
LB
9systemd (since version 239) supports a concept of "Portable Services".
10"Portable Services" are a delivery method for system services that uses
11two specific features of container management:
44d565ed 12
66e093de
LB
131. Applications are bundled. I.e. multiple services, their binaries and all
14 their dependencies are packaged in an image, and are run directly from it.
44d565ed
LP
15
162. Stricter default security policies, i.e. sand-boxing of applications.
17
66e093de
LB
18The primary tool for interacting with Portable Services is `portablectl`,
19and they are managed by the `systemd-portabled` service.
44d565ed
LP
20
21Portable services don't bring anything inherently new to the table. All they do
22is put together known concepts in a slightly nicer way to cover a specific set
23of use-cases in a nicer way.
24
991b4350 25## So, what *is* a "Portable Service"?
44d565ed
LP
26
27A portable service is ultimately just an OS tree, either inside of a directory
5d55791e
LB
28tree, or inside a raw disk image (or a set of images that get layered, see
29[Layered Images](#layered-images)) containing a Linux file system. This tree is called the
30"image". It can be "attached" or "detached" from the system. When "attached"
31specific systemd units from the image are made available on the host system,
32then behaving pretty much exactly like locally installed system services. When
33"detached" these units are removed again from the host, leaving no artifacts
34around (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
46If you so will, "Portable Services" are a nicer way to manage chroot()
47environments, with better security, tooling and behavior.
48
991b4350 49## Where's the difference to a "Container"?
44d565ed
LP
50
51"Container" is a very vague term, after all it is used for
52systemd-nspawn/LXC-type OS containers, for Docker/rkt-like micro service
53containers, and even certain 'lightweight' VM runtimes.
54
55The "portable service" concept ultimately will not provide a fully isolated
56environment to the payload, like containers mostly intend to. Instead they are
57from the beginning more alike regular system services, can be controlled with
58the same tools, are exposed the same way in all infrastructure and so on. Their
00473ac8 59main difference is that they use a different root directory than the rest of the
44d565ed 60system. Hence, the intention is not to run code in a different, isolated world
00473ac8 61from the host — like most containers would do it — but to run it in the same
44d565ed
LP
62world, but with stricter access controls on what the service can see and do.
63
64As one point of differentiation: as programs run as "portable services" are
65pretty much regular system services, they won't run as PID 1 (like Docker would
00473ac8 66do it), but as normal processes. A corollary of that is that they aren't supposed
44d565ed
LP
67to manage anything in their own environment (such as the network) as the
68execution environment is mostly shared with the rest of the system.
69
70The primary focus use-case of "portable services" is to extend the host system
71with encapsulated extensions, but provide almost full integration with the rest
72of the system, though possibly restricted by effective security knobs. This
73focus includes system extensions otherwise sometimes called "super-privileged
74containers".
75
76Note that portable services are only available for system services, not for
00473ac8
PL
77user services (i.e. the functionality cannot be used for the stuff
78bubblewrap/flatpak is focusing on).
44d565ed 79
991b4350 80## Mode of Operation
44d565ed 81
00473ac8 82If you have a portable service image, maybe in a raw disk image called
44d565ed
LP
83`foobar_0.7.23.raw`, then attaching the services to the host is as easy as:
84
85```
86# /usr/lib/systemd/portablectl attach foobar_0.7.23.raw
87```
88
89This command does the following:
90
6f61b14d
ДГ
911. It dissects the image, checks and validates the `/etc/os-release`
92 (or `/usr/lib/os-release`, see below) data of the image, and looks for
93 all included unit files.
44d565ed
LP
94
952. It copies out all unit files with a suffix of `.service`, `.socket`,
96 `.target`, `.timer` and `.path`. whose name begins with the image's name
97 (with the .raw removed), truncated at the first underscore (if there is
98 one). This prefix name generated from the image name must be followed by a
99 ".", "-" or "@" character in the unit name. Or in other words, given the
100 image name of `foobar_0.7.23.raw` all unit files matching
101 `foobar-*.{service|socket|target|timer|path}`,
102 `foobar@.{service|socket|target|timer|path}` as well as
103 `foobar.*.{service|socket|target|timer|path}` and
104 `foobar.{service|socket|target|timer|path}` are copied out. These unit files
83f72cd6
LP
105 are placed in `/etc/systemd/system.attached/` (which is part of the normal
106 unit file search path of PID 1, and thus loaded exactly like regular unit
107 files). Within the images the unit files are looked for at the usual
108 locations, i.e. in `/usr/lib/systemd/system/` and `/etc/systemd/system/` and
109 so on, relative to the image's root.
44d565ed
LP
110
1113. For each such unit file a drop-in file is created. Let's say
112 `foobar-waldo.service` was one of the unit files copied to
83f72cd6
LP
113 `/etc/systemd/system.attached/`, then a drop-in file
114 `/etc/systemd/system.attached/foobar-waldo.service.d/20-portable.conf` is
115 created, containing a few lines of additional configuration:
44d565ed
LP
116
117 ```
118 [Service]
119 RootImage=/path/to/foobar.raw
120 Environment=PORTABLE=foobar
121 LogExtraFields=PORTABLE=foobar
122 ```
123
1244. For each such unit a "profile" drop-in is linked in. This "profile" drop-in
125 generally contains security options that lock down the service. By default
126 the `default` profile is used, which provides a medium level of
127 security. There's also `trusted` which runs the service at the highest
b99bfb13 128 privileges, i.e. host's root and everything. The `strict` profile comes with
44d565ed
LP
129 the toughest security restrictions. Finally, `nonetwork` is like `default`
130 but without network access. Users may define their own profiles too (or
131 modify the existing ones)
132
133And that's already it.
134
00473ac8 135Note that the images need to stay around (and in the same location) as long as the
44d565ed
LP
136portable service is attached. If an image is moved, the `RootImage=` line
137written to the unit drop-in would point to an non-existing place, and break the
138logic.
139
140The `portablectl detach` command executes the reverse operation: it looks for
141the drop-ins and the unit files associated with the image, and removes them
142again.
143
00473ac8 144Note that `portablectl attach` won't enable or start any of the units it copies
5d55791e
LB
145out by default, but `--enable` and `--now` parameter are available as shortcuts.
146The same is true for the opposite `detach` operation.
147
148A `portablectl reattach` command is made available to combine a `detach` with an
149`attach`, and it is useful in case an image gets upgraded, as it allows a to
150perform a `restart` operation on the unit(s) instead of `stop` plus `start`,
151thus providing lower downtime and avoiding losing runtime state associated with
152the unit such as the file descriptor store.
44d565ed 153
991b4350 154## Requirements on Images
44d565ed
LP
155
156Note that portable services don't introduce any new image format, but most OS
157images should just work the way they are. Specifically, the following
158requirements are made for an image that can be attached/detached with
159`portablectl`.
160
957848db
LP
1611. It must contain an executable that shall be invoked, along with all its
162 dependencies. If binary code, the code needs to be compiled for an
163 architecture compatible with the host.
44d565ed
LP
164
1652. The image must either be a plain sub-directory (or btrfs subvolume)
166 containing the binaries and its dependencies in a classic Linux OS tree, or
167 must be a raw disk image either containing only one, naked file system, or
168 an image with a partition table understood by the Linux kernel with only a
169 single partition defined, or alternatively, a GPT partition table with a set
170 of properly marked partitions following the [Discoverable Partitions
19ac32cd 171 Specification](https://systemd.io/DISCOVERABLE_PARTITIONS).
44d565ed
LP
172
1733. The image must at least contain one matching unit file, with the right name
174 prefix and suffix (see above). The unit file is searched in the usual paths,
175 i.e. primarily /etc/systemd/system/ and /usr/lib/systemd/system/ within the
176 image. (The implementation will check a couple of other paths too, but it's
177 recommended to use these two paths.)
178
6f61b14d
ДГ
1794. The image must contain an os-release file, either in `/etc/os-release` or
180 `/usr/lib/os-release`. The file should follow the standard format.
181
1825. The image must contain the files `/etc/resolv.conf` and `/etc/machine-id`
183 (empty files are ok), they will be bind mounted from the host at runtime.
44d565ed 184
957848db
LP
1856. The image must contain directories `/proc/`, `/sys/`, `/dev/`, `/run/`,
186 `/tmp/`, `/var/tmp/` that can be mounted over with the corresponding version
187 from the host.
188
1897. The OS might require other files or directories to be in place. For example,
190 if the image is built based on glibc, the dynamic loader needs to be
191 available in `/lib/ld-linux.so.2` or `/lib64/ld-linux-x86-64.so.2` (or
192 similar, depending on architecture), and if the distribution implements a
193 merged `/usr/` tree, this means `/lib` and/or `/lib64` need to be symlinks
194 to their respective counterparts below `/usr/`. For details see your
195 distribution's documentation.
196
197Note that images created by tools such as `debootstrap`, `dnf --installroot=`
198or `mkosi` generally qualify for all of the above in one way or another. If you
199wonder what the most minimal image would be that complies with the requirements
200above, it could consist of this:
44d565ed
LP
201
202```
570ee29c
LP
203/usr/bin/minimald # a statically compiled binary
204/usr/lib/systemd/system/minimal-test.service # the unit file for the service, with ExecStart=/usr/bin/minimald
205/usr/lib/os-release # an os-release file explaining what this is
206/etc/resolv.conf # empty file to mount over with host's version
207/etc/machine-id # ditto
208/proc/ # empty directory to use as mount point for host's API fs
209/sys/ # ditto
210/dev/ # ditto
211/run/ # ditto
212/tmp/ # ditto
213/var/tmp/ # ditto
44d565ed
LP
214```
215
216And that's it.
217
218Note that qualifying images do not have to contain an init system of their
219own. If they do, it's fine, it will be ignored by the portable service logic,
220but they generally don't have to, and it might make sense to avoid any, to keep
221images minimal.
222
957848db
LP
223If the image is writable, and some of the files or directories that are
224overmounted from the host do not exist yet they are automatically created. On
225read-only, immutable images (e.g. squashfs images) all files and directories to
226over-mount must exist already.
227
44d565ed 228Note that as no new image format or metadata is defined, it's very
00473ac8 229straightforward to define images than can be made use of in a number of
44d565ed
LP
230different ways. For example, by using `mkosi -b` you can trivially build a
231single, unified image that:
232
2331. Can be attached as portable service, to run any container services natively
234 on the host.
235
2362. Can be run as OS container, using `systemd-nspawn`, by booting the image
237 with `systemd-nspawn -i -b`.
238
2393. Can be booted directly as VM image, using a generic VM executor such as
240 `virtualbox`/`qemu`/`kvm`
241
2424. Can be booted directly on bare-metal systems.
243
244Of course, to facilitate 2, 3 and 4 you need to include an init system in the
245image. To facility 3 and 4 you also need to include a boot loader in the
246image. As mentioned `mkosi -b` takes care of all of that for you, but any other
247image generator should work too.
248
5d55791e
LB
249## Extension Images
250
251Portable services can be delivered as one or multiple images that extend the base
252image, and are combined with OverlayFS at runtime, when they are attached. This
253enables a workflow that splits the base 'runtime' from the daemon, so that multiple
254portable services can share the same 'runtime' image (libraries, tools) without
255having to include everything each time, with the layering happening only at runtime.
256The `--extension` parameter of `portablectl` can be used to specify as many upper
257layers as desired. On top of the requirements listed in the previous section, the
258following must be also be observed.
259
2601. The base/OS image must contain an os-release file, either in `/etc/os-release` or
261 `/usr/lib/os-release`. The file should follow the standard format.
262
2632. The upper extension(s) image(s) must contain an extension-release file in
264 `/usr/lib/extension-release.d/`, with an `ID=` and `SYSEXT_LEVEL=`/`VERSION_ID=`
265 matching the base image.
266
2673. The base/OS image does not need to have any unit files.
268
2694. The upper extension(s) image(s) must at least contain one matching unit file each,
270 with the right name prefix and suffix (see above).
271
272```
273# /usr/lib/systemd/portablectl attach --extension foobar_0.7.23.raw debian-runtime_11.1.raw foobar
274# /usr/lib/systemd/portablectl attach --extension barbaz_7.0.23.raw debian-runtime_11.1.raw barbaz
275```
276
991b4350 277## Execution Environment
44d565ed
LP
278
279Note that the code in portable service images is run exactly like regular
280services. Hence there's no new execution environment to consider. Oh, unlike
281Docker would do it, as these are regular system services they aren't run as PID
2821 either, but with regular PID values.
283
991b4350 284## Access to host resources
44d565ed
LP
285
286If services shipped with this mechanism shall be able to access host resources
287(such as files or AF_UNIX sockets for IPC), use the normal `BindPaths=` and
288`BindReadOnlyPaths=` settings in unit files to mount them in. In fact the
289`default` profile mentioned above makes use of this to ensure
290`/etc/resolv.conf`, the D-Bus system bus socket or write access to the logging
291subsystem are available to the service.
292
991b4350 293## Instantiation
44d565ed
LP
294
295Sometimes it makes sense to instantiate the same set of services multiple
296times. The portable service concept does not introduce a new logic for this. It
297is recommended to use the regular unit templating of systemd for this, i.e. to
298include template units such as `foobar@.service`, so that instantiation is as
299simple as:
300
301```
302# /usr/lib/systemd/portablectl attach foobar_0.7.23.raw
303# systemctl enable --now foobar@instancea.service
304# systemctl enable --now foobar@instanceb.service
305
306```
307
308The benefit of this approach is that templating works exactly the same for
309units shipped with the OS itself as for attached portable services.
310
991b4350 311## Immutable images with local data
44d565ed
LP
312
313It's a good idea to keep portable service images read-only during normal
314operation. In fact all but the `trusted` profile will default to this kind of
315behaviour, by setting the `ProtectSystem=strict` option. In this case writable
316service data may be placed on the host file system. Use `StateDirectory=` in
317the unit files to enable such behaviour and add a local data directory to the
318services copied onto the host.