Image Deploy¶
The image-deploy plugin deploys images to systems. These images can be tarballs that get untarred onto defined partition-based filesystems or raw disk images that get blown onto the disk. In either case, additional files can be injected into the images for post-install operations.
The provided stages and workflows also know how to drive cloud-init and provided the information required to let cloud-init startup the post-install process. This includes injecting DRPCLI-based runners.
The image-deploy system is built upon and extends the curtin project. Curtin is driven by a configuration YAML file that is built dynamically based upon the value of parameters. These parameters drive the actual imaging process.
Getting Started¶
The 'image-deploy-base' Workflow has been defined as a getting started reference example. It contains the mose basic components needed for image provisioning.
Image-Deploy Image Construction¶
image-deploy requires an image. This image can be in many different formats. The format type defines what additional
operational parameters that need to be set. These images can be built using RackN's image-builder content pack,
using Hashicorp's Packer tool (examples can be found here: FILL_IN), or other tools that generate images. The images
have some specific requirements that must be met for success.
The first requirement is that all images must have a /curtin directory in the top-level directory of the base
image file. If the image is a raw disk image, this directory must be backed into that. If the image is a rootfs
tarball, the directory must be added as part of that tarball. This must be created by the base image or first image
applied. Whoever builds the image also owns the permissions on that directory - image-deploy cannot tighten them
on a Windows image. See /curtin Permissions.
The second requirement is that all drivers must be added to the system in the base image or additional tarball packages. The image-deploy components do NOT handle driver updates or installs.
The third requirement is for raw disk images. The disk image must be constructed for the the boot-style of the target hardware. If the hard is going to boot in UEFI mode, then the disk image must be formatted with EFI partitions that hold EFI bootloaders. The same applies for legacy systems. There are disk layouts that can work for both.
A final item to consider during image construction is how will the next phase of operation start. This means what will
run the next phase of operation. For windows, this could be an unattend.xml that is part of the image or injected by
additional parameters. Or it could be cloud-init is installed and set to automatically start. The image-deploy
system has the ability configure cloud-init meta-data and user-data with default to start a DRP runner on
boot. The system will also inject scripts to install a runner for the OS type in question. These could also be called
to install the agent as well. Depending upon the choice of startup method, different things need to be done. Some
involve adding things to the image.
/curtin Permissions¶
/curtin is deployment scratch space, not part of the running system. image-deploy writes the curtin hooks, the
join-up bootstrap (drpcli-install.sh or drpcli-install.bat), and - when image-deploy/cloud-init-base-url is
left at its file:///curtin/ default - the cloud-init meta-data and user-data into it. meta-data carries
the values of image-deploy/admin-username, image-deploy/admin-password and access-keys, so its contents are
sensitive on every OS. No machine token is written there; see Agent Join-Up and Cleanup.
Everything under /curtin is written from the Linux deployment OS, so the permissions image-deploy can apply are
limited to what the target filesystem understands:
- Linux and ESXi images - the deploy sets
/curtinto mode0700, owned byroot. Nothing further is required of the image. - Windows images - the deploy writes NTFS from Linux. POSIX mode bits do not become NTFS ACLs there, so the
chmodis a no-op and image-deploy cannot restrictC:\curtin. AC:\curtinthe image did not create picks up the inheritable ACL of the volume root, which grantsBUILTIN\Usersread access.
On Windows the ACL on C:\curtin is the image builder's responsibility. Create the directory while building
the image, break inheritance on it, and grant only SYSTEM and Administrators:
New-Item -ItemType Directory -Path C:\curtin -Force | Out-Null
icacls C:\curtin /inheritance:r
icacls C:\curtin /grant 'NT AUTHORITY\SYSTEM:(OI)(CI)F' 'BUILTIN\Administrators:(OI)(CI)F'
Know what that does and does not buy. It stops ordinary users from listing C:\curtin, but Windows grants
Bypass traverse checking to Everyone by default, so a user who already knows a file name can still open that
file if the file's own ACL allows it - and files written to NTFS from the Linux deployment OS do not pick up the
parent directory's ACL. Treat the directory ACL as defense in depth.
The actual control is that /curtin does not survive. Once the agent has joined, image-deploy-cleanup removes
C:\curtin entirely. If you set image-deploy/cleanup-curtin to false, or point custom cloud-init/user-data
or unattend content at /curtin for later boots, then you are choosing to keep it and you must re-apply the ACLs
from inside Windows on first boot, where they take effect. A SetupComplete.cmd, an unattend
FirstLogonCommands entry, or a cloud-init runcmd running the icacls lines above all work.
Image-Deploy Operations¶
Once an image id built, the system needs to know where it is, what type of image it is, what OS it contains, and what startup process to use. These are all defined as parameters that can be added to a machine. Because all of this information is consistent across all machines using this image, it is best practice to create a profile that contains all these parameters.
To define the location of the image file, you must use ONE of the following parameters. If both are used, the system
will use the image-deploy/image-file value.
- image-deploy/image-file - This is a path relative to the tftpboot directory of the running DRP endpoint. e.g. If the
image has been uploaded with the files API to images/my-win-image.raw.gz, then the value of this parameter would be
files/images/my-win-image.tar.gz. - image-deploy/image-url - This is a URL that references the image. This must be an http or https URL that does NOT require authentication.
To define the type and content of the image, all of these values must be specified:
- image-deploy/image-type - This is the curtin image type value. These types are define in the parameter and validated by the systems. Some examples are: dd-gz, tgz, and others.
- image-deploy/image-os - This is the type of OS being installed. Current values are are linux or windows. The value of basic is deprecated and maps to windows.
- image-deploy/image-os-subtype - This is the subtype of the
image-deploy/image-osvalue. This is ignored currently for windows, but for linux, this is used to indicate arawimage. Therawvalue indicates that the disk is a full disk image and curtin should not run any hooks to alter the image state.
Additional parameters can be used to override and expand the system.
Image-Deploy Customizations¶
With the basic parameters set in a profile, additional parameters can be added to drive further customization and enhancements.
Partitioning¶
When using a raw disk image, partitioning is not used other than to select the hard disk. By default, this will be
specified by the image-deploy/install-disk parameter with a value of /dev/sda. This value can be overridden
to direct the install to a different location.
When using a rootfs and other tarballs, the system will use the image-deploy-install-disk as the default disk and
use a simple GPT-based filesystem layout chosen by curtin. A custom partition table can be added by using the
curtin/partitions parameter. This object-based parameter will be converted to yaml and injected into the
curtin-config yaml.
The curtin/partitions parameter is an object that defines the disks, partitions, filesystems, and mount points for
system. The definition of the object can be found here: https://curtin.readthedocs.io/en/latest/topics/storage.html.
Additional Content¶
Once the base image and the RackN content tarball are added to the system, additional tarballs can be added to the main
disk. These are defined in the image-deploy/additional-tarballs parameter. This is a list of objects that define
file locations or URLs, and format (like the image-deploy/image-type parameter. The assumption is that these tarballs
will be applied at the root level of the mounted images. These MUST be built prior to the curtin-deploy task is
executed.
The image-deploy tasks build one tarball and apply it for all systems. This is the RackN Content tarball. This contains at a minimum an OS appropriate runner, the curtin hooks needed to complete installation if required, an install script to install the DRPCLI as a runner, and optionally cloud-init configuration pieces.
The following pieces are installed and their locations:
- drpcli(.exe) - For linux, this is installed to
/usr/local/bin. For windows, this isC:\Program Files\drpcli, which is where the join-up and control scripts expect to find it. - curtin hooks - These will go into
/curtinand can be ignored. - join-up bootstrap -
/curtin/drpcli-install.sh(linux) or/curtin/drpcli-install.bat(windows). - machine UUID -
/etc/rs-uuid(linux) orC:\ProgramData\drp-uuid.txt(windows). This lets the join-up bootstrap bind to the right machine when it cannot be matched by MAC address.
For window's systems, there is an additional file added if specified. If image-deploy/windows-unattend-template
is defined, it should contain the name of a template that is loaded into the system. This template will be expanded and
stored in the newly imaged filesystem at the location specified by image-deploy/windows-unattend-path. The default
path is Windows/Panther/unattend.xml. This can be used to inject a dynamic unattend xml file for startup usage. This
allows for a more flexible image.
For further flexibility, the system can be configured to configure cloud-init or cloud-base as well.
Cloud-Init / Cloud-Base¶
The image-deploy system will attempt to configure cloud-init (or Cloud-Base the windows version of cloud-init) by default.
To turn this off, set the image-deploy/use-cloud-init parameter to false.
For linux systems, the system will configure cloud-init to use a data source to find meta-data and user-data.
These will be injected locally by default into the /curtin directory. The image-deploy/cloud-init-base-url
parameter allows this to be overridden. This can be other directory locations and the files will be placed accordingly.
The system also allows for a remote file location through specific URLs or parameter expansion. A common use would be
to specific, {{.Machine.Url}}/. This expansion would map to files provided by the image-deploy-cloud-init
stage.
For windows systems, the system will configure cloud-base to use the custom RackN data source that works similar to the
data sources used by linux. The same parameters control the location and contents of the meta-data and user-data
files.
The contents of the meta-data file includes the hostname, ssh access keys, admin-username, and admin-password.
Hostname is specified by the Machine.Name field. The ssh access keys are pulled from the access-keys parameter.
The admin-username and admin-password come from the parameters image-deploy/admin-username and image-deploy/admin-password
respectively if specified.
The final piece of cloud-init data is the user-data file. If not specified, the default action will be to install
and start the DRP runner as a last action of cloud-init. Other user-data content can be provided by filling in the
string parameter, cloud-init/user-data. For best results, one should include a final run command to install
and start the agent.
For linux,
For windows,
Agent Join-Up and Cleanup¶
drpcli-install.sh and drpcli-install.bat do not contain a machine token. They download
machines/join-up.sh (or machines/join-up.ps1) from the endpoint and run it, which identifies the
machine, obtains a token over the network, and hands off to the machine's control.sh/control.ps1
to install and start the agent. The image-deploy-cloud-init stage serves those control scripts, so
the machine must be in that stage while the deployed system comes up for the first time.
This matters most on Windows, where image-deploy cannot restrict C:\curtin and the image builder must
set its ACL instead - see /curtin Permissions. Anything image-deploy writes there has to
be assumed readable by every local user, which is why no credentials are placed in it.
Once the agent is running, the image-deploy-cleanup task removes the join-up and control scripts
from the temporary directories, and removes /curtin (C:\curtin) entirely. Set
image-deploy/cleanup-curtin to false to keep /curtin, for example if custom cloud-init/user-data
or unattend content reads from it on later boots.
On Windows the task also removes C:\root and C:\usr. Curtin copies its install log and the
rendered install config into the target's /root, and that config contains the value of
image-deploy/windows-license-key when it is set, so on NTFS it would otherwise be left readable by
every local user. C:\usr is an empty directory left behind by older versions of this pack. On
Linux and ESXi both paths are real system directories and are never touched.
Deprecated Templates¶
The following templates are deprecated as of v4.16.5 and will be removed in a later release. No task, stage or bootenv in this pack references any of them.
These six render an infinite machine token into their output, so anything that writes their result to disk leaves a credential that never expires on the deployed system:
curtin-linux-runner.sh.tmplcurtin-windows-runner.ps1.tmplcurtin-basic-linux-finish.sh.tmplcurtin-linux-finish.sh.tmplcurtin-basic-windows-finish.ps1.tmplcurtin-windows-finish.ps1.tmpl
The first two were previously written into /curtin as drpcli.sh and drpcli.ps1. curtin-deploy
no longer places them in the image, which is the fix for the world-readable token; the templates
themselves remain for compatibility.
One consumer lives outside this pack. The eikon pack's eikon-cloudbase-init-config task
called curtin-windows-runner.ps1.tmpl by ID and wrote it to C:\curtin\drpcli.ps1 on the
deployed machine, which put two infinite machine tokens in the image on eikon's default Windows
path. eikon stopped doing that in v4.16.14. Check for out-of-pack callers by template ID
before removing any of these.
These four are unused leftovers of the earlier Cloudbase-derived Windows finalize path:
curtin-basic-finalize.tmplcurtin-windows-finalize.tmplcurtin-windows-finalize.py.tmplcurtin-windows-maasservice.py.tmpl
They are all still shipped because .CallTemplate and parameters such as
image-deploy/windows-unattend-template can name any template by ID, so an existing deployment could
be calling one. Do not call them in new work. Marking the machine runnable and kicking off job
processing is handled by the join-up described above.
Problem Determination¶
To debug issues, you can set the curtin/debug parameter to true and addtional curtin logs will be generated.
Ubuntuhammer¶
As part of the 4.11 release RackN added support for a custom version of Ubuntu targeted directly at doing an image-deploy using Ubuntu as the OS instead of using Sledgehammer. Doing this allowed for the most recent version of curtin to be used. Changes to the curtin code made it too difficult to get it working on RHEL based distros, so using sledgehammer as the image-deploy deployment OS will lock the curtin version at 20.2 whereas using ubuntuhammer will provide 22.1 or newer. Ubuntuhammer will continue getting updates to its curtin version as new releases are made available, where sledgehammer will not.
For the 4.11 release Ubuntuhammer is available to be used in image-deploy, sledgehammer is still the default system used for image-deploy, but a new param was added to allow setting Ubuntuhammer as the image-deploy deployment OS. Using the opt-in method allows operators to try the new functionality without introducing changes to their current vetted processes.
To use Ubuntuhammer as the image-deploy deployment OS first you need to upload the ubuntuhammer iso to the endpoint.
Next add the paramimage-deploy/deployment-os to a profile and set its value to "ubuntuhammer" then attach that profile to the
machine. When you run image-deploy it should use ubuntuhammer instead of sledgehammer to deploy the image. This works like other
params and can be in a profile directly attached to a machine, or at a global level by placing the param in the global profile.
Another helpful global param is the kexec-ok param. Adding it to your global profile and setting the value to true will speed
up the process by reducing unnecessary reboots.