Перейти до вмісту

Обчислення

Віртуальна машина є найстарішою хмарною послугою, і решта сервісів або працює на ній, або скопійована з неї. Рішень при цьому кілька: з якого сімейства взяти інстанс, чи годиться для задачі ARM, як машина налаштовує себе під час першого запуску і що станеться, коли провайдер забере її серед ночі.

Три факти визначають відповіді. Інстанс на 2 vCPU коштує від $0.07 до $0.10 за годину залежно від процесора й провайдера. Його spot-варіант у Azure на 79% дешевший, але провайдер може забрати машину за 30 секунд. А кожна машина має локальну адресу 169.254.169.254, за якою будь-який процес на ній читає метадані, зокрема тимчасові ключі доступу.

Передумови. Регіони й зони доступності (модуль 1), акаунти й бюджети (модуль 2), ролі й тимчасові облікові дані (модуль 3). Гіпервізор і віртуальні машини розібрано в курсі ОС.

Інстанс (instance) є віртуальною машиною, яку гіпервізор провайдера запускає на фізичному сервері: ви отримуєте кількість vCPU, обсяг пам’яті, мережевий інтерфейс із заявленою пропускною здатністю і диски. У AWS гіпервізором є Nitro з розвантаженням мережі й дисків на окремі карти, в Azure Hyper-V, в GCP KVM. Як це працює, розібрано в курсі ОС, тут воно вважається відомим.

Слово vCPU потребує уточнення. На x86 vCPU зазвичай є апаратним потоком: два vCPU можуть ділити одне фізичне ядро (SMT). На ARM-процесорах AWS Graviton і Azure Cobalt SMT немає, vCPU відповідає цілому ядру (для Cobalt 100 це прямо написано в документації Azure). Тому порівнювати «2 vCPU» на x86 і на ARM за ціною напряму не можна, продуктивність міряють на власному навантаженні.

На одному фізичному сервері живуть інстанси різних клієнтів. Гіпервізор ізолює їх, але кеші процесора й пропускна здатність пам’яті спільні. Через це той самий тип показує різну затримку в різні дні, а для чутливих навантажень існують виділені хости (dedicated host) за окрему плату.

Назва типу кодує призначення. Розібравши її, ви бачите характеристики без довідника.

Провайдер Приклад Як читати
AWS m7g.large m сімейство (general purpose), 7 покоління, g процесор Graviton, large розмір
Azure Standard_D2ps_v6 D сімейство, 2 vCPU, p ARM, s підтримка Premium SSD, v6 версія
GCP c4a-standard-2 c4a серія (C4 на Axion), standard співвідношення пам’яті до vCPU, 2 vCPU

Сімейства розрізняються співвідношенням ресурсів. Загальні (general purpose) дають близько 4 ГіБ пам’яті на vCPU і підходять для веб-серверів, невеликих баз даних, більшості застосунків. Оптимізовані під обчислення дають 2 ГіБ на vCPU і вищу частоту. Оптимізовані під пам’ять дають 8 ГіБ і більше на vCPU для кешів і баз в пам’яті. Оптимізовані під сховище мають швидкі локальні NVMe-диски. Окрема гілка — прискорювачі (GPU), яким присвячено модуль 14.

Призначення AWS Azure GCP
Загальне M, T (burstable) D, B (burstable) N, E, C4
Обчислення C F C2, H3
Пам’ять R, X E, M M
Сховище I, D L Z3
Burstable T B E2 (спільні ядра)

Burstable-інстанси (T, B) мають базовий рівень процесора нижче за 100% і накопичують кредити, коли простоюють. Вони дешеві й підходять для сервісів, що більшість часу майже нічого не роблять. Якщо ж кредити закінчуються, процесор урізається до базового рівня; в AWS режим unlimited дозволяє продовжити за додаткову плату. GCP має гнучкість, якої немає в інших: власні типи машин (custom machine types), де кількість vCPU і обсяг пам’яті задаються окремо.

Кожен провайдер розробив власний ARM-процесор: AWS Graviton (суфікс g в m7g, m8g), Azure Cobalt 100 (серія Dpsv6; раніше Azure пропонував Ampere Altra в Dpsv5) і Google Axion (серія C4A). Власний процесор дає провайдерові контроль над ціною й енергоспоживанням, а клієнтові часто знижку, але не однакову: за цінами з розділу «Скільки це коштує» ARM-варіант дешевший на 19% в AWS, на 27% в Azure і лише на 8% в GCP. Покоління процесорів у цих порівняннях різні, тож точну різницю дає лише вимір власного навантаження.

Щоб перейти на ARM, потрібні три речі. Образ ОС має бути зібраний під arm64. Контейнерні образи мають бути мультиархітектурними (наприклад, docker buildx build --platform linux/amd64,linux/arm64, докладніше в модулі 8). Нативні залежності (бібліотеки на C, wheel-пакети Python, бінарники Node) мають існувати під arm64. Java, Go і Python без нативних розширень зазвичай переносяться без змін.

Образ (image) містить диск з ОС і встановленим ПЗ, з якого створюється інстанс. У AWS він називається AMI (Amazon Machine Image), в Azure це образ із Marketplace або з Azure Compute Gallery, в GCP образ у проєкті з родинами образів (image family). Публічні образи дають провайдер і дистрибутиви (Amazon Linux, Ubuntu від Canonical), власний золотий образ (golden image) збирають інструментом на кшталт Packer: ставлять залежності, агенти моніторингу й застосунок, фіксують результат.

Навіщо це, видно під час автомасштабування. Якщо машина після старту п’ять хвилин ставить пакети, нова потужність з’являється через п’ять хвилин. Образ із усім уже встановленим стартує за десятки секунд. Заразом інфраструктура стає незмінною (immutable): машину не лагодять, а замінюють новою з нового образу. Снапшот диска зберігає стан одного диска, образ додає до нього метадані для запуску машин; диски розібрано в модулі 6 і в модулі 14 курсу ОС.

Машина з образу ще не знає, як її звати, яку конфігурацію взяти й кому дозволити вхід по SSH. cloud-init входить у більшість образів Linux, на першому запуску читає дані від провайдера (user data) і застосовує їх: створює користувачів, кладе ключі, ставить пакети, пише файли, виконує команди. Формат буває декларативним (файл #cloud-config у YAML) або скриптом з #!/bin/bash. За замовчуванням user data виконується лише один раз за життя інстанса.

Що варто знати наперед:

  • Логи лежать у /var/log/cloud-init-output.log; cloud-init status --wait блокує, доки налаштування не завершиться. Це перше, що дивляться, якщо машина «піднялася, але нічого не працює».
  • Помилка в скрипті не зупиняє машину: вона вважається створеною до завершення cloud-init, тож готовність перевіряйте health check.
  • Секрети в user data класти не можна. Їх бачить кожен, хто читає метадані машини, і кожен із правом описати інстанс через API. Секрети машина бере зі сховища секретів за своєю роллю.
  • Розмір обмежений (в EC2 16 КБ): довгі скрипти лежать в об’єктному сховищі, а в user data лишається завантажувач.

GCP має власний механізм поряд із cloud-init: ключ метаданих startup-script виконується гостьовим агентом на кожному старті. На образах Ubuntu працює й cloud-init через ключ user-data. Azure приймає custom_data і передає його cloud-init.

Процесу на машині потрібно дізнатися про себе: ідентифікатор інстанса, зону, мережеві налаштування, теги, а головне тимчасові облікові дані ролі, під якою машина працює (модуль 3). Для цього кожна хмара віддає машині HTTP-сервіс на локальній адресі 169.254.169.254, доступний лише зсередини машини (запит до цієї адреси не виходить за межі хоста).

Механізм у трьох провайдерів однаковий, різняться лише обов’язкові заголовки.

Terminal window
# IMDSv2: спершу токен, потім запит із токеном
TOKEN=$(curl -s -X PUT http://169.254.169.254/latest/api/token \
-H 'X-aws-ec2-metadata-token-ttl-seconds: 300')
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/instance-id

Той самий сервіс віддає й токени доступу. В AWS це шлях …/meta-data/iam/security-credentials/<роль>, в Azure /metadata/identity/oauth2/token для керованої ідентичності, в GCP …/instance/service-accounts/default/token. Саме цю можливість використовує SDK, коли ви не задаєте ключів явно.

Перша версія сервісу метаданих EC2 (IMDSv1) відповідала на будь-який простий GET. Якщо застосунок на машині можна змусити зробити HTTP-запит за адресою, яку вказав зловмисник, ця вразливість називається SSRF (server-side request forgery), і зловмисник отримує тимчасові ключі ролі машини.

IMDSv2 вимагає двох кроків. Спершу PUT-запит на /latest/api/token із заголовком X-aws-ec2-metadata-token-ttl-seconds (від 1 секунди до 6 годин) повертає токен, потім усі GET передають його в заголовку X-aws-ec2-metadata-token. Захист складається з кількох дрібних перепон, які разом відсікають типові SSRF:

  • Вразливі місця в застосунках найчастіше дозволяють лише GET і рідко дозволяють довільні заголовки, а тут потрібен PUT із власним заголовком.
  • Відповідь на PUT за замовчуванням має обмеження hop limit = 1 на рівні IP: пакет із токеном не проходить далі за саму машину, тож контейнер у власній мережі або зворотний проксі його не побачить.
  • PUT-запити з заголовком X-Forwarded-For сервіс відхиляє, тобто запит, який прийшов через проксі, не проходить.
Три сценарії звернення до сервісу метаданих EC2: SSRF проти IMDSv1 отримує ключі ролі, SSRF проти IMDSv2 отримує відмову 401, власний код на інстансі спершу створює токенIMDSv1SSRF-запит через застосунок169.254.169.254сервіс метаданихGET …/iam/security-credentials/роль200: AccessKeyId, SecretAccessKey, TokenIMDSv2, той самий SSRFSSRF-запит через застосунок169.254.169.254сервіс метаданихGET без токена401: токена немає, відповіді немаєIMDSv2, власний код на інстансіSDK або curl на інстансі169.254.169.254сервіс метаданих1) PUT /latest/api/token 2) GET з токеном200: дані метаданих
Той самий SSRF-запит проти IMDSv1 віддає ключі, проти IMDSv2 закінчується відповіддю 401. Свій код на інстансі проходить обидва кроки без проблем.

Вимагати IMDSv2 можна на трьох рівнях. Для інстанса це параметр http_tokens = "required". Для образу це властивість imds-support = v2.0 (Amazon Linux 2023 вже задає її, тому нові інстанси на ньому вимагають IMDSv2). Для регіону акаунта це значення за замовчуванням, яке задається командою aws ec2 modify-instance-metadata-defaults --http-tokens required.

Що бувало без цього захисту, показано в розборі нижче; інцидент Capital One докладно розглянуто в модулі 12.

Провайдери мають вільну потужність, яку не купили за звичайною ціною. Її вони продають зі знижкою, зберігаючи право забрати машину назад. Це spot-інстанс: в AWS Spot Instance, в Azure Azure Spot VM, в GCP Spot VM (попередник preemptible VM мав ліміт 24 години, у Spot його немає).

Знижка суттєва. Для Azure D2s_v5 Linux в eastus поточна spot-ціна $0.020266 проти $0.096 on-demand, це мінус 79%. GCP заявляє знижки до 91% відносно on-demand для багатьох типів машин; AWS заявляє до 90%. Ціни spot змінюються залежно від попиту й від типу машини та зони, тож будь-яке фіксоване число тут орієнтир.

Перерваного інстанса ви не отримаєте безкоштовно назад: провайдер надсилає сигнал, чекає й зупиняє машину. Скільки чекає, залежить від хмари.

Часова шкала переривання spot-ВМ: в AWS 120 секунд між сповіщенням і зупинкою, в Azure 30 секунд, в GCP 30 секундAWSсповіщення про переривання: 120 сAzureподія Preempt: до 30 сGCPACPI G2: до 30 с0 с30 с60 с90 с120 ссигналзупинка (AWS)
AWS дає на реакцію 120 секунд, Azure і GCP по 30. Код, що коректно завершується за 30 секунд, встигне й у AWS; навпаки не працює.
AWS Azure GCP
Час до зупинки 2 хвилини до 30 секунд до 30 секунд (типово)
Як приходить сигнал метадані spot/instance-action; подія EventBridge Scheduled Events, подія Preempt ключ метаданих preempted = TRUE і ACPI G2 soft off
Що станеться потім terminate, stop або hibernate Deallocate (типово) або Delete STOP (типово) або DELETE

AWS до того ж надсилає rebalance recommendation, коли потужність у пулі стає дефіцитною, раніше за 2-хвилинне сповіщення і без гарантії. В Azure машину виселяють і через ціну: для неї задають максимальну ціну, а -1 означає «не вище за ціну звичайної машини». GCP у режимі Preview дозволяє збільшити повідомлення до 120 секунд.

Реагувати на сигнал доводиться самому. Нижче мінімальний цикл, який перевіряє його; в AWS документація радить опитувати кожні 5 секунд.

Terminal window
TOKEN=$(curl -s -X PUT http://169.254.169.254/latest/api/token \
-H 'X-aws-ec2-metadata-token-ttl-seconds: 21600')
while true; do
code=$(curl -s -o /dev/null -w '%{http_code}' \
-H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/spot/instance-action)
[ "$code" = 200 ] && { echo 'переривання за 2 хвилини'; break; }
sleep 5
done

Зупинка за 30 секунд залишає мало. Тому spot підходить для навантажень, які переносять втрату машини: пакетна обробка, CI-агенти, рендеринг, безстанові вузли за балансувальником. Для бази даних або єдиного інстанса застосунку він не годиться. Основні прийоми: зберігати стан поза машиною (черга, об’єктне сховище), вміти продовжити роботу з контрольної точки, і розподіляти потужність по кількох типах інстансів і зонах, щоб один дефіцитний пул не забрав усе.

Групи автомасштабування

Section titled “Групи автомасштабування”

Одна машина не витримує ні збою, ні піку. Група автомасштабування (autoscaling group) тримає задану кількість однакових інстансів, замінює зламані й додає чи прибирає машини за метрикою.

AWS Azure GCP
Група Auto Scaling group (ASG) Virtual Machine Scale Set (VMSS), режим Flexible Managed Instance Group (MIG), зональна або регіональна
Шаблон launch template модель scale set instance template
Spot у групі mixed instances policy priority = "Spot", priority_mix шаблон із provisioning_model = SPOT

Скрізь однакові три поняття. Мінімум, максимум і бажана кількість (min / max / desired) задають межі. Перевірка стану (health check) вирішує, що інстанс зламався, і група замінює його новим із шаблону. Політика найчастіше є відстеженням цілі (target tracking): «тримай середнє завантаження процесора на 50%», далі група сама рахує, скільки машин додати.

Швидкість реакції обмежена часом старту: метрика збирається хвилину, потім машина створюється, завантажується ОС, виконується cloud-init, застосунок прогрівається. Через це група часто «встигає» вже наприкінці різкого піку. Відомий заздалегідь пік краще закладати розкладом, а старт скорочувати золотим образом. Група в кількох зонах доступності дає базову відмовостійкість: коли зона недоступна, інстанси створюються в решті (модуль 13).

Функція AWS Azure GCP
Віртуальна машина EC2 Azure Virtual Machines Compute Engine
ARM-процесор Graviton (g) Cobalt 100 (ps, pds) Axion (C4A)
Образ AMI Marketplace / Compute Gallery image / image family
Налаштування при старті user data (cloud-init) custom_data (cloud-init) startup-script, user-data
Сервіс метаданих IMDS, v2 із токеном IMDS, заголовок Metadata:true metadata server, Metadata-Flavor
Дешева переривана Spot Instance (2 хв) Spot VM (30 с) Spot VM (30 с)
Група Auto Scaling group VM Scale Set Managed Instance Group

Чим це відрізняється і що з цього випливає. В AWS і GCP зупинений інстанс не коштує за обчислення, лише за диски й адреси. В Azure вимкнення зсередини ОС залишає машину виділеною, і за неї платять повністю, поки ви не виконаєте deallocate (докладніше нижче). Захист метаданих у AWS залежить від вашого налаштування (http_tokens), а в Azure і GCP основний захист (Metadata:true, Metadata-Flavor) уже вбудований і не вимикається. Час до зупинки spot у 4 рази різний: скрипт завершення, написаний під AWS, ляже на 30 секундах Azure чи GCP.

Приклади нижче створюють одну ARM-машину, яка встановлює nginx через cloud-init. В AWS вона вимагає IMDSv2.

data "aws_ssm_parameter" "al2023_arm" {
name = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64"
}
resource "aws_instance" "web" {
ami = data.aws_ssm_parameter.al2023_arm.value
instance_type = "t4g.small"
user_data = <<-EOT
#cloud-config
packages:
- nginx
runcmd:
- systemctl enable --now nginx
EOT
user_data_replace_on_change = true
metadata_options {
http_endpoint = "enabled"
http_tokens = "required"
http_put_response_hop_limit = 1
}
tags = {
Name = "web"
}
}

Cloud-init працює однаково: packages ставить nginx, runcmd вмикає службу. Перед запуском на Azure перевірте назву образа для ARM, командою az vm image list --architecture Arm64 --publisher Canonical --offer ubuntu-24_04-lts --all -o table; для GCP тип диска hyperdisk-balanced потрібен для машин C4A.

Тепер група автомасштабування з spot-потужністю. В AWS базова частина береться on-demand, решта spot із кількох типів. В Azure це scale set у режимі Flexible з priority_mix. В GCP регіональна група з автоскейлером на шаблоні зі Spot.

variable "subnet_ids" {
type = list(string)
}
data "aws_ssm_parameter" "al2023_arm" {
name = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64"
}
resource "aws_launch_template" "web" {
name_prefix = "web-"
image_id = data.aws_ssm_parameter.al2023_arm.value
instance_type = "m7g.large"
metadata_options {
http_tokens = "required"
http_put_response_hop_limit = 1
}
}
resource "aws_autoscaling_group" "web" {
name = "web"
min_size = 2
max_size = 10
vpc_zone_identifier = var.subnet_ids
capacity_rebalance = true
mixed_instances_policy {
instances_distribution {
on_demand_base_capacity = 1
on_demand_percentage_above_base_capacity = 0
spot_allocation_strategy = "price-capacity-optimized"
}
launch_template {
launch_template_specification {
launch_template_id = aws_launch_template.web.id
version = "$Latest"
}
override {
instance_type = "m7g.large"
}
override {
instance_type = "m8g.large"
}
override {
instance_type = "m6g.large"
}
}
}
}
resource "aws_autoscaling_policy" "cpu" {
name = "cpu-50"
autoscaling_group_name = aws_autoscaling_group.web.name
policy_type = "TargetTrackingScaling"
target_tracking_configuration {
predefined_metric_specification {
predefined_metric_type = "ASGAverageCPUUtilization"
}
target_value = 50
}
}

В Azure правила масштабування задаються окремим ресурсом azurerm_monitor_autoscale_setting, у якому потрібні два правила: на збільшення й на зменшення кількості машин. AWS і GCP роблять це самі: target tracking і autoscaler тримають ціль в обидва боки.

Ціни на 2 vCPU і 8 ГіБ пам’яті, Linux, on-demand, американські долари за годину й за місяць у 730 годин. Станом на вересень 2026, з офіційних сторінок цін провайдерів (Amazon EC2 On-Demand Pricing, Azure Retail Prices API, Compute Engine pricing). Регіони: us-east-1, eastus, us-central1.

Тип За годину За місяць (730 год)
AWS x86 m7i.large $0.1008 $73.58
AWS ARM m7g.large $0.0816 $59.57
Azure x86 Standard_D2s_v5 $0.096 $70.08
Azure ARM Standard_D2ps_v6 $0.0702 $51.25
GCP x86 n2-standard-2 $0.097118 $70.90
GCP ARM c4a-standard-2 $0.0898 $65.55

Spot: Azure Standard_D2s_v5 коштує $0.020266 за годину (−79%). Для GCP на сторінці Spot VMs поточна ціна n2-standard-2 становить $0.058256 за годину . Для AWS spot-ціну не наводжу: вона змінюється залежно від зони й моменту, її дивляться в Spot Instance Advisor і в історії цін.

У цю суму не входить кілька позицій, які легко забути.

  • Диск. Завантажувальний диск оплачується окремо й у всіх трьох продовжує коштувати, поки машина зупинена.
  • Публічна IPv4-адреса. В AWS і Azure вона коштує $0.005 за годину (близько $3.65 на місяць) на кожну адресу, навіть без трафіку.
  • Вихідний трафік. Розглянуто в модулі 5.
  • Зупинена, але не звільнена машина в Azure. Якщо вимкнути її зсередини ОС, статус буде Stopped, а compute-ресурси лишаються закріпленими, тож оплата триває. Лише статус Stopped (deallocated) знімає плату за обчислення.

Білінг посекундний, з мінімумом 60 секунд в EC2 і в GCP . Знижки за зобов’язання (Savings Plans, Reserved Instances, committed use discounts) і порівняння моделей оплати розглядає модуль 13.

Розбір: один запит до 169.254.169.254

Section titled “Розбір: один запит до 169.254.169.254”

Ця адреса стала ключовою деталлю інциденту Capital One 2019 року: неправильно налаштований вебзастосунковий файрвол (WAF) на EC2-інстансі дозволяв зловмиснику змусити його виконати HTTP-запит за довільною адресою. Повну хронологію, масштаб і наслідки розібрано в модулі 12, а тут показано лише механізм, який робить такий запит небезпечним.

  1. Зловмисник змушує WAF відправити GET на http://169.254.169.254/latest/meta-data/iam/security-credentials/. Це SSRF: запит іде не від зловмисника, а зсередини машини.
  2. IMDSv1 відповідає на простий GET і повертає ім’я ролі, а другим запитом ключі цієї ролі: AccessKeyId, SecretAccessKey і Token.
  3. Роль машини має права на сервіси AWS. Що вона може, те зловмисник і робить зі своєї машини, поки ключі не втратять чинність.

Проти IMDSv2 перший крок закінчується відповіддю 401: вразливий застосунок шле простий GET без токена, а токен створюється PUT-запитом із власним заголовком. Це закриває лише один шлях. Зловмисник із кодом, що виконується всередині машини, отримає токен і ключі так само, як власний застосунок. Тому додатково потрібні ролі з найменшими привілеями (модуль 3), а решта захисних шарів описана в модулі 12.

Типові помилки розуміння

Section titled “Типові помилки розуміння”

«vCPU — це ядро». На x86 це найчастіше апаратний потік, два vCPU можуть ділити одне ядро. На ARM-процесорах Graviton і Cobalt vCPU відповідає ядру. Порівнювати типи за кількістю vCPU без вимірювання не можна.

«Spot — це безкоштовна знижка». Плата за знижку — переривання. Без зберігання стану поза машиною й реакції на сигнал вона обернеться втратою роботи.

«IMDSv2 захищає від усього». Він закриває SSRF із простим GET. Код, що виконується на машині, метадані читає в будь-якому разі; його обмежують правами ролі.

«Зупинена машина нічого не коштує». Диск і публічна адреса лишаються в рахунку у всіх трьох хмарах, а в Azure зупинка без deallocate залишає й плату за обчислення.

Перевір себе

1. Вебзастосунок на EC2 має вразливість SSRF: він робить GET за довільною адресою. Інстанс налаштований з http_tokens = required. Що отримає зловмисник за адресою http://169.254.169.254/latest/meta-data/iam/security-credentials/?
2. Ваш скрипт коректного завершення встигає зберегти стан за 45 секунд. Де він працюватиме без втрат на spot-інстансах?
3. Ви зупинили Azure VM командою shutdown зсередини ОС. Статус — Stopped. Що з рахунком?
4. Що обмежує швидкість реакції групи автомасштабування на різкий пік, якщо метрики й правила налаштовано правильно?
5. Команда переносить сервіс на ARM і виявляє, що збірка нативної бібліотеки Python під arm64 відсутня. Що з цього випливає?
6. Що визначає, чи можна класти пароль до бази даних у user data машини?
7. Група з 20 spot-інстансів одного типу в одній зоні втратила всі машини за хвилину. Яка зміна конфігурації найбільше знижує ризик повторення?