cloud-init
De-facto-standard für die Initialisierung cloud - alle wichtigen Linux Distributionen + FreeBSD.
Merkmale
- basiert auf einer yaml config
- läuft als oneshot-dienst in systemd
- hat viele Module (kann z.B. chef oder puppet-code im stand-alone-modus laden)
- Frequenz (frequency) einstellbar (once, instance, always),
/etc/cloud/cloud.cfg
- datasource provider:
- EC2 style metadata server
- config-drive (openstack-style/cloudstack ab 4.11) entweder immer individuell oder nur defaults über und dann userdata im image verändert:
Images
-
- Ubuntu:
- CentOS (incl. stream): https://cloud.centos.org/centos/
datasource
configdrive / nocloud data source
openstack/latest/ meta_data.json network_data.json user_data vendor_data.json
Dual-Stack
Der YAML-parser wirft bei doppelter v4/v6 (inet/inet6)-Konfiguration den folgenden parsing-Fehler aus: cloudinit.net.ParserError interface can only be defined once
Der „Trick“ ist das gleiche Interface nochmal mit „:0“ anzugeben, das wird dann als verschiedenes interface interpretiert.
network-interfaces: | iface eth0 inet static address 1.2.3.4/24 gateway 1.2.3.1 iface eth0:0 inet6 static address 2a00:1:2:3::4/64 gateway 2a00:1:2:3::1
Die Netzwerkkonfiguration landet dann in:
- /var/lib/cloud/seed/nocloud-net/network-config (nocloud)
- /etc/network/interfaces.d/50-cloud-init.cfg (ifupdown)
- /etc/netplan/50-cloud-init.yaml (netplan)
weitere Partitionen
Standardmäßig vergrößert cloud-init das root-Dateisystem auf die maximale Größe des virtuellen Datenträgers („ephemeral disk“).
Beispiel: zwei zusätzliche Partitionen mit 10G und 30G Größe:
#cloud-config growpart: mode: off runcmd: # Parted asks whether to fix /dev/vda to use all available space, we reply "Fix" and continue # Resize primary partition to 10GB - "printf 'Fix\n1\nyes\n10GB\n' | parted ---pretend-input-tty /dev/vda resizepart" # Prepare partitions - "parted -s /dev/vda mkpart DATA ext4 10GB 20GB" - "parted -s /dev/vda mkpart DATA ext4 20GB 50GB" # Configure new partitions - "echo $(parted /dev/vda -s print|grep DATA |awk '/^\ *[0-9]+/{print $1}') > /partition_nums.txt" - "for i in $(cat /partition_nums.txt); do mkfs.ext4 /dev/vda${i}; done" - "for i in $(cat /partition_nums.txt); do e2label /dev/vda${i} DATA${i}; done" - "for i in $(cat /partition_nums.txt); do mkdir -p /mnt/disks/data${i}; done" - "for i in $(cat /partition_nums.txt); do mount -t ext4 /dev/vda${i} /mnt/disks/data${i}; done" - "for i in $(cat /partition_nums.txt); do echo LABEL=DATA${i} /mnt/disks/data${i} ext4 defaults 0 0 | sudo tee -a /etc/fstab; done" # System is not aware of new space on main partition. Needs refresh. - "resize2fs /dev/vda1"
https://docs.syseleven.de/syseleven-stack/de/howtos/repartition-vm-disk
Code
Links
- cloud-init Beispiele: https://cloudinit.readthedocs.io/en/stable/topics/examples.html
- proxmox (nocloud-v1, configdrive-v2 data sources): siehe Cloud-init
- Vorträge:
- Using Cloud Images in KVM https://www.theurbanpenguin.com/using-cloud-images-in-kvm/
Problembehandung
Passwort aus user-config setzen
Die Passwörter für root und den Standardbenutzer will man nicht als Klartext auf einem Server rumliegen haben. Daher RANDOM benutzen oder einen hash. Leider werden nicht alle hashes erkannt (z.B. der Standardmäßig bei Debian11 verwendet yescrypt mit $y nicht) weil die Unterscheidung zwischen Klartext und Hash mit einem regex vorgenommen wird (r'\$(1|2a|2y|5|6)(\$.+){2}').
Daher am besten ein bcrypt-hash für cloud-init hinterlegen und ggf. später mit ansible neu setzen.
Mögliche Konfiguration https://cloudinit.readthedocs.io/en/latest/topics/modules.html
chpasswd: list: - root:{{ baserole_root_password_hash }}
Kernel panic nach resize
Nach disk-resize kommt es zu einer kernel-panic. Grund ist ein fehlendes serielles Gerät wenn das Image Konsolenparameter (wie hier Debian11) von „console=tty0 console=ttyS0,115200“ hat.
Hier der Fix für libvirt: „The problem is „fixed“, if you remove '-serial none' from the kvm cmdline, and thus get the default serial device that kvm appends.
The original test.xml can be fixed in a similar manner by simply adding:
<console type='pty'> <target type='serial' port='0'/> </console>
It can also be fixed by mounting the image and removing 'console=ttyS0' from the kernel command lines in /boot/grub/grub.cfg.
Its hard to see, because observing it makes it work. But, I suspect that the root of the problem is that cloud-initramfs-growpart is writing to stdout, which is redirected to /dev/console, and /dev/console writes are going to the non-existant device 'ttyS0' (as told to by the command line).“
FQDN in /etc/hosts zeigt auf 127.0.1.1
Default is:
127.0.1.1 $FQDN $Hostname
Lösungsweg:
- 'manage_etc_hosts' as True
- Anpassung des master file in /etc/cloud/templates/hosts.debian.tmpl
- oder ändern/entfernen manage_etc_hosts in /etc/cloud/cloud.cfg oder cloud-config from user-data
Debugging von cloud-init
auf dem host: /var/log/cloud-init-output.log
cloud-init aufräumen
cloud-init reset und logs entfernen:
cloud-init clean -l