Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

GitHub action to use systemd-nspawn to run commands in a (un)booted container on a Raspberry Pi SD card image

License

Apache-2.0, Unknown licenses found

Licenses found

Apache-2.0
LICENSE-Apache
Unknown
LICENSE-BlueOak.md
NotificationsYou must be signed in to change notification settings

ethanjli/pinspawn-action

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Repository files navigation

GitHub action to usesystemd-nspawn to run commands in a (un)booted container on a Raspberry Pi SD card image

systemd-nspawn isused to run commands in a light-weight namespace container, like chroot but with full virtualizationof the file system hierarchy, the process tree, the various IPC subsystems, and the host and domainname. It can also be used to boot the image's init program (which is usually systemd) as an OS; thisaction makes it easy to run a set of shell commands whether or not the OS is booted in thecontainer. You can use this action to set up Docker containers as part of your OS image buildprocess in GitHub Actions!

Note that currently only unbooted containers work correctly on GitHub's new hosted arm64 runners;booted systemd-nspawn containers spontaneously initiate shutdown as soon as the system boot sequencereaches the login prompt. Maybe that's a bug which will magically go away after the hosted arm64runners exit public preview (this is wishful thinking). If you want to start or interact with theDocker daemon inside an unbooted container on an arm64 runner, you will need instantiate thecontainer with theCAP_NET_ADMIN capability (to make iptables work as required by Docker) and thenmanually start both containerd (by launching/usr/bin/containerd as a background process) and theDocker daemon (by launching/usr/bin/dockerd as a background process). Seethe relevant example below for an illustration ofhow to do this.

Motivation

Unlike thealternatives listed below (which you should evaluate based on your ownproject's requirements to see which ones might be more appropriate for you),ethanjli/pinspawn-action attempts to provide a bare-minimum abstraction which gets youcloserto shell scripting - it tries to minimize the amount of tool-specific abstraction for you to learn,and the only thing you can do with it is to run your own shell commands/scripts.

Also, by contrast to every below-listed alternative besides sdm, pinspawn-action takes advantage ofa mechanism which is more powerful (and more similar to actually-booted Raspberry Pi environments)than chroots. pinspawn-action is designed specifically as an ergonomic wrapper for GitHub Actionsto use systemd-nspawn with Raspberry Pi OS images.

Basic Usage Examples

Run shell commands as root

-name:Install and run cowsayuses:ethanjli/pinspawn-action@v0.1.5with:image:rpi-os-image.imgrun:|      apt-get update      apt-get install -y cowsay      /usr/games/cowsay 'I am running in a light-weight namespace container!'

Run shell commands in a specific shell

-name:Run in Pythonuses:ethanjli/pinspawn-action@v0.1.5with:image:rpi-os-image.imgshell:pythonrun:|      import platform      for word in reversed(['!', platform.python_version(), 'Python', 'in', 'running', 'am', 'I']):        print(word, end=' ')

Run shell commands as thepi user

-name:Run without root permissionsuses:ethanjli/pinspawn-action@v0.1.5with:image:rpi-os-image.imguser:pishell:shrun:|      sudo apt-get update      sudo apt-get install -y figlet      figlet -f digital "I am $USER in $SHELL!"

Run an external script directly, with the shell selected by its shebang line

-name:Make a script on the hostuses:1arp/create-a-file-action@0.4.5with:file:figlet.shcontent:|      #!/usr/bin/env -S bash -eux      figlet -f digital "I am $USER in $SHELL!"-name:Make the script executablerun:chmod a+x figlet.sh-name:Run script directlyuses:ethanjli/pinspawn-action@v0.1.5with:image:rpi-os-image.imgargs:--bind "$(pwd)":/run/externaluser:pishell:/run/external/figlet.sh

Run shell commands with one or more bind mounts from the host OS

-name:Make a bootloader configuration snippetuses:1arp/create-a-file-action@0.4.5with:file:boot-config.snippetcontent:|      # Enable support for the RV3028 RTC      dtoverlay=i2c-rtc,rv3028,trickle-resistor-ohms=3000,backup-switchover-mode=1-name:Modify bootloader configurationuses:ethanjli/pinspawn-action@v0.1.5with:image:rpi-os-image.imgargs:--bind "$(pwd)":/run/externalrun:|      cat /run/external/boot-config.snippet >> /boot/firmware/config.txt      # Note: this assumes rpi-os-image.img is for bookworm or later:      cp /boot/firmware/config.txt /run/external/boot.config-name:Print the bootloader configrun:cat boot.config

Run shell commands in a booted container

Note: the system in the container will shut down after the specified commands finish running.

-name:Analyze systemd boot processuses:ethanjli/pinspawn-action@v0.1.5with:image:rpi-os-image.imgargs:--bind "$(pwd)":/run/externalboot:truerun:|      while ! systemd-analyze 2>/dev/null; do        echo "Waiting for boot to finish..."        sleep 5      done      systemd-analyze critical-chain | cat      systemd-analyze blame | cat      systemd-analyze plot > /run/external/bootup-timeline.svg      echo "Done!"-name:Upload the bootup timeline to Job Artifactsuses:actions/upload-artifact@v4with:name:bootup-timelinepath:bootup-timeline.svgif-no-files-found:erroroverwrite:true

Interact with Docker in an unbooted container

Note: this example willonly work if you run it in theubuntu-24.04-arm GitHub Actions runner;trying to run it onubuntu-22.04-arm results in an error whendockerd tries to start(failed to start daemon: Devices cgroup isn't mounted).

-name:Install Dockeruses:ethanjli/pinspawn-action@v0.1.5with:image:rpi-os-image.imgrun:|      export DEBIAN_FRONTEND=noninteractive      apt-get update      apt-get install -y ca-certificates curl      install -m 0755 -d /etc/apt/keyrings      curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc      chmod a+r /etc/apt/keyrings/docker.asc      echo \        "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \        https://download.docker.com/linux/debian \        $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \        > /etc/apt/sources.list.d/docker.list      apt-get update      apt-get install -y \        docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin-name:Pull a Docker container imageuses:ethanjli/pinspawn-action@v0.1.5with:image:rpi-os-image.imgargs:--capability=CAP_NET_ADMINrun:|      #!/bin/bash -eux      /usr/bin/containerd &      sleep 5      /usr/bin/dockerd &      sleep 10      docker image pull hello-world      docker image ls

Usage Options

Inputs:

InputAllowed valuesRequired?Description
imagefile pathyesPath of the image to use for the container.
argssystemd-nspawn options/argsno (default ``)Options, args, and/or a command to pass tosystemd-nspawn.
shell``,bash, `sh`, `python`, etc.no (default ``)The shell to use for running commands.
runshell commandsno (default ``)Commands to run in the shell.
username of user in imageno (defaultroot)The user to run commands as.
bootfalse,trueno (defaultfalse)Boot the image's init program (usually systemd) as PID 1.
run-servicefile pathno (default ``)systemd service to runshell with therun commands; only used with booted containers.
boot-partition-mountfile pathno (default ``)Mount point of the boot partition.
  • image must be the path of an unmounted raw disk image (such as a Raspberry Pi OS SD card image),where partition 2 should be mounted as the root filesystem (i.e./) and partition 1 should bemounted to/boot.

  • args can be a list of command-line options/arguments forsystemd-nspawn.You should not set the--user or--boot flags here; instead, you should set theuser andboot action inputs.

  • Ifrun is not left empty,shell will be used to execute commands specified in therun input.You can use built-inshell keywords, or you can define a custom set of shell options. The shellcommand that is run internally executes a temporary file that contains the commands to run, likein GitHub Actions.Please refer to the GitHub Actions semantics of theshell keyword of job steps for detailsabout the behavior of this action'sshell input.

    If you just want to run a single script, you can leaverun empty and provide that script as theshell input. However, you will need to set the appropriate permissions on the script file.

  • Ifboot is enabled, this action will usesystemd-nspawn to automatically search for an initprogram in the image (typically systemd) and invoke it as PID 1, instead of a shell.

    • The providedrun commands will be triggered by a temporary system service defined with thefollowing template (unless you specify a different service file template using therun-serviceinput):

      [Unit]Description=Run commands in booted OSAfter=getty.target[Service]Type=execExecStart=bash -c "\  su - {user} -c '{command}; echo $? | tee {result}'; \  echo Shutting down...; \  shutdown now \" &StandardOutput=tty[Install]WantedBy=getty.target

      This service file template has string interpolation applied to the following strings:

      • {user} will be replaced with the value of the action'suser input.
      • {command} will be replaced with a command to run your specifiedrun commands using yourspecifiedshell
      • {result} will be replaced with the path of a temporary file whose contents will be checkedafter the container finishes running to determine whether the command finished successfully(in which case the file should be the string0); this file is interpreted as holding areturn code.
    • If this flag is enabled, then any arguments specified as the command line inargs are used asarguments for the init program, i.e.systemd-nspawn will be invoked likesystemd-nspawn --boot {args}.

  • Ifboot-partition-mount is not specified, the action will automatically select/boot/firmwareif that directory exists in the root partition (which is true of RPi OS bookworm or later), or/boot otherwise (for compatibility with RPi OS bullseye).

Running Locally

You may also be able to run thegha-wrapper-pinspawn.sh script on your own computer, but you willhave to figure out how to install the required dependencies yourself - take a look ataction.yml to see what extra apt packages get installed on top of the GitHub Actionsrunner's default set of packages, and to see how you can pass inputs to thegha-wrapper-pinspawn.sh script as environment variables. Or, if youreally can't tolerate using environment variables, you can instead directly invokepinspawn.sh - look at the contents ofgha-wrapper-pinspawn.sh to see how to doso.

Alternatives

I'm aware of a variety of existing approaches for generating custom Raspberry Pi OS images in GitHubActions CI for building a custom OS which is meant to be maintained (i.e. changed) over time. Thefollowing are all built as abstractionsaway from pure shell-scripting and, with the exceptionof sdm, are based on pure chroots (which come with various limitations, some of which may affectyour work depending on your goals):

  • Nature40/pimod: a great option to consider if you want to useDockerfile-style syntax. Ready-to-use as aGitHub Action! If you want to interact with Docker, you will need to use some advancedDocker-in-Docker magic - seehere fordetails.
  • usimd/pi-gen-action withRPi-Distro/pi-gen: a good option to consider if you wantto build OS images using the same(rather-complicated) abstractionsystem that is used for building the Raspberry Pi OS, e.g. for multi-stage builds.
  • guysoft/CustomPiOS: a system of build scripts organizedaround pre-defined modules which you can combine with your own scripts. A good option to considerif you want to use some of the modules they provide in your own OS image, or if you also want tobuild images locally (e.g. in a Docker container, apparently?).
  • gitbls/sdm: a system of build scripts organized aroundpre-defined plugins which you can combine with your own scripts. Has many more plugins for you tosearch through compared to CustomPiOS, and also has enough functionality to replace Raspberry PiImager. Can work on chroots, but defaults to using systemd-nspawn instead. You may need to figureout GitHub Actions integration yourself.
  • pndurette/pi-packer: potentially reasonable if you know(or would be comfortable learning)Packer andPacker HCL. You may need tofigure out GitHub Actions integration yourself.
  • raspberrypi/rpi-image-gen: Raspberry Pi's newframework for building custom images, if you want to learn their unique YAML-based configurationsystem. You may need to figure out GitHub Actions integration yourself.

If you absolutely need to run shell commands/scripts in a booted QEMU virtual machine with fullvirtualization of Raspberry Pi hardware, I have createdethanjli/piqemu-action with basically the sameinterface as pinspawn-action. However, I found in GitHub Actions runners that Raspberry Pi QEMU VMsare quite slow (especially for downloading files over the network) and flaky (in the sense that theywill just freeze in the middle of work without a helpful error message, requiring you to restart theworkflow to make it work - which is definitely a some kind of bug). I strongly recommend usingpinspawn-action instead of piqemu-action unless you have something which absolutely won't workoutside a full virtual machine.

Licensing

We have chosen the following licenses in order to give away our work for free, so that you canfreely use it for whatever purposes you have, with minimal restrictions, while still protecting ourdisclaimer that this work is provided without any warranties at all. If you're using this project,or if you have questions about the licenses, we'd love to hear from you - please start a newdiscussion thread in the "Discussions" tab of this repository on Github or email us atlietk12@gmail.com .

Software

Except where otherwise indicated, source code provided here is covered by the following information:

Copyright Ethan Li and pinspawn-action contributors

SPDX-License-Identifier:Apache-2.0 OR BlueOak-1.0.0

Software files in this repository are released under theApache 2.0 License and theBlue Oak Model License 1.0.0;you can use the source code provided here either under the Apache License or under theBlue Oak Model License, and you get to decide which license you will agree to.We are making the software available under the Apache license because it'sOSI-approved,but we like the Blue Oak Model License more because it's easier to read and understand.Please read and understand the licenses for the specific language governing permissions andlimitations.

About

GitHub action to use systemd-nspawn to run commands in a (un)booted container on a Raspberry Pi SD card image

Topics

Resources

License

Apache-2.0, Unknown licenses found

Licenses found

Apache-2.0
LICENSE-Apache
Unknown
LICENSE-BlueOak.md

Stars

Watchers

Forks

Languages


[8]ページ先頭

©2009-2025 Movatter.jp