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

Ви увійшли як

Вхід у Curious Dev Learn

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

Модуль 0030 хв

Чому нуль ClickOps

Чому вся інфраструктура в цьому курсі живе в git як Pulumi на C#, і як влаштовані курс та його лаби.

Перш ніж ви напишете хоч рядок коду, я хочу пояснити одне правило, яке визначає кожен модуль цього курсу: ви ніколи не створюєте й не змінюєте інфраструктуру кліками в консолі Google Cloud. Цей урок про те, чому так, що ми використовуємо натомість і як влаштований сам курс.

ClickOps це ручне налаштування інфраструктури через вебконсоль. Відкриваєте консоль, шукаєте потрібну сторінку, заповнюєте форму, тиснете «Create». Це найшвидший спосіб уперше щось запустити, і консоль справді добре з цим справляється. Саме в цьому й пастка.

Ось історія, яка може здатися вам знайомою. Невелика команда робить сервіс для виставлення рахунків. Одна інженерка, назвімо її Дана, за пів дня налаштовує хмарний проєкт: контейнерний сервіс, реєстр, базу даних, пару секретів і сервіс-акаунт з роллю «Editor», бо деплой постійно падав з помилками доступу. Усе працює. Всі займаються своїми справами далі.

Через вісім місяців команді потрібне staging-середовище. Ніхто не пам’ятає, які з 40 налаштувань на сторінці сервісу Дана змінила відносно дефолтних. Дана вже звільнилася. Хтось робить скриншоти кожної сторінки продакшну і вручну відтворює все в другому проєкті. Це займає два дні, і результат однаково відрізняється: на staging новіший runtime, інший ліміт пам’яті та секрет, який вказує на продакшн-базу. Коли staging уперше поводиться інакше, ніж продакшн, ніхто не може сказати, чи винен код, чи середовище.

Потім фінвідділ питає, звідки в рахунку зайві 140 доларів на місяць. З’ясовується, що десь висить забута VM після експерименту, load balancer для сервісу, якого вже немає, і бакет на 900 GB зі старими образами. Ніхто не знає, чи щось із цього ще потрібне, тож ніхто й не наважується видаляти.

Для всього цього не знадобився поганий інженер. Знадобилася лише консоль.

П’ять цін ручного налаштування

Section titled “П’ять цін ручного налаштування”

У цій історії п’ять окремих проблем. Їх варто назвати, бо всі вони вирішуються однією практикою.

  1. Неможливо повторити. Сесія в консолі не залишає рецепта. Ви не можете вдруге запустити «те, що зробила Дана», чи то для другого середовища, другого регіону чи навчань із disaster recovery.
  2. Неможливо зробити рев’ю. Зміна в консолі стає живою в ту мить, коли ви тиснете кнопку. Ніхто не читає її заздалегідь. У коді застосунку ви б ніколи не прийняли «я запушив одразу в продакшн, повір».
  3. Немає історії. Cloud Audit Logs фіксують, що налаштування змінилося і хто його змінив, але не чому, а читати їх означає займатися археологією. Git log з посиланням на pull request є історією, якою людина може скористатися.
  4. Дрейф між середовищами. Два середовища, зібрані вручну, розходяться з першого дня і продовжують розходитися. Кожен баг «на staging працює», який виявляється різницею в конфігурації, і є дрейфом.
  5. Неможливо чисто видалити. Якщо у вас немає списку того, що ви створили, ви не можете прибрати все. Забуті ресурси працюють і далі, і далі виставляють рахунки. Для курсу на кшталт цього, де ви створюватимете й знищуватимете ресурси в кожному модулі, саме ця ціна б’є по вашій власній картці.

Кожен ресурс у цьому курсі описаний у коді, лежить у git і змінюється через pull request. Конкретно:

  • Уся інфраструктура є програмою Pulumi на C# у теці infra/ вашого репозиторію.
  • Зміни ви застосовуєте командою pulumi up (з ноутбука в модулях 1-5, із Cloud Build починаючи з модуля 6).
  • Консоль лише для читання. Ви використовуєте її, щоб дивитися: логи, метрики, список ревізій, сторінку IAM, щоб переконатися, що зробив ваш код. Змінювати через неї нічого не можна.
  • Якщо ви ось-ось натиснете «Create» чи «Edit», зупиніться і напишіть код. Якщо все ж натиснули, видаліть те, що наклікали, і зробіть це заново в коді. Зараз це дешевше, ніж через вісім місяців.

Виграш у тому, що весь ваш проєкт відтворюється однією командою. Видаліть проєкт, створіть новий, запустіть bootstrap-скрипт і pulumi up, і ви там само, де були. Так само ви прибиратимете після кожної лаби.

Є кілька хороших інструментів для інфраструктури як коду. Я обрав для цього курсу Pulumi з C# з причин, що стосуються саме вас як .NET-розробника:

  • Одна мова для застосунку та інфраструктури. C# ви вже знаєте. Сервіс Cloud Run, його сервіс-акаунт і його секрети є C#-об’єктами в проєкті, який лежить поруч з вашим API в тому самому solution.
  • Типи та IntelliSense. Назви властивостей, обов’язкові поля та значення enum перевіряє компілятор. Помилка в назві регіону все одно проявиться лише під час виконання, але помилка в назві властивості дає червоне підкреслення, а не зламаний деплой.
  • Справжні інструменти для коду. Цикли, функції, класи, NuGet-пакети, рефакторинг в IDE і юніт-тести на xUnit для ваших описів інфраструктури. Коли три сервіси мають однакові налаштування безпеки, ви пишете метод, а не копіюєте.
  • Відтворюваність однією командою. pulumi up обчислює різницю між вашим кодом і тим, що вже існує, показує preview і застосовує лише цю різницю. pulumi destroy видаляє все, чим володіє stack.

State Pulumi (запис про те, які реальні ресурси належать вашій програмі) житиме в бакеті Cloud Storage у вашому власному проєкті, а його секрети шифруватимуться ключем Cloud KMS, яким володієте ви. Жоден сторонній сервіс нічого вашого не зберігає. Обидва ці елементи ви налаштуєте в наступному уроці.

Якщо пошукати вакансії за запитом «infrastructure as code», більшість згадуватиме Terraform, а деякі тепер і OpenTofu, open-source форк, що з’явився після того, як HashiCorp у 2023 році перевела Terraform на Business Source License. Pulumi поширений, але не домінує. Я не хочу, щоб після цього курсу ви не могли читати інструмент, яким користується більшість команд.

Тому кожен фрагмент інфраструктури в цьому курсі має вкладку Terraform поруч із Pulumi. Основний шлях, лаби та пояснення побудовані на Pulumi; вкладка Terraform показує ті самі ресурси в HCL, щоб ви могли зіставити одне з іншим. Здебільшого це майже дослівний переклад, бо провайдер Pulumi для Google Cloud генерується з того самого upstream-коду провайдера, який використовує Terraform, і назви ресурсів та властивостей дуже близькі.

Pulumi Terraform / OpenTofu
Мова C#, TypeScript, Python, Go, Java, YAML HCL, декларативна мова конфігурації
Логіка Повноцінна мова: цикли, функції, класи, тести count, for_each, модулі, вирази; обмежено свідомо
State За замовчуванням Pulumi Cloud або власний бекенд (GCS, S3, Azure Blob, локально) За замовчуванням локально або бекенд (GCS, S3, HCP Terraform та інші)
Екосистема Провайдер Google Cloud покриває ті самі ресурси, що й у Terraform; менше модулів від спільноти Найбільший реєстр провайдерів і модулів; більшість прикладів в інтернеті на HCL
Найм Шукають у деяких командах, часто в .NET- чи TypeScript-компаніях Згадується в більшості IaC-вакансій
Ліцензія Apache 2.0 Terraform: BSL 1.1. OpenTofu: MPL 2.0

Мій чесний підсумок: головна сила Terraform у його повсюдності, а головна слабкість у тому, що HCL не є мовою програмування, і ви це відчуєте того дня, коли знадобиться справжня логіка чи тести. Головна сила Pulumi полягає у вашій мові та ваших інструментах, а слабкість у меншій спільноті й меншій кількості прикладів для copy-paste. Концепції (ресурси, state, plan, apply, дрейф) переносяться повністю. Якщо ви пройдете цей курс на Pulumi, то за тиждень зможете читати й писати Terraform.

«Нуль ClickOps» є правилом, але є два місця, де ручного кроку не уникнути. Я краще назву їх, ніж удаватиму, що їх немає.

1. Bootstrap (модуль 0). Pulumi потрібне місце для зберігання state і ключ для шифрування секретів, перш ніж він зможе чимось керувати, а ще хтось має прив’язати білінг до проєкту та увімкнути API. Це проблема курки та яйця: інструменту, який створює інфраструктуру, потрібна інфраструктура, що вже існує. Ми розв’язуємо її коротким bash-скриптом scripts/bootstrap.sh, який один раз виконує команди gcloud. Це прийнятно, бо це скрипт у git: його можна відрев’юїти, повторити і безпечно запустити двічі. І це все одно не клік у консолі.

2. Встановлення GitHub app (модуль 6). Щоб Cloud Build міг читати ваш репозиторій на GitHub, GitHub вимагає, щоб людина встановила GitHub app Google Cloud Build і підтвердила доступ у браузері. Така модель безпеки GitHub, і вона хороша: жоден API не повинен мати змоги видати доступ до репозиторію від вашого імені без вас. Усе навколо цього (підключення, прив’язка репозиторію, тригер) робиться в Pulumi.

Це повний список. Якщо в якомусь із наступних уроків вас попросять клікнути щось інше, вважайте це багом курсу і скажіть мені.

Курс складається з модуля 0 (цей урок і налаштування), шести модулів з навичками та фінального проєкту. Кожен модуль з навичками має однакову структуру.

Спершу лог інциденту. Кожен модуль починається з короткого логу реалістичного збою: ревізія, яка не стартує, образ на 900 MB, що працює від root, витік ключа. Логи вигадані, але кожен із цих збоїв я чи хтось, з ким я працював, бачили наживо. Далі модуль дає знання, потрібні, щоб пояснити й виправити проблему. Ви вивчаєте інструмент, бо він вам потрібен, а не тому, що він наступний у документації.

Застосунок, що проходить через увесь курс. Ви деплоїтимете Sniplink, невеликий скорочувач URL на мінімальних API ASP.NET Core. Він навмисно тримає дані в пам’яті, бо персистентність є темою наступного курсу, а не цього. У фінальному проєкті ви з порожньої папки, без покрокових інструкцій, збудуєте другий сервіс: Dayquote.

Лаби, які перевіряються за URL. Кожен модуль закінчується лабою. Ви деплоїте у свій проєкт Google Cloud, вставляєте URL свого сервісу на сторінці лаби, і платформа перевіряє ваш сервіс ззовні. Доступ до вашого проєкту їй ніколи не потрібен. Сервіс доводить, що він справді працює на Cloud Run у вашому проєкті, повертаючи ID-токен, підписаний Google, який платформа валідує за публічними ключами Google.

LabKit. Endpoint-и для перевірки дає невеликий open-source NuGet-пакет CuriousDev.LabKit. Ви додаєте два рядки в Program.cs, і він мапить кілька endpoint-ів /_lab/*. LabKit дотримується одного правила: він автоматизує обв’язку, яка однакова для всіх і якій лаба не навчає, і ніколи не реалізує навичку, що перевіряється. Він отримує для вас ID-токен; він не читає ваш секрет, не пише ваші health check-и і не налаштовує ваш сервіс. Це ваша робота. Endpoint-и LabKit ніколи не повертають секрети чи змінні середовища, лише докази, наприклад HMAC над випадковим nonce.

Деякі перевірки самозвітні: сервіс повідомляє платформі, що працює від non-root користувача, і платформі доводиться повірити йому на слово. Якщо перевірка самозвітна, урок про це каже і пояснює, що знадобилося б для суворішої перевірки.

Сертифікат. Пройдіть лаби модулів з 1 по 7, і отримаєте сертифікат «Containerizing & Deploying .NET on Google Cloud». На старті це рівень Completed: кожна перевірка зовнішня, через ваш URL. Суворіший рівень Verified з’явиться пізніше. Він необов’язковий і вимагатиме надати платформі вузький доступ лише на читання до ізольованого курсового проєкту, щоб вона могла перевірити те, чого не видно через URL, наприклад розмір образу та IAM-прив’язки. Щоб завершити курс, він вам ніколи не знадобиться, але це ще одна причина завести для курсу окремий новий проєкт. Саме про це вас і попросить наступний урок.

  • ClickOps коштує вам повторюваності, рев’ю, історії, паритету середовищ і чистого видалення, а останнє з’являється у вашому рахунку.
  • У цьому курсі кожен ресурс описано як Pulumi на C# у git і він змінюється через pull request, а консоль лише для читання.
  • Pulumi на C# дає одну мову, перевірки компілятора і справжні тести для інфраструктури; Terraform отримує вкладку в кожному модулі, бо ним користується ринок праці.
  • Є рівно два ручні винятки: bootstrap-скрипт і встановлення GitHub app, і обидва свідомі.
  • Кожен модуль іде за схемою інцидент, виправлення, лаба; лаби перевіряються ззовні через ваш URL за допомогою LabKit, який бере на себе обв’язку і ніколи не бере саму навичку.