Skip to content

Commit

Permalink
Merge pull request #948 from kysrpex/kysrpex.systemd_nspawn
Browse files Browse the repository at this point in the history
Add kysrpex.systemd_nspawn role
  • Loading branch information
kysrpex authored Oct 23, 2023
2 parents 9d9350b + 9f845f6 commit 8496e13
Show file tree
Hide file tree
Showing 7 changed files with 354 additions and 0 deletions.
112 changes: 112 additions & 0 deletions roles/kysrpex.systemd_nspawn/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Ansible role: systemd-nspawn

A role that runs a container using systemd-nspawn. Only works on RHEL-based
systems, and can only run RHEL-based containers.

# Requirements

No specific requirements, the role is self-contained.

# Role variables

Default values are available on
[defaults/main.yml](https://github.com/usegalaxy-eu/infrastructure-playbook/blob/main/roles/kysrpex.systemd-nspawn/defaults/main.yml).

```yaml
nspawn_name: container_name
```
Name assigned to the container. It will show up when invoking
`machinectl list`, and can be used with `machinectl` commands, such as
`machinectl shell container_name`.

```yaml
nspawn_distro: "rocky"
nspawn_release: "9"
```

Distribution to base the container's rootfs on. The root file system of the
container is built using [DNF](https://en.wikipedia.org/wiki/DNF_(software))
and one of the configuration files in the
[templates](https://github.com/usegalaxy-eu/infrastructure-playbook/blob/main/roles/kysrpex.systemd-nspawn/templates)
folder. `nspawn_distro` determines the template to use, and `nspawn_release` is
passed to DNF so that it installs the correct distribution release.

```yaml
nspawn_packages:
- dhcp-client
- dnf
- glibc-langpack-en
- iproute
- iputils
- less
- passwd
- systemd
- dbus
- vim-minimal
```

List of packages to preinstall in the container's rootfs. They will be pulled
from the distribution's repositories using DNF.

```yaml
nspawn_config: |
# systemd-nspawn container configuration file
[Exec]
NotifyReady=yes
```

Configuration file for the container. See the
[systemd.nspawn manpage](https://manpages.debian.org/unstable/systemd-container/systemd.nspawn.5.en.html).

```yaml
nspawn_enable: true
nspawn_start: true
```

Whether to enable (meaning that it will autostart at boot) and/or start the
container after creating it.

# Dependencies

None.

# Example Playbook

```yaml
- name: Run a systemd-nspawn container.
hosts: host-machines
vars:
nspawn_name: container_name
nspawn_distro: "rocky"
# only distros that use DNF/YUM and are supported by the role, check the
# templates directory
nspawn_release: "9"
# any release of the supported distros
nspawn_packages:
# list of packages to install in the container's rootfs
- dhcp-client
- dnf
- glibc-langpack-en
- iproute
- iputils
- less
- passwd
- systemd
- dbus
- vim-minimal
nspawn_config: |
# systemd-nspawn container configuration file
[Exec]
NotifyReady=yes
pre_tasks:
# This role does not configure SELinux in a way such that it coexists with
# systemd-nspawn. If SELinux is enabled on your system, do NOT use this
# role.
- name: Disable SELinux.
become: true
ansible.posix.selinux:
state: disabled
roles:
- kysrpex.systemd_nspawn
```
21 changes: 21 additions & 0 deletions roles/kysrpex.systemd_nspawn/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
nspawn_name: nspawn
nspawn_distro: "rocky"
nspawn_release: "9"
nspawn_packages:
- dhcp-client
- dnf
- glibc-langpack-en
- iproute
- iputils
- less
- passwd
- systemd
- dbus
- vim-minimal

nspawn_config: |
# systemd-nspawn container configuration file
nspawn_enable: true
nspawn_start: true
29 changes: 29 additions & 0 deletions roles/kysrpex.systemd_nspawn/files/rocky-gpg.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBGAofzYBEAC6yS1azw6f3wmaVd//3aSy6O2c9+jeetulRQvg2LvhRRS1eNqp
/x9tbBhfohu/tlDkGpYHV7diePgMml9SZDy1sKlI3tDhx6GZ3xwF0fd1vWBZpmNk
D9gRkUmYBeLotmcXQZ8ZpWLicosFtDpJEYpLUhuIgTKwt4gxJrHvkWsGQiBkJxKD
u3/RlL4IYA3Ot9iuCBflc91EyAw1Yj0gKcDzbOqjvlGtS3ASXgxPqSfU0uLC9USF
uKDnP2tcnlKKGfj0u6VkqISliSuRAzjlKho9Meond+mMIFOTT6qp4xyu+9Dj3IjZ
IC6rBXRU3xi8z0qYptoFZ6hx70NV5u+0XUzDMXdjQ5S859RYJKijiwmfMC7gZQAf
OkdOcicNzen/TwD/slhiCDssHBNEe86Wwu5kmDoCri7GJlYOlWU42Xi0o1JkVltN
D8ZId+EBDIms7ugSwGOVSxyZs43q2IAfFYCRtyKHFlgHBRe9/KTWPUrnsfKxGJgC
Do3Yb63/IYTvfTJptVfhQtL1AhEAeF1I+buVoJRmBEyYKD9BdU4xQN39VrZKziO3
hDIGng/eK6PaPhUdq6XqvmnsZ2h+KVbyoj4cTo2gKCB2XA7O2HLQsuGduHzYKNjf
QR9j0djjwTrsvGvzfEzchP19723vYf7GdcLvqtPqzpxSX2FNARpCGXBw9wARAQAB
tDNSZWxlYXNlIEVuZ2luZWVyaW5nIDxpbmZyYXN0cnVjdHVyZUByb2NreWxpbnV4
Lm9yZz6JAk4EEwEIADgWIQRwUcRwqSn0VM6+N7cVr12sbXRaYAUCYCh/NgIbDwUL
CQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRAVr12sbXRaYLFmEACSMvoO1FDdyAbu
1m6xEzDhs7FgnZeQNzLZECv2j+ggFSJXezlNVOZ5I1I8umBan2ywfKQD8M+IjmrW
k9/7h9i54t8RS/RN7KNo7ECGnKXqXDPzBBTs1Gwo1WzltAoaDKUfXqQ4oJ4aCP/q
/XPVWEzgpJO1XEezvCq8VXisutyDiXEjjMIeBczxb1hbamQX+jLTIQ1MDJ4Zo1YP
zlUqrHW434XC2b1/WbSaylq8Wk9cksca5J+g3FqTlgiWozyy0uxygIRjb6iTzKXk
V7SYxeXp3hNTuoUgiFkjh5/0yKWCwx7aQqlHar9GjpxmBDAO0kzOlgtTw//EqTwR
KnYZLig9FW0PhwvZJUigr0cvs/XXTTb77z/i/dfHkrjVTTYenNyXogPtTtSyxqca
61fbPf0B/S3N43PW8URXBRS0sykpX4SxKu+PwKCqf+OJ7hMEVAapqzTt1q9T7zyB
QwvCVx8s7WWvXbs2d6ZUrArklgjHoHQcdxJKdhuRmD34AuXWCLW+gH8rJWZpuNl3
+WsPZX4PvjKDgMw6YMcV7zhWX6c0SevKtzt7WP3XoKDuPhK1PMGJQqQ7spegGB+5
DZvsJS48Ip0S45Qfmj82ibXaCBJHTNZE8Zs+rdTjQ9DS5qvzRA1sRA1dBb/7OLYE
JmeWf4VZyebm+gc50szsg6Ut2yT8hw==
=AiP8
-----END PGP PUBLIC KEY BLOCK-----
20 changes: 20 additions & 0 deletions roles/kysrpex.systemd_nspawn/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
galaxy_info:
namespace: kysrpex # change to usegalaxy-eu if releasing on Ansible Galaxy
role_name: systemd_nspawn
author: José Manuel Domínguez
description: Run a systemd-nspawn container.
company: The Galaxy Project
license: MIT
min_ansible_version: "2.13"
platforms:
- name: EL
versions:
- "8"
- "9"
galaxy_tags:
- system
- systemd
- container

dependencies: []
42 changes: 42 additions & 0 deletions roles/kysrpex.systemd_nspawn/tasks/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Build a container rootfs that can be used with systemd-nspawn.
---
- name: Ensure the build directory exists.
become: true
ansible.builtin.file:
path: "{{ nspawn_build_directory }}"
state: directory
mode: "0700"

- name: Template the DNF configuration needed to build the rootfs.
become: true
ansible.builtin.template:
src: "{{ nspawn_distro }}-dnf.conf.j2"
dest: "{{ nspawn_build_directory }}/nspawn-dnf.conf"
owner: root
mode: "0644"

- name: Copy the GPG key needed to build the rootfs.
become: true
ansible.builtin.copy:
src: "{{ nspawn_distro }}-gpg.pub"
dest: "{{ nspawn_build_directory }}/nspawn-gpg.pub"
owner: root
mode: "0644"

- name: Build the container rootfs.
become: true
ansible.builtin.shell:
executable: /bin/bash
cmd: |
dnf \
--assumeyes \
--releasever={{ nspawn_release }} \
--config {{ nspawn_build_directory }}/nspawn-dnf.conf \
--installroot={{ nspawn_build_directory }} \
--setopt=install_weak_deps=False \
--repo=nspawn-baseos \
--repo=nspawn-appstream \
--repo=nspawn-extras \
install {{ nspawn_distro }}-release \
{{ nspawn_packages | join(' ') }}
changed_when: true
100 changes: 100 additions & 0 deletions roles/kysrpex.systemd_nspawn/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
- name: Ensure systemd-container is installed.
become: true
ansible.builtin.package:
name: systemd-container
state: installed

- name: Check if the container already exists.
ansible.builtin.shell:
executable: /bin/bash
cmd: "machinectl image-status {{ nspawn_name }}"
register: nspawn_status
changed_when: false
failed_when: nspawn_status.rc == 127 # command not found

- name: Build and import the container rootfs.
become: true
when: nspawn_status.rc != 0
block:
- name: Create a temporary build directory.
when: nspawn_build_directory is not defined
ansible.builtin.tempfile:
state: directory
suffix: "ansible.{{ ansible_role_name }}"
register: nspawn_build_directory

- name: Overwrite nspawn_build_directory with the build directory path.
# only if the build directory was created by the previous task
when: nspawn_build_directory.path is defined
ansible.builtin.set_fact:
nspawn_build_directory: "{{ nspawn_build_directory.path }}"

- name: Build the container rootfs.
ansible.builtin.include_tasks: build.yml

- name: Get the location of machinectl's image store.
ansible.builtin.shell:
executable: /bin/bash
cmd: |
set -o pipefail
machinectl image-status | grep "Path: " | awk '{$1=$1};1' | cut -d' ' -f2
# `machinectl image-status` prints
# Path: /var/lib/machines
# to stdout.
changed_when: false
register: nspawn_image_store

- name: Import the container rootfs.
become: true
ansible.builtin.shell:
executable: /bin/bash
cmd: "mv {{ nspawn_build_directory }} {{ nspawn_image_store.stdout }}/{{ nspawn_name }}"
changed_when: true
rescue:
- name: Clean the build directory.
ansible.builtin.file:
path: "{{ nspawn_build_directory }}"
state: absent

- name: Ensure the systemd-nspawn configuration directory exists.
become: true
ansible.builtin.file:
path: /etc/systemd/nspawn
state: directory
mode: "0755"

- name: Configure the container.
become: true
ansible.builtin.copy:
content: "{{ nspawn_config }}"
dest: "/etc/systemd/nspawn/{{ nspawn_name }}.nspawn"
mode: "0644"

- name: Enable the container.
# meaning that it will autostart at boot
become: true
ansible.builtin.shell:
executable: /bin/bash
cmd: "machinectl enable {{ nspawn_name }}"
register: nspawn_container_enable
changed_when: nspawn_container_enable.rc == 0 and nspawn_container_enable.stderr != ''
when: nspawn_enable

- name: Check if the container is already running.
ansible.builtin.shell:
executable: /bin/bash
cmd: "machinectl show {{ nspawn_name }} -p State --value"
register: nspawn_status
changed_when: false
failed_when: nspawn_status.rc == 127 # command not found
when: nspawn_start

- name: Start the container.
become: true
ansible.builtin.shell:
executable: /bin/bash
cmd: "machinectl start {{ nspawn_name }}"
register: nspawn_container_enable
changed_when: nspawn_status.stdout != 'running'
when: nspawn_start
30 changes: 30 additions & 0 deletions roles/kysrpex.systemd_nspawn/templates/rocky-dnf.conf.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[main]
gpgcheck=1
installonly_limit=3
clean_requirements_on_remove=True
best=True
skip_if_unavailable=False

[nspawn-baseos]
name=Rocky Linux $releasever - BaseOS
mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=BaseOS-$releasever
#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/BaseOS/$basearch/os/
gpgcheck=1
enabled=1
gpgkey=file://{{ nspawn_build_directory }}/nspawn-gpg.pub

[nspawn-appstream]
name=Rocky Linux $releasever - AppStream
mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=AppStream-$releasever
#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/AppStream/$basearch/os/
gpgcheck=1
enabled=1
gpgkey=file://{{ nspawn_build_directory }}/nspawn-gpg.pub

[nspawn-extras]
name=Rocky Linux $releasever - Extras
mirrorlist=https://mirrors.rockylinux.org/mirrorlist?arch=$basearch&repo=extras-$releasever
#baseurl=http://dl.rockylinux.org/$contentdir/$releasever/extras/$basearch/os/
gpgcheck=1
enabled=1
gpgkey=file://{{ nspawn_build_directory }}/nspawn-gpg.pub

0 comments on commit 8496e13

Please sign in to comment.