dustin/jenkinsagent/pipeline/head This commit looks goodDetails
There is apparently a bug in *runc* 1.1.0 that prevents privileged
containers from starting:
> docker: Error response from daemon: failed to create shim: OCI runtime
> create failed: runc create failed: unable to start container process:
> unable to apply cgroup configuration: chown
> /sys/fs/cgroup/system.slice/docker-….scope/memory.oom.group: no such
> file or directory: unknown.
A patch is available but has not been integrated into an official
release yet.
Docker and Jenkins need more storage than is available in the *tmpfs*
filesystem mounted at `/var`. We can use NBD to provide additional
storage volumes for these paths.
The `nbd@.service` systemd unit, which is included in the *nbd* package
but not actually installed by it, starts an NBD client, using the
configuration in `/etc/nbdtab` for the specified block device. To avoid
hard-coding the NBD server name here, the file included in the rootfs
image is actually a template. This template is rendered at boot time,
using the same server name specified on the kernel command line for the
rootfs device. Obviously, this implies that the same server has to host
both the rootfs image and the persistent storage, but that is not likely
to be a problem for this project.
To allow multiple devices to use the same rootfs image but separate
persistent storage devices, the `nbdtab` template can include a
placeholder for the device's serial number. This only works for
Raspberry Pi devices, of course, but the concept could be extended to
other device types by adding more placeholders for other
machine-specific properties (e.g. DMI UUID, etc.)
Since `/var/lib/jenkins` is the home directory for the *jenkins* user,
and thus the location of its `~/.ssh/authorized_keys` file, we have to
make sure the *fetch-sshkeys@jenkins.service* unit does not start until
the persistent storage volume is mounted. We also need a service unit
that ensures the permissions of the mount point are correct,
particularly for the first boot when the filesystem is initially
created.
Similarly, we have to ensure that the Docker daemon does not start until
`/var/lib/docker` is mounted. Adding a `RequiresMountsFor=` property to
the *docker.service* unit generates the necessary dependencies to
accomplish this.
*dhcpcd* does not set the system host name to the value provided in the
DHCP lease unless the current hostname matches its compiled-in default
value (which is `(none)`) or is *localhost*. I'm not sure how to change
the former, but we can easily set the default to the latter to enable
dynamic hostname configuration via DHCP.
By default, *dhcpcd* generates a "complete" `chrony.conf` file using the
NTP servers specified in the DHCP lease, and then restarts the Chrony
daemon. This is unnecessary, as *chrony* can reload its list of
sources without restarting, and also problematic in our case. For one
thing, *dhcpcd* tries to write to `/etc/chrony.conf` directly, which is
obviously impossible when the root filesystem is immutable.
Fortunately, it is flexible enough to be configured to leave
`/etc/chrony.conf` alone and generate a different file and then tell
*chrony* to reread it.
The *chrony-wait.service* unit introduces a delay into the system
startup that allows follow-up units to wait until the system time is
confirmed correct. The unit file itself was derived from the one
included in the *chrony* package for Fedora.