1
0
Fork 0
mirror of https://gitlab.alpinelinux.org/alpine/aports.git synced 2025-07-19 17:25:17 +03:00
aports/community/cloud-init
..
01-oauthlib-remove.patch
02-disable-irrelevant-modules.patch
03-hook-hotplug-sh.patch
04-add-doas.patch
APKBUILD
cloud-init-hotplugd
cloud-init-hotplugd.initd
cloud-init.logrotate
cloud-init.post-install
interfaces
README.Alpine
setup-cloud-init

After the cloud-init package is installed you will need to run the
"setup-cloud-init" command to prepare the OS for cloud-init use.

This command will enable cloud-init's init.d services so that they are run
upon future boots/reboots.


** IMPORTANT **
---------------

To avoid the Alpine package having a large number of dependencies that in
many cases would be unnecessary the package only has a general set of
dependencies defined that are common for the majority of use cases.

When creating an Alpine OS image that makes use of cloud-init you should
read the rest of this document, set a DataSources list to only enable
whichever DataSource(s) you require, and install any additionally required
Alpine package dependings on the filesystem type, DataSource(s), etc in use.
Information related to this is contained in the rest of this document.



Customising the enabled Data Sources list
-----------------------------------------

Whenever cloud-init runs on first boot it determines which DataSource is to
be used for performing machine configuration, it does so by reading the
"datasource_list" definition in the /etc/cloud/cloud.cfg file.

By default "datasource_list" is not set and so cloud-init defaults to
enabling all DataSources. If you do NOT set a "datasource_list" then you
should also install *all* the additional Alpine packages required by the
full set of DataSources - these are detailed below - to avoid cloud-init
errors/warnings.

If you are creating a cloud-init enabled Alpine image for a specific
environment, or a known set of environments, then it would make sense to
add a "datasource_list" value to only list whichever DataSource is
required/expected as this potentially result in (slightly) faster first boot
times as each individual enabled DataSource would not have to be checked in
sequence until the required one is reached.

For example if creating an Alpine image only for use with AWS then adding
the following setting to /etc/cloud/cloud.cfg would make sense:

  datasource_list: ['Ec2', 'None']

whereas if the image was intended to be used for either of AWS, Azure, or
Google Cloud then:

  datasource_list: ['Ec2', 'Azure', 'GCE', 'None']

and for an image to only be used with ISO or disk configuration files:

  datasource_list: ['NoCloud', 'None']


Additional Alpine packages required by specific DataSources
-----------------------------------------------------------

  Azure                           dhclient
  CloudSigma & SmartOS/Joyent     py3-pyserial
  Ec2                             dhclient, eudev
  GCE                             dhclient
  Hetzner                         dhclient
  MAAS                            py3-oauthlib
  NWCS                            dhclient
  OpenStack                       eudev
  Oracle                          dhclient
  Scaleway                        dhclient
  UpCloud                         dhclient
  VMware                          py3-netifaces
  Vultr                           dhclient


Additional Alpine packages you may want or need to manually install
-------------------------------------------------------------------

  doas

    Alpine v3.15+, see the section "Sudo & Doas" below.

  mdevd or eudev

    see the section "mdev / mdevd / eudev" below.

  mount (Alpine Edge & v3.17+) or util-linux-misc (Alpine v3.15 & v3.16)
  or util-linux (Alpine <= v3.14)

    see the section "Using ISO images for cloud-init configuration (i.e.
    with NoCloud/ConfigDrive)" below.

  openssh-server or openssh-server-pam

    see the section "Unable to SSH in as user(s) as the account(s) is/are
    locked" below.

  sudo

    see the section "Sudo & Doas" below.

Also please read the section "Missing dependencies" below for further
information.


mdev / mdevd / eudev
--------------------

As of Alpine release v3.17 (and Edge from mid-Nov 2022 onwards) the Alpine
cloud-init package can be used together with either eudev (aka udev), mdev,
or mdevd.

Due to this change the cloud-init package from Alpine v3.17 onwards no longer
declares a dependency on the eudev package - you will need to manually install
either eudev or mdevd to your Alpine disk image if required. You may also need
to run "setup-devd mdevd" or "setup-devd udev" accordingly to enable those
instead of mdev.

Upstream cloud-init is only designed and tested to work with udev and
therefore some cloud-init functionality may not work when either mdev or mdevd
are used instead. This document will, over time, detail any known mdev or
mdevd incompatible cloud-init modules and/or Data Sources.


Sudo & Doas
-----------

Cloud-init has always had support for 'sudo' when adding users (via
user-data). As Alpine has now moved towards preferring the use of 'doas'
rather than 'sudo' support for 'doas' has been added to the cc_users_groups
module.

As a result, the Alpine cloud-init package from Alpine v3.15 onwards no
longer declares a dependency on sudo - you must ensure to install either the
'doas' or 'sudo' package (or indeed both), depending on which you wish to use,
in order to be able to create users that can run commands as a privileged
user.


Doas
----

The cloud-init support for Doas has not (yet) been upstreamed, it only
exists in the Alpine cloud-init package. This functionality performs some
basic sanity checks of per-user Doas rules - it double-checks that the user
referred to in any such rules corresponds to the user the rule(s) is/are
defined for - if not then an error appears during 1st boot and no Doas rules
are added for that user.

It is recommended that you set up a Doas rule: "permit persist :wheel" so
that all members of group 'wheel' can have root access. The default
/etc/doas.d/doas.conf file has such a rule but it is commented out.

The cloud-init global configuration file /etc/cloud/cloud.cfg defines the
default 'alpine' user to be created upon 1st boot with a Doas rule giving
password-less root access - as the 'alpine' user is locked for password
access, both local and remote, and so only SSH key-based access is available
then obviously password-based Doas access would not work.

To setup Doas rules for additional users, both existing and new, in the
user-data add a 'doas' entry to define one or more rules to be setup for
each user, for example:

  users:
    - default
    - name: tester
      doas: ["permit tester as root"]

When cloud-init runs on 1st boot it creates the file
/etc/doas.d/cloud-init.conf containing all the per-user rules specified in
user-data, as well as the rule for the default 'alpine' user.

NOTE: if you specify a "users:" section in user-data you MUST specify a
"default" entry in addition to any other entries, otherwise the default
'alpine' user will NOT be created.


NTP
---

It is recommended that you enable a NTP client on the machine. Cloud-init
supports both Chrony (fully featured) and Busybox's NTP client (a minimal
implementation).

Chrony is the default NTP client in cloud-init for Alpine Linux.


To use Chrony as the NTP client:

  Install the chrony package and enable the chrony init.d service

    # apk add chrony
    # rc-update add chronyd default

  Specify a ntp section in your cloud-init User Data like so:

    ntp:
      pool:
        - 0.uk.pool.ntp.org
        - 1.uk.pool.ntp.org

  If you do not specify any pool or servers then 0.pool.ntp.org ->
  3.pool.ntp.org will be used.

  The file /etc/cloud/templates/chrony.conf.alpine.tmpl is used by cloud-init
  as a template to create the configuration file /etc/chrony/chrony.conf.


To use Busybox as the NTP client:


  Edit the /etc/conf.d/ntpd file and change the line:

    NTPD_OPTS="-N -p pool.ntp.org"

  so that it is instead:

    NTPD_OPTS="-N"

  This changes the NTP client from using the hardcoded NTP server
  "pool.ntp.org" to instead use the /etc/ntp.conf file which will be
  generated by cloud-init upon first boot.

  Enable the ntp init.d service:

    # rc-update add ntpd default

  Specify a ntp section in your cloud-init User Data like so:

    ntp:
      ntp_client: ntp
      servers:
        - 192.168.0.1
        - 192.168.0.2

  If you do not specify any servers then 0.pool.ntp.org -> 3.pool.ntp.org
  will be used.

  The file /etc/cloud/templates/ntp.conf.alpine.tmpl is used by cloud-init
  as a template to create the configuration file /etc/ntp.conf.



Network interface hotplugging
-----------------------------

Version 21.3 of cloud-init has added some support for network interface
hotplugging, that is the addition or removal of additional network
interfaces on an already running machine.

A simple daemon, cloud-init-hotplugd, if enabled runs at boot time that
listens for udev hotplug events and triggers cloud-init to react to them.

This daemon, via its init.d script, is *not* at present enabled by the
setup-cloud-init script as hotplug is currently *only* supported by the
'ConfigDrive', 'Ec2', and 'OpenStack' DataSources.

In order to make use of network hotplug you will need to do the following
*three* things:

  - install and enable the Alpine "eudev" package for managing devices.

  - add the /etc/init.d/cloud-init-hotplugd script to the "default"
    run-level, i.e.

      rc-update add cloud-init-hotplugd default

  - enable hotplug for the relevant DataSource by adding the following to
    either the /etc/cloud.cfg file or else to the supplied user-data:

      updates:
        network:
          when: ['boot','hotplug']


Limitations
===========

Unable to resize LVM or LUKS rootfs partitions and filesystems on them
----------------------------------------------------------------------

cloud-init's cc_growpart module, if enabled, attempts to resize the root
partition. If however the rootfs is on a /dev/mapper/ devices (whether LVM,
or LUKS, or LVM-on-LUKS, or LUKS-on-LVM, cc_growpart will be unable to
resize the partition - this is due to a difference in behaviour between mdev
(always used by Alpine's initramfs **even if eudev is used by the rest of
the OS once the rootfs is mounted**) and eudev.

When the initramfs' init runs it will trigger mdev to create a /dev/mapper/
entry, if required, for the rootfs. With mdev this entry is an actual file,
whereas eudev would create it as a softlink to the underlying /dev/dm-*
device. Cloud-init's cc_growpart attempts to determine the device that
provides the rootfs and, due to this mdev limitation, believes this is
/dev/mapper/<whatever> rather that the actual /dev/dm-<whatever> device. The
/growpart utility can resize /dev/dm-*

This issues affects partition growing/fs resizing regardless of whether
udev, mdev, or mdevd is enabled in the Alpine disk image - Alpine's
initramfs' init *always* runs mdev regardless.

As a workaround, in user-data provided to the VM the runcmd module can be
used to perform any resizing as follows:

For a LUKS-encrypted rootfs (assuming it is on a LUKS partition labelled
"lukspart" and is device /dev/sda2):

  runcmd:
    - growpart /dev/sda2
    - cryptsetup resize lukspart
    - resize2fs /dev/mapper/lukspart

For a LVM-based rootfs (assuming it is on a LVM VG called "rootfs" in VG
"vg0" with /dev/sda2 being the partition LVM is using):

  runcmd:
    - growpart /dev/sda2
    - lvextend -l +100%FREE /dev/mapper/vg0-rootfs
    - resize2fs /dev/mapper/vg0-rootfs



Known Issues
============


Unable to SSH in as user(s) as the account(s) is/are locked
-----------------------------------------------------------

Issue: By default cloud-init will ensure that any user accounts have their
password locked. The OpenSSH sshd daemon has logic that, when PAM is not
enabled, for accounts with locked passwords it *also* decides to refuse
key-based SSH logins.

Solution: install the openssh-server-pam package (rather than
openssh-server) and edit /etc/ssh/sshd_config to ensure that it defines
"UsePAM yes".

In the future this package may add "openssh-server-pam" as a dependency but
as it is possible some individuals may wish to use cloud-init without any
SSH daemon installed that decision is unclear.


Missing dependencies
--------------------

The cloud-init package declares dependencies for only commonly used
cloud-init modules - if deps for all supported modules were defined then the
dependency list would be quite large.

As a result when building cloud-init based disk images you may need to
manually install additional packages required by some cloud-init modules.

The following modules should work, in general, with the defined dependencies:

  cc_apk_configure
  cc_bootcmd
  cc_ca_certs
  cc_disable_ec2_metadata
  cc_disk_setup
  cc_final_message
  cc_growpart
  cc_key_to_console
  cc_locale
  cc_migrator
  cc_mount
  cc_package_update_upgrade_install
  cc_phone_home
  cc_power_state_change
  cc_resizefs
  cc_resolv_conf
  cc_rsyslog
  cc_runcmd
  cc_scripts_per_boot
  cc_scripts_per_instance
  cc_scripts_per_once
  cc_scripts_user
  cc_scripts_vendor
  cc_seed_random
  cc_set_hostname
  cc_set_passwords
  cc_ssh
  cc_ssh_authkey_fingerprints
  cc_timezone
  cc_update_etc_hosts
  cc_update_hostname
  cc_users_groups
  cc_write_files

If you want to delete existing partitions using cc_disk_setup then you will
need to install the Alpine "wipefs" package.

If you want to create/resize filesystems using cc_disk_setup and/or
cc_resizefs then you will need to install the relevant package(s) containing
the appropriate tools:

  BTRFS:        btrfs-progs
  EXT2/3/4:     e2fsprogs-extra
  F2FS:         f2fs-tools
  LUKS:         cryptsetup and device-mapper
  LVM:          lvm2 and device-mapper
  XFS:          xfsprogs and xfsprogs-extra
  ZFS:          zfs

Cloud-init assumes the use of dhclient for DHCP purposes. However other DHCP
clients do also work, in part, with cloud-init. Therefore "dhclient" has not
been set as a hard dependancy for the Alpine package.

However if you are using a DataSource (i.e. AWS Ec2, Azure, GCE, Hetzner,
NWCS, OpenStack, Oracle, Scaleway, UpCloud, and Vultr) that needs to set up a
Ephemeral (temporary) DHCPv4 connection in order to talk to a Metadata Server
(to retrieve metadata, network configuration, and user-data information from)
then these DataSources expect "dhclient" to be installed and will try and
execute it directly and therefore retrieving information from the metadata
server will fail if dhclient is not installed).


cc_ca_certs module
------------------

The "remove-defaults" option of the cloud-init cc_ca_certs module does not
currently work correctly. This option will delete certificates installed by
the Alpine ca-certificates package as expected. However the certificates
provided by the ca-certificates-bundle package, which is always automatically
installed in an Alpine system due to it being a dependency of a base package,
are not deleted.


Using ISO images for cloud-init configuration (i.e. with NoCloud/ConfigDrive)
-----------------------------------------------------------------------------

The "mount" command in Alpine is provided by the "busybox" package by default.

The "mount" package (Alpine v3.17+), "util-linux-misc" package (Alpine v3.15
& v3.16), or "util-linux" package (Alpine <= v3.14) provides an alternative,
full featured, version of the "mount" command.

Cloud-init makes use of the mount command's "-t auto" option to mount a
filesystem containing cloud-init configuration data (detected by searching
for a filesystem with the label "cidata"). Busybox's mount command behaves
differently to that of util-linux's when the "-t auto" option is used,
specifically if the kernel module for the required filesystem is not already
loaded the util-linux mount command will trigger it to be loaded and so the
mount will succeed. However Busybox's mount will not normally trigger a kernel
module load and the mount will fail!

When this problem occurs a message such as the following will be displayed on
the console during boot:

  util.py[WARNING]: Failed to mount /dev/vdb when looking for data

If cloud-init debugging is enabled then the file /var/log/cloud-init.log will
also contain the following entries:

  subp.py[DEBUG]: Running command ['mount', '-o', 'ro', '-t', 'auto',
  '/dev/vdb', '/run/cloud-init/tmp/tmpAbCdEf'] with allowed return codes [0]
  (shell=False, capture=True)
  util.py[DEBUG]: Failed mount of '/dev/vdb' as 'auto': Unexpected error
  while running command.
  Command: ['mount', '-o', 'ro', '-t', 'auto', '/dev/vdb',
  '/run/cloud-init/tmp/tmpAbCdEf']
  Exit code: 255
  Reason: -
  Stdout:
  Stderr: mount: mounting /dev/vdb on /run/cloud-init/tmp/tmpAbCdEf failed:
  invalid argument

There are 2 possible solutions to this issue, either:

(1) Install the mount (Edge and v3.17+) / util-linux-misc (v3.15 & v3.16) /
    util-linux (<= v.3.14) package in the Alpine image used with cloud-init.

or:

(2) Create (or modify) the file /etc/filesystems and ensure it has a line
    present with the name of the required kernel module for the relevant
    filesystem i.e. "iso9660". This will ensure that Busybox's mount will
    trigger the loading of this kernel module.