DevOps з AWS CDK та майбутнє «інфраструктури як коду»
Мене звати Мозговий Микола, Ex-Sigma Software, наразі старший інженер Bolt. У недалекому минулому щільно працював з Azure та IoT, проте, протягом останнього року доводиться більше взаємодіяти з AWS.
У цій статті я хочу передати свій досвід користування особливою технологією, яка, на мою думку, визначає майбутнє «інфраструктури як коду» в цілому, а саме AWS CDK.
Окрім мого звіту ви також отримаєте зразок застосунку, який зможете використати як шаблон до власних проєктів.
По суті, AWS CDK дозволяє кодувати вашу інфраструктуру використовуючи мову програмування загального призначення за вибором. Наразі підтримуються наступні мови: C#, F#, Go, Java, Python, JavaScript, TypeScript.
TLDR: зразок застосунку з інструкцією щодо його використання можна знайти за посиланням.
Передісторія
Наша зустріч з AWS CDK була випадковою. Необхідно було розробити відносно простий MVP, невеликою командою з
Проєкт мав використовувати AWS, у той час як мій попередній досвід був в основному пов’язаний з Azure, тому використання більш-менш знайомих ARM- шаблонів або Azure CLI не було можливим. Крім того, ніхто з команди не мав досвіду роботи ні з Terraform, ні з CloudFormation.
AWS CDK виявився вдалою знахідкою. Мені, без перебільшення, вистачило двох днів, щоб розібратись з принципом його роботи та перевірити можливість його застосування для реалізації проєкту.
Оригінальний проєкт сам по собі та його функції неважливі до теми статті, тому в якості зразка ми будемо використовувати дуже просту веб-версію добре знайомої гри Snake.
Зразок архітектури
Архітектура, зображена нижче, досить точно представляє ресурси, що були використані для нашого реального проєкту (зображення 1):
Зображення 1. Цільова архітектура
Ключові особливості:
- Це безсерверна архітектура: відсутні зарезервовані обчислювальні потужності та відсутні витрати «наперед».
- Amazon API Gateway служить єдиною точкою входу до застосунку.
- Сховище S3 використовується для розміщення статичного вебсайту та медіа-контенту (у нашому випадку самої гри).
- AWS Lambda використовується як середовище виконання для API.
- Dynamo DB зберігає стан системи (у даному випадку це рахунок у грі).
- Заради простоти прикладу я маю оминути інтеграцію з Cognito, що в реальному рішенні була використана для ідентифікації користувачів.
Згідно зі схемою вище, репозиторій містить три проєкти:
/aws-snake
/snake-API # node/express API
/snake-client # безпосередньо гра на звичайному JavaScript
/snake-iac # проєкт AWS CDK
Оригінальний комерційний проєкт побудований на . NET Core, але для поточного зразка я використовую TypeScript з трьох причин:
- TypeScript виглядає чимось середнім між Java/C# і JavaScript.
- JavaScript-подібний синтаксис розуміють майже повсюдно.
- Щоб довести собі, що CDK справді працює незалежно від обраної мови програмування.
Початок роботи з CDK
Старт роботи з AWS CKD доволі простий, ви можете або слідувати офіційним інструкціям з початку роботи, або виконати вказані нижче кроки:
- Створити обліковий запис AWS.
- Створити ключ доступу AWS.
- Встановити AWS CLI.
- Сконфігурувати AWS CLI, використовуючи попередньо створений ключ
aws configure
- Встановити Node LTS.
brew install node # mac sudo apt-get install nodejs # debian
- Встановити AWS CDK toolkit.
npm install -g aws-cdk
- Встановити цільове середовище виконання (у нашому випадку TypeScript)
.
npm install -g typescript
- Cтворити пустий CDK проєкт.
mkdir test-iac cd test-iac cdk init app --language typescript
- Ознайомитись з CDK командами.
cdk list # Список усіх стеків у програмі cdk synthesize # Синтезує та друкує шаблон CloudFormation для поточного стеку cdk bootstrap # Розгортання стека інструментів CDK у середовищі AWS cdk diff # Порівнює локальний стек із розгорнутим стеком та друкує різницю cdk deploy # Розгортання стека в обліковому записі AWS cdk destroy # Знищити розгорнутий стек
curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"
sudo installer -pkg AWSCLIV2.pkg -target /
Ось і все! Тепер ви знаєте всі необхідні команди CDK. Хоча здебільшого ви будете використовувати лише дві: cdk diff
та cdk deploy
.
Налаштування стека
Стек CloudFormation — це колекція ресурсів AWS керованих як одне ціле, що налаштовується як шаблон JSON або YAML (див. як це працює).
По суті, AWS CDK надає обгортку над стеком CloudFormation, що дозволяє створити його, використовуючи мову програмування загального призначення.
cdk init app
створює порожній стек з відповідним файлом програмного коду, що залежить від цільової мови. В нашому випадку це lib/snake-iac-stack.ts
(див. коміт 37d8d7d)
import * as cdk from '@aws-cdk/core'; export class SnakeIacStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // The code that defines your stack goes here } }
Додавання нового ресурсу до стека — це просто створення нового екземпляру класу, наприклад, щоб створити S3 сховище для хостингу нашої JavaScript гри ми просто додаємо наступні рядки (див. коміт 93ceebe):
// The code that defines your stack goes here // Snake Web Client const snakeClient = new s3.Bucket(this, nameIt("website-s3"), { bucketName: nameIt("website-s3"), versioned: false, publicReadAccess: true, websiteIndexDocument: "index.html", removalPolicy: cdk.RemovalPolicy.DESTROY // remove on stack destruction });
Зверніть увагу, що дуже важливо встановити загальну конвенцію іменування для всіх ресурсів, наприклад: <environment>-<project>-<resource>
. Для цього ми використовуємо наступну допоміжну функцію:
const envName = 'test'; const nameIt = (name: string) => `${envName}-snake-${name}`.toLowerCase();
Сполучення ресурсів
Суттєвою особливістю CDK є можливість логічно зв’язувати ресурси разом, використовуючи їх як залежності. Наприклад, ми можемо встановити налаштований вище s3 як маршрут за замовчуванням (точку входу) до нашого веб-застосунку (див. коміт 59b58dc):
// API Gateway const snakeClientIntegration = new integration.HttpProxyIntegration( { method: gate.HttpMethod.GET, url: snakeClientBucket.bucketWebsiteUrl, }); const httpApi = new gate.HttpApi(this, nameIt("Api-GateWay"), { apiName: nameIt("Api-GateWay"), defaultIntegration: snakeClientIntegration, });
Далі ми можемо встановити маршрути API таким же чином (див. коміт 8f6e9e1):
const apiGateway = new gate.HttpApi(this, nameIt("Api-GateWay"), { // ... // }); // Snake API const apiLambda = new lambda.Function(this, nameIt("api-lambda"), { // ... // }); const snakeApiIntegration = new integration.LambdaProxyIntegration({ handler: apiLambda, // api integration }); apiGateway.addRoutes({ // api route path: "/api/{proxy+}", methods: [gate.HttpMethod.ANY], integration: snakeApiIntegration }); apiGateway.addRoutes({ // swagger route path: "/swagger/{proxy+}", methods: [gate.HttpMethod.GET], integration: snakeApiIntegration });
Те саме стосується управління контролем доступу, надання доступу до бази даних для API компоненту (див. коміт b20df0a):
// Persistence layer const table = new dynamodb.Table(this, nameIt('DynamoDb-Table'), { // ... // }); table.grantReadWriteData(apiLambda); // give api access to dynamo DB table
Для завершеного зразка конфігурації стека зверніться до репозиторію проєкту.
Перегляд стеку
По-перше, ви можете знайти стеки CloudFormation у веб-консолі AWS (зображення 2):
Зображення 2. Стеки CloudFormation у консолі AWS
По-друге, той самий перелік стеків можна отримати, виконавши наступну команду у терміналі:
aws cloudformation list-stacks
Обробка дрейфу конфігурації
На жаль, це слабке місце як AWS CDK так і CloudFormation, оскільки виявлення та обробка дрейфу конфігурації наразі відсутні «out of the box» (див. відкрите питання).
Обробка дрейфу конфігурації можлива, проте не тривіальна (див. статтю).
Тому я б запропонував почати з запобігання можливості внесення несанкціонованих змін до конфігурації (див. офіційний посібник).
В ідеалі, всі зміни до інфраструктури повинні вноситися програмно, від імені окремого облікового запису, що використовується винятково CDK застосунком.
Цей підхід також може бути автоматизований (див. відкрите питання).
CI/CD
AWS CDK може бути легко інтегрований в процедури безперервного доставлення (continuous delivery). Для цього зразка використовуються GitHub Actions, тоді як для оригінального проєкту ми використали Azure DevOps, відмінності не суттєві.
Зразок конфігурації CI/CD складається з двох важливих частин:
- Скрипт для компіляції пакетів, що будуть розгорнуті (
./build.sh
); - Налаштування GitHub Workflow у вигляді YAML файлу, що описує доставлення до декількох середовищ (test, prod) з підтвердженням адміністратора (
./.github/workflows/ci-cd.yml
).
Отриманий результат доставлення відображено нижче (зображення 3):
Зображення 3. Результат доставлення GitHub Workflow
Зверніться до інструкції з CI/CD у Readme.MD для налаштування власноруч.
Висновок
На мою думку, AWS CDK створив прецедент для DevOps практики майбутнього, а поточна розробка Terraform CDK доводить існування широкої зацікавленості у використанні мов загального призначення для реалізації «інфраструктури як коду».
Цей підхід робить дисципліну безперервного доставлення доступнішою, дозволяє розробникам бути залученими до підтримки інфраструктури, а також використати існуючі інструменти контролю якості як то статичний аналіз, або навіть модульні тести.
Наостанок, я припускаю, що деякі читачі будуть заперечувати ідею використання мови загального призначення для кодування інфраструктури. Оскільки це питання виходить за межі цієї статті, я маю обмежитися посиланнями (один, два) на відповідні дискусії в Reddit, що містять доволі доречні аргументи за і проти.
41 коментар
Додати коментар Підписатись на коментаріВідписатись від коментарів