1.Úvod
Cloud-init (dále CI) je multiplatformní balíček který má na starosti prvotní inicializaci VPS. Podporu CI nalezneme u většiny rozšířených OS či u poskytovatelů cloudu. Aby ne, vždyť také významným způsobem ulehčuje automatizaci a počáteční deploy. Používá se také k personalizaci VPS u různých dodavatelů.
Mezi takové základní konfigurace, které chceme mít zavedené při iniciálním deploy VPS patří automatická konfigurace všeho, co se dělá těžce za běhu stroje:
- IP adresy
- DNS
- Hostname
- Hosts
- SSH klíče
- user login i hesla
Někteří vývojáři OS dodávají rovnou předpřipravené CI image, typicky třeba společnost Canonical, která vyvíjí OS Ubuntu. My si zde ukážeme deploy CI na Proxmoxu. Proxmox jako jeden z mála hypervizorů, který je na deployment CI výborným způsobem připraven.
2. Jak a co vytáčet?
existuje určitý filozofický rozkol mezi tím, co je vhodné mít v image přímo od začátku a tím, co je vhodno si dodělat přes nějakou orchestraci po deploy VPS. Jinými slovy – máme-li nový OS tak má smysl do něj nainstalovat nějakou sadu balíčků, nebo je lepší po vytočení VPS je tam dodatečně poslat třeba přes Ansible? Odpověď na to se odvíjí od toho, jak moc často vznikají změny. Pokud například na CI VPS nainstalujeme zabbix agenta, tak při každém vytáčení VPS můžeme v CI nechat aktualizovat všechny balíčky a tím nám může v čase vzniknout stav, kdy se nám rozjedou verze. U nějakých verzí je nám to jedno. Balíček vim/nano není tak podstatný, aby měl všude stejné verze, ale na druhou stranu takové prostředí není ani žádoucí v produkci. Lze to řešit dvěma způsoby:
- v CI nastavíme, že budeme chtít po vytočení VPS nechat nainstalovat konkrétní verzi nějakého nástroje a poté nastavíme, aby po druhém rebootu VPS už nedocházelo k inicializaci apt-upgrade automaticky.
- Nebudeme řešit aby CI provedl instalaci balíčků a po vytočení VPS si je nainstalujeme přes Ansible přes nějaký playbook co si k tomu vytvoříme.
Pokud ale jste pokroková firma, už máte dávno zaveden proces patching serverů a to znamená, že pokud vytočíte nějakou novou VPS se sadou nejnovějších balíků, velmi pravděpodobně zbytek infrastruktury k těmto balíčkům rychle dorovnáte, protože chcete mít vše v infrastruktuře v pořádku sjednocené. Jinak vám vzniká technologický dluh a to je v oblasti IT velmi nebezpečné. Samozřejmě vytáčení verzí a jejich patch management je relativní. Nepodstatné balíčky na práci typu vim, nano apod se mohou srovnávat na všech serverech a pravděpodobně neovlivní produkci, ale srovnávat verze PHP, MariaDB už nemusí být k vývojářům solidární a na ty je potřeba dávát extra pozor, aby se nerozbila produkce. Takové balíčky nedává smysl mít v CI, ale dává smysl je orchestrovat.
3. Cloud init na Proxmoxu
3.1 Příprava CI image
Přípravu CI image lze provést dvěma způsoby:
- Stažením hotového CI image
- Tvorba vlastního CI
Základem přípravy CI image je utvořit co nejvíce čistou instalaci OS, kterému pak jen v PVE namoutíme přes tlačítko cloud-init CDROMku.
3.1.1 Deploy hotového Ubuntu image
Deploy hotového image je snadný a my jen přejmeme materiál z dokumentace na ukázku. Přihlásíme se na náš PVE a postupujeme takto:
# Stažení cloud image Ubuntu
wget https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64.img
# Tvorba nového VM v PVE
qm create 900 --memory 2048 --net0 virtio,bridge=vmbrX
# import staženého disku na daný storage v PVE
qm importdisk 900 bionic-server-cloudimg-amd64.img nazevPole
# finally apřiřazení a nastavení disku v PVE
qm set 900 --scsihw virtio-scsi-pci --scsi0 storage:vm-900-disk-1.raw
# fA přiřazení nastavení disku v PVE k danému stroji
qm set 999 --scsihw virtio-scsi-pci --scsi0 storage:vm-999-disk-1.raw
# Přiřadíme CloudInit CDROM
qm set 999 --ide2 local-lvm:cloudinit
#Umožníme bootování přímo z CI image
qm set 999 --boot c --bootdisk scsi0
# Můžeme ale také nemusíme nakonfigurovat seriovou konzoli
qm set 999 --serial0 socket --vga serial0
# Ztemplatujeme stroj
qm template 999
Template lze pak snadno naklonovat a přidat mu doplňkové konfigurace
qm clone 999 123 --name Neco
# Přidání IP, SSH klíče
qm set 123 --sshkey ~/.ssh/id_rsa-ansible.pub
qm set 123 --ipconfig0 ip=1.1.1.2/24,gw=1.1.1.1
Z takto utvořeného template získáme panenský stroj. Je o minimální velikosti (do 3GB) a předchystán pro práci. Má by default jen jednu partition (buď sda nebo vda).
Stroj v defaultním nastavení má také DHCP-klienta na ethernetovém portu. Tady je ukázka, jak vypadá /etc/network/interfaces
V podstatě je tam jediná direktiva a to na posledním řádku, pokud stroji chceme přidělit statickou IP z CI, stačí zakomentovat info o ethernetových rozhraních a jejich dhcp-klientech.
root@127connectica:/etc/network# cat interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
# The loopback network interface
auto lo
iface lo inet loopback
# The normal eth0
allow-hotplug eth0
iface eth0 inet dhcp
#
## Additional interfaces, just in case we're using
## multiple networks
allow-hotplug eth1
iface eth1 inet dhcp
#
allow-hotplug eth2
iface eth2 inet dhcp
# Set this one last, so that cloud-init or user can
# override defaults.
source /etc/network/interfaces.d/*
Zde je ukázka obsahu v /etc/network/interfaces.d/50-cloud-init
root@127connecica1:/etc/network/interfaces.d# cat 50-cloud-init
# This file is generated from information provided by the datasource. Changes
# to it will not persist across an instance reboot. To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
auto lo
iface lo inet loopback
dns-nameservers 2.2.2.2 8.8.8.8
dns-search cnnc.local
auto eth0
iface eth0 inet static
address 1.1.1.1.2/24
gateway 1.1.1.1
Mnohem zajímavější je defaultní konfigurace grubu v /etc/default/grub
root@127connectica1:~# cat /etc/default/grub
# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.
# For full documentation of the options in this file, see:
# info -f grub -n 'Simple configuration'
GRUB_DEFAULT=0
GRUB_TIMEOUT=0
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="nosplash text biosdevname=0 net.ifnames=0 console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0 systemd.show_status=true "
GRUB_CMDLINE_LINUX=""
# Uncomment to enable BadRAM filtering, modify to suit your needs
# This works with Linux (no patch required) and with any kernel that obtains
# the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...)
#GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef"
# Uncomment to disable graphical terminal (grub-pc only)
#GRUB_TERMINAL=console
# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'
#GRUB_GFXMODE=640x480
# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
#GRUB_DISABLE_LINUX_UUID=true
# Uncomment to disable generation of recovery mode menu entries
#GRUB_DISABLE_RECOVERY="true"
# Uncomment to get a beep at grub start
#GRUB_INIT_TUNE="480 440 1"
# openstack-debian-images disables OS prober to avoid
# loopback detection which breaks booting
GRUB_DISABLE_OS_PROBER=true
To je přímo žádoucí si změnit orchestrací.
3.1.2 Tvorba vlastního CI na Debian 10
Provedeme čistou instalaci Debianu a nainstalujeme pouze jednu hlavní partition (volba use entire disk) o velikosti 5 GB. Utvoříme root usera s libovolným heslem. Heslo později přepíšeme cloud-initem.
Swap můžeme, ale nemusíme konfigurovat. Swap můžeme později nakonfigurovat pomocí modulu mounts v CI později. Pro jednoduchost swap klidně už nyní nastavte.
Po instalaci Debian provedeme následující sumu opatření:
- Volitelné: Nainstalujeme si naše základních balíčky pro práci (sysstat, htop, mc, zabbix-agent, vim, nano)
- Provedeme editaci a úprava GRUBu, aby se síťovky jmenovali po staru
- Odstraníme všechny usery kromě root usera
- Nainstalujeme cloud-init podporu
- Smažeme a a pročištíme logů, odmažeme tempy, smažeme historii a smažeme klíče v
/etc/ssh/
Pojdme si to spolem projet bod po bodu.
3.1.2.1 Aktualizace a upgrade
apt update
apt-upgrade
apt dist-upgrade
3.1.2.2 Instalace oblíbených balíčků
Můžeme si je nainstalovat manuálně:
apt install htop mc sysstat vim nano qemu-guest-agent
Nebo provedeme editaci CI configu takto
package_upgrade: true
packages:
- htop
- mc
- sysstat
- vim
- nano
- qemu-guest-agent
3.1.2.3 Editace GRUB
Provedeme editaci GRUBu
vim /etc/default/grub
GRUB_DEFAULT=0
GRUB_TIMEOUT=0
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet"
GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0"
# update grubu
update-grub
3.1.2.4 Odstraníme všechny users krom roota
v image necháme pouze root usera. root userovi je doporučeno zakázat přihlášení přes heslo v /etc/ssh
nebo
userdel -r NazevUseraZInstalace
3.1.2.5 Nainstalujeme cloud-init podporu
apt install cloud-init
CI je velmi obecný, proto nakonfiguruje CI tak, že zakomentujeme to, co považujeme za nepodstatné. Podrobněji o modulech najdete v dokumentaci CIhttps://cloudinit.readthedocs.io/en/latest/topics/modules.html?highlight=fan
Pokud nechcete procházet bod po bodu co jsou jednotlivé moduly, zde Vám mohu dát tip, co bych doporučil zakomentovat pro začátek.
# - disable-ec2-metadata
# - byobu
# - fan
# - puppet
# - chef
# - salt-minion
# - mcollective
Zde je example CI config souboru
vim /etc/cloud/cloud.cfg
# The top level settings are used as module
# and system configuration.
# A set of users which may be applied and/or used by various modules
# when a 'default' entry is found it will reference the 'default_user'
# from the distro configuration specified below
users:
- default
# If this is set, 'root' will not be able to ssh in and they
# will get a message to login instead as the above $user (debian)
disable_root: true
# This will cause the set+update hostname module to not operate (if true)
preserve_hostname: false
# This preverts apt/sources.list to be updated at boot time, which
# may be annoying.
apt_preserve_sources_list: true
# Example datasource config
# datasource:
# Ec2:
# metadata_urls: [ 'blah.com' ]
# timeout: 5 # (defaults to 50 seconds)
# max_wait: 10 # (defaults to 120 seconds)
# The modules that run in the 'init' stage
cloud_init_modules:
- migrator
- seed_random
- bootcmd
- write-files
- growpart
- resizefs
- disk_setup
- mounts
- set_hostname
- update_hostname
- update_etc_hosts
- ca-certs
- rsyslog
- users-groups
- ssh
# The modules that run in the 'config' stage
cloud_config_modules:
# Emit the cloud config ready event
# this can be used by upstart jobs for 'start on cloud-config'.
- emit_upstart
- ssh-import-id
- locale
- set-passwords
- grub-dpkg
- apt-pipelining
- apt-configure
- ntp
- timezone
# - disable-ec2-metadata
- runcmd
# - byobu
# The modules that run in the 'final' stage
cloud_final_modules:
- package-update-upgrade-install
#- fan
#- puppet
#- chef
#- salt-minion
#- mcollective
- rightscale_userdata
- scripts-vendor
- scripts-per-once
- scripts-per-boot
- scripts-per-instance
- scripts-user
- ssh-authkey-fingerprints
- keys-to-console
- phone-home
- final-message
- power-state-change
# System and/or distro specific settings
# (not accessible to handlers/transforms)
system_info:
# This will affect which distro class gets used
distro: debian
# Default user name + that default users groups (if added/used)
default_user:
name: ansible
lock_passwd: True
gecos: Debian
groups: [adm, audio, cdrom, dialout, dip, floppy, netdev, plugdev, sudo, video]
sudo: ["ALL=(ALL) NOPASSWD:ALL"]
shell: /bin/zsh
# Other config here will be given to the distro class and/or path classes
paths:
cloud_dir: /var/lib/cloud/
templates_dir: /etc/cloud/templates/
upstart_dir: /etc/init/
package_mirrors:
- arches: [default]
failsafe:
primary: http://deb.debian.org/debian
security: http://security.debian.org/
ssh_svcname: ssh
Problematika CI skriptování je velmi rozsáhlá a dále se modifikací parametrů nebudeme v tomto článku zabývat. Pro naše iniciální spuštění nám to zatím stačí.
Jen zmíníme, že konfigurace
- scripts-per-once
- scripts-per-boot
slouží k tomu, abychom po rebootu buď spustili nějaký skript jednorázově, nebo pokaždé. Skript stačí uložit do adresáře
/var/lib/cloud/scripts
➜ scripts tree
.
├── per-boot
├── per-instance
├── per-once
└── vendor
Proč bychom to chtěli mít? Třeba proto, že v nainstalovaném zabbix-agentovi se konfiguruje dost špatně proměnná hostname v jeho konfiguračním souboru /etc/zabbix/zabbix-agent.conf
jinak než post-ex přes Ansible. Jednoduše si doplňkové skripty představme jako kdyby byly v cronu a spouštěli se po rebootu a to buď jednorázově, nebo pokaždé dle naší potřeby.
3.1.2.6 Provedeme editaci GRUBu
Abychom docílili toho, že síťovky se budou jmenovat dle konvence eth0, eth1…, musíme do GRUB zadat parametr "net.ifnames=0 biosdevname=0"
# Editace GRUB souboru
vim /etc/default/grub
GRUB_DEFAULT=0
GRUB_TIMEOUT=0
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet"
GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0"
# Provedeme update grub
update-grub
3.1.2.7 Pročištění stroje
Pročístíme logy, tempy, historii a další nepořádky.
# Odmázneme co se napsalo do logů
rm /var/log/*.log.*
rm /var/log/apt/*.*
cat /dev/null > /var/log/btmp
cat /dev/null > /var/log/dmesg
/bin/cat /dev/null > /var/log/lastlog
/bin/cat /dev/null > /var/log/syslog
# Odmázneme tempy
rm –rf /tmp/*
rm –rf /var/tmp/*
# Odmázneme SSH klíče
rm –f /etc/ssh/*key*
# Pročistíme apt
apt-get autoremove
apt-get autoclean
apt-get clean
# Odmázneme BASH history
rm -f ~root/.bash_history
# Smázne unset HISTFILEme historii
history -c
Ještě než si řekneme hotovo, upozorníme na existenci machine-id. Toto je unikátní ID stroje, které slouží k:
- Tvorbě DHCP host identifikátoru
- GNOME si ukládá nějaké sessiny pomocí tohoto ID
- Systemd-boot EFI bootloader si ukládá instalační adresáře kernelu pojmenovaných pomocí machine-id.
Machine-id nás nebude trápit, pokud strojům přiřazujeme statické adresy, což je u serverů žádoucí. Pokud ale byste měli potřebu DHCP-klienta pro přidělování adres nebo měli speciálně Ubuntu, je potřeba na to myslet a nechat u image prázdné adresáře pro machine-id.
/etc/machine-id
/var/lib/dbus/machine-id
# a udělat symlink
ln -s /etc/machine-id /var/lib/dbus/machine-id
Image máme hotov. Je to mnohem hezčí, než si stáhnout hotový image. Takto lépe pochopíme problematiku CI, Nyní stroj vypneme, uděláme z něj template a jdeme nastavit cloud-init v PVE pro danou VM. Pro naši jednoduchost example ID naší mašiny bude 100 a náš disk se bude jmenovat ssd.
# Přidáme Cloud-init
qm set 100 --ide2 ssd:cloudinit
update VM 100: -ide2 ssd:cloudinit
Formatting '/mnt/pve/ssd/images/100/vm-100-cloudinit.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off preallocation=metadata compression_type=zlib size=4194304 lazy_refcounts=off refcount_bits=16
# Nastavíme, aby VM bootoval primárně ze své hlavní partition a ne z cloud-initu
qm set 100 --boot c --bootdisk scsi0
# Z mašiny si uděláme Template
qm template 100
k takto vytočenému template přidělíme mu:
- ip adresu
- ssh klíč pro autorizaci
- Usera pod kterým se budeme přihlašovat
qm set 100 --sshkey ~/.ssh/id_rsa.pub
qm set 100 --ipconfig0 ip=1.2.3.4/24,gw=1.1.1.1
qm set 100 --ciuser root
ciuser může být libovolný, nemusí to být root. Když zvolíte libovolného usera jiného než root, na mašinu se by default nepřihlásíte pod root userem ale jako sudo pod novým userem. Když ale jako ciuser zvolíte root, na mašinu se dostanete jen jako root.
Závěr
Tímto čtením jste získali nezbytné minimum pro práci s CI. Problematika je rozsáhlá a možnosti modifikací jsou mnohem hlubší, než jak jsme si zde uvedli. Pro základní práci jsou aktuální informace více než dostatečně. Budete-li potřebovat hlubší znalosti, doporučujeme začít studiem online dokumentace https://cloudinit.readthedocs.io/en/latest/