You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Stephane Bausseron 410e022763 Merge branch 'ci-jobs-add-docker-tag' into 'master' 1 year ago
bootp-registry Project initialization: add BOOTP registry part 1 year ago
targets/base [target/base] Add FROM_UBUNTU_VERSION Dockerfile argument 1 year ago
tools/gitlab-ci [target/build] Add target_docker_build_* hooks 1 year ago
.gitignore Project initialization: add BOOTP registry part 1 year ago
.gitlab-ci.yml [CI] Add docker tag to the jobs 1 year ago
LICENSE Add LICENSE file 1 year ago [target/base] Add FROM_UBUNTU_VERSION Dockerfile argument 1 year ago


The LiveBOOTP project is a solution in two parts:

  • The BOOTP registry
  • Targets images

Table of Contents

Target image creation

Each target image is generated using a simple way (Dockerfile based format) and produce, for each version, a set of file: kernel image + initrd + squashfs filesystem

You can create a new target in tree steps. To illustrate with an example, wee will create a nginx web server image named nginx-web-server.

There is two type of target image:

  • Intermediate image: Used as base image by several targets
  • Final image: image to deploy

Target creation step 1: Gitlab-CI job creation

The first step is to add the new job into the .gitlab-ci.yml file.

There are tree steps to the image generation & deployment:

  • 1: Image build (intermediate and final images): Build the image and store it into the registry
  • 2: SquashFS image generation (final images specific): Extract SquashFS and kernel image from the docker image
  • 3: Image deployment to the BOOTP registries (final images specific): This step is specific and must be designed depending on your IT environment

The job format must follow this model (only the two first steps will be documented here):

    - /^target-my-target-name\/.*$/
  <<: *target-build-template

    - /^target-my-target-name\/.*$/
  <<: *target-mksquashfs-template

For our example, we will create the following job:

    - /^target-nginx-web-server\/.*$/
  <<: *target-build-template

    - /^target-nginx-web-server\/.*$/
  <<: *target-mksquashfs-template

Target creation step 2: Docker file creation

The target image is built from targets/my-target-name/Dockerfile.

The Dockerfile supported commands are: FROM, RUN, ADD, COPY, ENV, WORKDIR and VOLUME. The other commands will don’t have any effect.

  • Note 1: The image must be built FROM the $CI_REGISTRY_IMAGE/base:version or derivated image (where CI_REGISTRY_IMAGE contains your-registry.domain/group/your-bootp-project)
  • Note 2: for each declared volume with VOLUME Dockerfile keyword, a persistant data directory will be created (using add_pertistant_storage "/your/volume" bind copy, see here for more details).

For our example, we will create a file targets/nginx-web-server/Dockerfile containing:

FROM $CI_REGISTRY_IMAGE/base:1.2.0-ubuntu-16.04

RUN apt update &&                                 \
    DEBIAN_FRONTEND=noninteractive apt install -y \
        nginx                                     \

VOLUME /etc/nginx /var/www

IMPORTANT NOTE, for final/bootable image, not required for intermediate one: you have to install a valid kernel image (like linux-image-generic)

Optionally, you can add custom docker build hooks to perfom additional actions before and after the docker build by adding a file targets/my-target-name/ following this model:

target_docker_build_before() {
    echo "Executed before docker build, useful to perform some action that cannot be performed into the Dockerfile"

target_docker_build_after() {
    echo "Executed before docker build, useful to perform some action like temporary files cleanup"

Target creation step 3: startup script (optional)

This part explain how to add start script to perform some custom initialization. The global LiveBOOTP process is stored into the file list targets/base/startup.d/XX*.sh

Generic startup process

The generic startup process (regrouped into the files targets/base/startup.d/XX_*.sh):

  • [Once: first boot] Persistant storage initialization:
    • Create (if doesn’t exists) and mount the persistant storage device
    • Setup SSH host keys
  • [Once: first boot] Setup a new set of sshhost* key files for the SSH server
  • [Always: each boot] Setup the hostname from the hostname given by the bootp-registry
  • [Always: each boot] Fetch and setup the root authorized_keys specified by the bootp-registry

Add custom startup script

You can add your own script, e.g.: targets/nginx-web-server/

And add a line like :

ADD /etc/livebootp/startup.d/

in your targets/nginx-web-server/Dockerfile

How to build the target

  • With Gitlab-CI: create a tag under the following format: target-my-target-name/x.y.z where x.y.z is the version number. The gitlab-ci job is triggered only on tags with the prefix target-my-target-name/
  • On your workstation: with the ci-toolbox command like this: ci-toolbox target-my-target-name-mksquashfs (in addition you can use --image-tag parameter to customize version)

Note: For the base target, the tag is in the format target-base/<base_version>-ubuntu-<ubuntu_docker_version> (e.g.: target-base/1.2.0-b0-ubuntu-bionic-20171220. The Ubuntu docker version list can be found here. If the -ubuntu-<ubuntu_docker_version> is not specified, the selected version will be latest corresponding to the latest LTS release.

The generated files will be available in the artifacts/my-target-name/x.y.z/ directory

The BOOTP registry

The BOOTP registry is based on a docker image containing a DHCP and TFTP server where the configuration of all the service is centralized into a very basic YAML file.

How to build the registry

  • With Gitlab-CI: create a tag under the following format: bootp-registry/x.y.z where x.y.z is the version number. The gitlab-ci job is triggered only on tags with the prefix bootp-registry/
  • On your workstation: with the ci-toolbox command like this: ci-toolbox bootp-registry (in addition you can use --image-tag parameter to customize version)

How to setup the registry

The config-default.yml configuration file contains the full configuration schema with a documentation for each properties.

For our example we have to define the file bootp-registry/config/config.yml with the following content:


    hardware-ethernet: "52:54:00:12:34:56"
    fixed-address: ""
    image-name: nginx-web-server/test
    ssh-authorized-keys: default
    cmdline-append: debug

For the bootp-registry:

  • On many distributions, all the bootp-registry parameters can be auto detected. In this case, we have just overloaded the domain-name-servers due to some distributions like Ubuntu which contains a local DNS cache not accessible outside the local host.

We have defined a host block for our nginx web server:

  • Host name (block key name): my-nginx-web-server
  • MAC address (hardware-ethernet): 52:54:00:12:34:56 (may be customized when we will create the test target virtual machine)
  • IP address (fixed-address):
  • Image name (image-name): nginx-web-server/test (If you have generated your image using a custom version --image-tag x.y.z, set nginx-web-server/x.y.z here)
  • SSH authorized-keys file (ssh-authorized-keys): default (For this test, don’t change this value: the bootp-registry/ script used in the following part will mount your local ~/.ssh/ as /var/lib/tftpboot/ssh_authorized_keys/default into the bootp-registry docker)
  • [OPTIONAL] Append kernel parameters (cmdline-append): We have append debug property to the kernel parameter to add debug info, see here for more information.

How to start a registry on your workstation

You can run the registry on your local workstation to perform some test on the generated target images.

You can start the registry on your local workstation using the command:

$ bootp-registry/

On the start process, an info message with You have to use the bridge br-xxxxxxxxxxxx where br-xxxxxxxxxxxx is the bridge to use for your test target virtual machine.

Setup target virtual machine

libvirt is highly recommended here !

To setup the test virtual machine with libvirt, simply run:

$ virt-install --name my-nginx-web-server --vcpus 1 --memory 1024 \
    --pxe --disk size=10 --boot network --os-variant ubuntu16.04 \
    --network bridge=br-xxxxxxxxxxxx,model=virtio,mac=52:54:00:12:34:56 \
    --noreboot --noautoconsole --wait 0

Otherwith, you have to create manually a test virtual machine with the following properties:

  • An network interface bridged on br-xxxxxxxxxxxx
  • Start process setup on network (PXE)
  • The hardware address must be the same than the my-nginx-web-server.hardware-ethernet in the bootp-registry/config/config.yml file

NOTE: VirtualBox guest PXE client is not fully fonctional with this solution for now

How to deploy the registry

In the first time, you have to prepare your environment:

  • /opt/bootp-registry/config must contains your production config.yml file
  • /opt/bootp-registry/images is the directory where you have to deploy your images
  • /opt/bootp-registry/ssh-authorized-keys is the directory where you have to put the ssh authorized keys files

Note: you can customize the paths on the host side (/opt/bootp-registry/…)

You can now start the registry like this:

$ docker run --name bootp-registry -d --tmpfs /var/run \
    -v /opt/bootp-registry/config:/opt/livebootp/etc \
    -v /opt/bootp-registry/images:/var/lib/tftpboot/images \
    -v /opt/bootp-registry/ssh-authorized-keys:/var/lib/tftpboot/ssh_authorized_keys \
    --network host

Note: --network host is used here to bind directly on the host ethernet interface.


RC.local: useful functions

Print error message and exit

  • argument 1: Message

Print error message

  • argument 1: Message

print note message

  • argument 1: Message

Print info message

  • argument 1: Message


Fetch a resource

  • argument 1: URL
  • argument 2: target file path


Get a /proc/cmdline parameter

  • argument 1: parameter name


Test if mount point is active

  • argument 1: target mount point


Test if two files have the same content

  • argument 1: file 1
  • argument 2: file 2


Add a persistant storage

  • argument 1: target mount point (e.g.: /var/www)
  • argument 2: persistant storage format (accepted values: bind (default) and unionfs)
  • argument 3 only applicable for bind persistant storage format: Initialization method (accepted values: copy (default) and none)

LibeBOOTP kernel parameters


This parameter enable debug output into the files:

  • /var/log/live/boot.log: Ubuntu liveboot process
  • /var/log/live/livebootp-startup.log: Startup process


Allow to fetch resources on unsecure HTTPS server.


Disable root password. Useful to debug startup scripts.

The ci-toolbox command

The ci-toolbox command is a tool, provided by the tools/gitlab-ci/ setup execution, to run Gitlab-CI jobs on your local workstation (see the project page for more information)