Friday 5th April 2024 7:13 PM

NOTE: If you're doing this in VMware, now would be a good time to take a snapshot, so that you can repeatedly test provisioning on a clean box.

Now that our server hardware has been prepared, we can install the OS. We provide an Ignition script that specifies how we want the system to be configured, that will be run on first boot, to provision the system. However, the Ignition file format is a bit difficult to work with, so scripts are written in Butane format, which is then converted to Ignition.

Here's a simple Butane script that configures the password[1]You would normally use SSH keys for login, but my server is for internal use only, so I just use a password. for the default core user (use mkpasswd to generate the hash):

variant: fcos
version: 1.5.0

passwd:
  users:
    - name: core
      password_hash: $y$j9T$DUQ4JpHLE86HQpQemBNs3.$W2K2ymcyTaADWJfrZGbBnYFndwfYGtx6fs0lhzQJtu5

And to convert it to Ignition format[2]You will need to install the butane package.:

butane --pretty --strict config.bu >config.ign

We then run a command in the pre-installation environment that loads the base CoreOS image onto the system disk, plus our Ignition config file, so that when the computer boots up, it processes that Ignition config, to provision the system.

The problem is getting the Ignition file to the installer. The pre-installation environment is minimal, so VMware Tools and open-vm-tools are not there, so we can't use VMware's shared folders. And even if we could, the installer takes a URL, and the file:// protocol doesn't work.

The easiest way is to prepare the config files on another machine, and then run python -m http.server in that directory, which runs a little web server that serves files from that directory. Then, we can provide a URL to the Ignition config file[3]Where 10.2.2.10 is the IP address of my host machine.:

sudo coreos-installer install \
    /dev/sda \
    --insecure-ignition \
    --ignition-url http://10.2.2.10:8000/config.ign

The installer will load the base image on the specified device, and when it's done, type reboot to boot the server. Our Ignition config will be processed during this first boot, and when you are presented with the login prompt, you should be able to login in as the core user, using the password you specified earlier.

Automatically generating the Ignition config file

Having to run the butane command each time you change the Butane config file gets very old very fast, so I wrote a script that monitors this file for changes, and automatically re-generates the Ignition file:

cd $( dirname "$0" )
prev_md5=
while true; do
    md5=$( md5sum config.bu files/* )
    if [ "$md5" = "$prev_md5" ]; then
        sleep 1
    else
        if butane --pretty --strict --files-dir ./files/ config.bu >config.ign; then
            echo "Updated: `date`"
        fi
        prev_md5=$md5
    fi
done

Note that it also watches other files in a files/ sub-directory, that we will be creating later in this tutorial.

Configuring the server

To set the server's hostname, we configure Ignition to set up a file at /etc/hostname:

storage:
  files:
    - path: /etc/hostname
      mode: 0644
      contents:
        inline: vm-k3s

We also do something similar to configure the NIC with a static IP address:

storage:
  files:
  - path: /etc/NetworkManager/system-connections/ens33.nmconnection
    mode: 0400
    overwrite: true
    contents:
      local: nic.nmconnection

where nic.nmconnection looks like this[4]Make sure that the interface name matches what is on your machine.:

[connection]
interface-name = ens33
type = ethernet

[ipv4]
method = manual
address1 = 10.2.2.33/24,10.2.2.1
dns = 10.2.2.1

Note that while this file content can be specified inline in the Butane config file, the file will get very big very quickly[5]And much less readable., so I've moved it out into an external file. In this case, we need to have a --files-dir parameter when converting to Ignition format, that specifies the base directory of these external files e.g.

butane --pretty --strict --files-dir ./files/ config.bu >config.ign

Finally, I like to disable auto-updates[6]I update systems on my schedule, after ensuring that everything's backed up safely, and checking that everything works properly afterwards.:

storage:
  files:
  - path: /etc/zincati/config.d/90-disable-auto-updates.toml
    mode: 0644
    contents:
      inline: |
        [updates]
        enabled = false

Go back to your clean VM snapshot, run coreos-installer install again, with the updated Butane config, to re-provision the machine, and you should see all these changes have been applied to the new installation.




References

References
1 You would normally use SSH keys for login, but my server is for internal use only, so I just use a password.
2 You will need to install the butane package.
3 Where 10.2.2.10 is the IP address of my host machine.
4 Make sure that the interface name matches what is on your machine.
5 And much less readable.
6 I update systems on my schedule, after ensuring that everything's backed up safely, and checking that everything works properly afterwards.