Info
Content

cloud-init

Cloud-init - это индустриальный кросс-платформенный мульти-дистрибутивный стандарт для инициализации инстансов
Он поддерживается во всех крупных cloud-провайдерах, в системах провижининга для приватных инфраструктур и на bare-metal

При загрузке инстанса cloud-init понимает в каком облаке он запущен, читает предоставленную метадату и инициализирует систему соответствующим образом
Он может сетапить сеть, девайсы, ssh-ключи и много всего другого

Getting Started

Tutorial

Для обучения и тестирования cloud-init скриптов удобно использовать lxd (там из коробки хорошая поддержка cloud-init)

Вот такой терраформ манифест создает подходящую виртуалку

terraform {
  required_providers {
    yandex = {
      source = "yandex-cloud/yandex"
    }
  }
}

provider "yandex" {
  token     = "AQAAAAAayaoeuWVmM00"
  cloud_id  = "b1gaeounndt"
  folder_id = "b1gaaoeuobf5v"
  zone      = "ru-central1-c"
}

data "yandex_compute_image" "compute_image_search" {
  family = "ubuntu-2004-lts"
}

resource "yandex_compute_instance" "test" {
  platform_id = "standard-v1"
  zone        = "ru-central1-a"

  resources {
    cores         = 4
    core_fraction = 20
    memory        = 4
  }

  boot_disk {
    initialize_params {
      image_id = "${data.yandex_compute_image.compute_image_search.image_id}"
      size     = 30
    }
  }

  network_interface {
    subnet_id = "${yandex_vpc_subnet.test_network_subnet.id}"
    nat       = true
  }
  metadata = {
    ssh-keys = "ubuntu:${file("~/.ssh/id_rsa.pub")}"
  }
}

resource "yandex_vpc_network" "test_network" {}

resource "yandex_vpc_subnet" "test_network_subnet" {
  zone           = "ru-central1-a"
  network_id     = "${yandex_vpc_network.test_network.id}"
  v4_cidr_blocks = ["10.2.0.0/16"]
}

Далее заходим на нее, и налаживаем lxd

root@fhmkp99o5k8l3iultpf3:~# apt install snapd
root@fhmkp99o5k8l3iultpf3:~# snap install lxd
root@fhmkp99o5k8l3iultpf3:~# lxd init --minimal

Далее подготавливаем cloud-init конфиг

root@fhmkp99o5k8l3iultpf3:~# cat <<EOF > /tmp/user-data
> #cloud-config
> runcmd:
>   - echo 'Hello, World!' > /var/tmp/hello-world.txt
> EOF

Запускаем контейнер с этим конфигом

root@fhmkp99o5k8l3iultpf3:~# lxc launch ubuntu:focal my-test --config=user.user-data="$(cat /tmp/user-data)"

Идем внутрь и проверяем как оно там отработало

root@fhmkp99o5k8l3iultpf3:~# lxc shell my-test

root@my-test:~# cloud-init status -l
status: done
time: Wed, 10 Aug 2022 11:11:58 +0000
detail:
DataSourceNoCloud [seed=/var/lib/cloud/seed/nocloud-net][dsmode=net]

root@my-test:~# cloud-init query userdata
#cloud-config
runcmd:
  - echo 'Hello, World!' > /var/tmp/hello-world.txt

root@my-test:~# cloud-init schema --system --annotate
Valid cloud-config: system userdata

root@my-test:~# cat /var/tmp/hello-world.txt
Hello, World!

Сносим этот контейнер

root@fhmkp99o5k8l3iultpf3:~# lxc stop my-test
root@fhmkp99o5k8l3iultpf3:~# lxc rm my-test

Boot Stages

При загрузке из под systemd у cloud-init есть пять стадий:

  • Generator - systemd generator (так и не понял что это за зверь) включает в автозагрузку cloud-init.target. Cloud-init можно выключить если создать файл /etc/cloud/cloud-init.disabled или если передать аргумент при загрузке ядра cloud-init=disabled
  • Local - сервис cloud-init-local.service. Цель локальной стадии - найти локальные источники данных и настроить сеть
  • Network - cloud-init.service, запускается после local stage и настроенной сети, запускает disk_setup и mounts модули
  • Config - cloud-config.service, запускает конфигурационные модули
  • Final - cloud-final.service, эта стадия запускается в последнюю очередь. Занимается установкой пакетов, применением configuration management плагинов (ansible, puppet, etc), и запуском пользовательских скриптов

Cloud-init понимает запускается он впервые на новом инстансе или нет, в зависимости от этого применяется соответсвующая конфигурация
При первой загрузке применяется вся per-instance конфигурация, а при повторной загрузке применяются per-boot конфиги

При запуске cloud-init оставляет кэш который хранит внутреннее состояние и используется между загрузками

Соответственно если кэш присутствует, значит cloud-init уже запускался на этой системе
Это могло случится если система была перезагружена или если файловая система была приаттачена к новому инстансу и фактически это первая загрузка системы но кэш в файловой системе уже присутствует (такое бывает когда инстанс запускается из образа созданного из уже запровижененной машины)
По умолчанию cloud-init пытается понять что за кейс у него сейчас, для этого он проверяет instance id из кэша и сравнивает с id который определяется окружением, если разные то это первая загрузка. Внутри это поведение называется check
Instance ID находится в /var/lib/cloud:

root@fhmkp99o5k8l3iultpf3:~# cat /var/lib/cloud/data/instance-id
fhmkp99o5k8l3iultpf3

Возможны ситуации когда это поведение нужно изменить, это измененное поведение называется trust и заставляет cloud-init безусловно доверять найденной в кеше инфе

Управлять этим можно через опцию manual_cache_clean:

  • false -> check
  • true -> trust

Можно вручную снести кэш через cloud-init clean
Эта команда сносит все из /var/lib/cloud

root@fhmkp99o5k8l3iultpf3:~# tree /var/lib/cloud/ | wc -l
78
root@fhmkp99o5k8l3iultpf3:~# cloud-init clean
root@fhmkp99o5k8l3iultpf3:~# tree /var/lib/cloud/ | wc -l
4

CLI Interface

Актуальный список подкомманд доступен в хелпе cloud-init --help

  • analyze - анализ длительности загрузки (связано с systemd-analyze)
  • clean - чистит артифакты из /var/lib/cloud, так же с соответствующими ключами может почистить логи, удалить instance id файл и ребутнуть машину после удаления артифактов
  • collect-logs - собирает логи и всякую инфу и закладывает это в tar-архив
    root@fhmkp99o5k8l3iultpf3:~# cloud-init collect-logs
    Wrote /root/cloud-init.tar.gz
    
    root@fhmkp99o5k8l3iultpf3:~# tar --list -f cloud-init.tar.gz
    cloud-init-logs-2022-08-11/
    cloud-init-logs-2022-08-11/cloud-init.log
    cloud-init-logs-2022-08-11/dmesg.txt
    cloud-init-logs-2022-08-11/journal.txt
    cloud-init-logs-2022-08-11/dpkg-version
    cloud-init-logs-2022-08-11/run/
    cloud-init-logs-2022-08-11/run/cloud-init/
    cloud-init-logs-2022-08-11/run/cloud-init/cloud.cfg
    cloud-init-logs-2022-08-11/run/cloud-init/instance-data-sensitive.json
    cloud-init-logs-2022-08-11/run/cloud-init/instance-data.json
    cloud-init-logs-2022-08-11/run/cloud-init/.instance-id
    cloud-init-logs-2022-08-11/run/cloud-init/.ds-identify.result
    cloud-init-logs-2022-08-11/run/cloud-init/ds-identify.log
    cloud-init-logs-2022-08-11/run/cloud-init/enabled
    cloud-init-logs-2022-08-11/run/cloud-init/cloud-init-generator.log
    cloud-init-logs-2022-08-11/run/cloud-init/sem/
    cloud-init-logs-2022-08-11/run/cloud-init/sem/apply_network_config.once
    cloud-init-logs-2022-08-11/run/cloud-init/result.json
    cloud-init-logs-2022-08-11/run/cloud-init/cloud-id
    cloud-init-logs-2022-08-11/run/cloud-init/cloud-id-ec2
    cloud-init-logs-2022-08-11/run/cloud-init/status.json
    cloud-init-logs-2022-08-11/cloud-init-output.log
    cloud-init-logs-2022-08-11/version
    
  • devel - набор подкоманд которые сейчас находятся в разбработке, они будут вынесены в top-level когда станут стабильными
  • features - принтит фичи (хз что это)
  • init - налаживает стадии загрузки
  • modules - запускает модули, по умолчанию при запуске от ОС запускет только config и final стадии
  • query - инструмент для доступа к закешированной информации собранной при загрузке системы (/run/cloud-init/instance-data.json)
  • schema - валидирует cloud-config файлы
  • single - запускает один указанный модуль (а не стейдж как обычно)
  • status - статус выполнения

User Data

No Comments
Back to top