Зачем IaC
Infrastructure as Code (IaC) -- практика описания облачной инфраструктуры в текстовых файлах вместо ручного создания ресурсов через веб-консоль.
Проблемы ручного управления
| Проблема | Последствие |
|---|---|
| Нет документации | "Кто создал этот бакет и зачем?" |
| Невоспроизводимость | Невозможно точно воссоздать окружение |
| Дрифт | Реальность отличается от документации |
| Человеческие ошибки | Забыли настроить шифрование |
| Нет ревью | Изменения без проверки коллегами |
Преимущества IaC
- Воспроизводимость -- одна команда создаёт всю инфраструктуру
- Версионирование -- Git хранит историю всех изменений
- Ревью -- Pull Request для изменений инфраструктуры
- Автоматизация -- CI/CD для инфраструктуры
- Документация -- код = документация
AWS CloudFormation / SAM
CloudFormation для CRC
# template.yaml (SAM template)
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Cloud Resume Challenge Infrastructure
Globals:
Function:
Runtime: python3.12
Architectures: [arm64]
Timeout: 10
MemorySize: 128
Resources:
# DynamoDB Table
VisitorCounterTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: visitor-counter
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
# Lambda Function
VisitorCounterFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: visitor-counter
CodeUri: backend/
Handler: lambda_function.lambda_handler
Policies:
- DynamoDBCrudPolicy:
TableName: !Ref VisitorCounterTable
Events:
GetCount:
Type: HttpApi
Properties:
Path: /count
Method: GET
ApiId: !Ref CrcApi
# HTTP API
CrcApi:
Type: AWS::Serverless::HttpApi
Properties:
StageName: prod
CorsConfiguration:
AllowOrigins:
- https://resume.ivanpetrov.com
AllowMethods:
- GET
- OPTIONS
# S3 Bucket for Frontend
FrontendBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: ivan-petrov-resume
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
# CloudFront Distribution
CdnDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
DefaultRootObject: index.html
Enabled: true
Origins:
- Id: S3Origin
DomainName: !GetAtt FrontendBucket.RegionalDomainName
S3OriginConfig:
OriginAccessIdentity: ''
OriginAccessControlId: !Ref OAC
DefaultCacheBehavior:
TargetOriginId: S3Origin
ViewerProtocolPolicy: redirect-to-https
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6
OAC:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Name: crc-oac
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
Outputs:
ApiUrl:
Description: API endpoint URL
Value: !Sub 'https://${CrcApi}.execute-api.${AWS::Region}.amazonaws.com/prod/count'
CloudFrontUrl:
Description: CloudFront distribution URL
Value: !GetAtt CdnDistribution.DomainName
Деплой SAM
# Build
sam build
# Deploy (guided -- запросит параметры)
sam deploy --guided
# Обновление
sam deploy
AWS CDK
CDK позволяет описывать инфраструктуру на языках программирования:
# cdk/app.py
from aws_cdk import (
Stack, App, Duration,
aws_dynamodb as dynamodb,
aws_lambda as _lambda,
aws_apigatewayv2 as apigw,
aws_s3 as s3,
aws_cloudfront as cloudfront,
)
from constructs import Construct
class CrcStack(Stack):
def __init__(self, scope: Construct, id: str, **kwargs):
super().__init__(scope, id, **kwargs)
# DynamoDB
table = dynamodb.Table(self, 'VisitorCounter',
table_name='visitor-counter',
partition_key=dynamodb.Attribute(
name='id', type=dynamodb.AttributeType.STRING
),
billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST
)
# Lambda
fn = _lambda.Function(self, 'CounterFunction',
runtime=_lambda.Runtime.PYTHON_3_12,
handler='lambda_function.lambda_handler',
code=_lambda.Code.from_asset('backend/'),
architecture=_lambda.Architecture.ARM_64,
timeout=Duration.seconds(10),
memory_size=128
)
table.grant_read_write_data(fn)
app = App()
CrcStack(app, 'CrcStack')
app.synth()
Azure Bicep
// main.bicep
param location string = resourceGroup().location
param functionAppName string = 'crc-visitor-counter'
// Storage Account for Function App
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' = {
name: 'crcfuncstorage'
location: location
sku: { name: 'Standard_LRS' }
kind: 'StorageV2'
}
// Cosmos DB
resource cosmosAccount 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' = {
name: 'crc-cosmos'
location: location
properties: {
databaseAccountOfferType: 'Standard'
capabilities: [{ name: 'EnableServerless' }]
locations: [{ locationName: location }]
}
}
// App Service Plan (Consumption)
resource appServicePlan 'Microsoft.Web/serverfarms@2023-01-01' = {
name: 'crc-plan'
location: location
sku: { name: 'Y1', tier: 'Dynamic' }
kind: 'functionapp'
}
// Function App
resource functionApp 'Microsoft.Web/sites@2023-01-01' = {
name: functionAppName
location: location
kind: 'functionapp,linux'
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
pythonVersion: '3.11'
appSettings: [
{ name: 'COSMOS_CONNECTION', value: cosmosAccount.listConnectionStrings().connectionStrings[0].connectionString }
{ name: 'FUNCTIONS_WORKER_RUNTIME', value: 'python' }
]
}
}
}
# Деплой Bicep
az deployment group create \
--resource-group crc-resources \
--template-file main.bicep
Terraform (мультиклауд)
# main.tf - Terraform для AWS CRC
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
# DynamoDB
resource "aws_dynamodb_table" "visitor_counter" {
name = "visitor-counter"
billing_mode = "PAY_PER_REQUEST"
hash_key = "id"
attribute {
name = "id"
type = "S"
}
}
# Lambda
resource "aws_lambda_function" "counter" {
filename = "function.zip"
function_name = "visitor-counter"
role = aws_iam_role.lambda_role.arn
handler = "lambda_function.lambda_handler"
runtime = "python3.12"
architectures = ["arm64"]
timeout = 10
memory_size = 128
source_code_hash = filebase64sha256("function.zip")
}
# S3 Bucket
resource "aws_s3_bucket" "frontend" {
bucket = "ivan-petrov-resume"
}
# Terraform workflow
terraform init # Initialize providers
terraform plan # Preview changes
terraform apply # Apply changes
terraform destroy # Delete everything
Сравнение инструментов IaC
| Параметр | CloudFormation/SAM | CDK | Bicep | Terraform |
|---|---|---|---|---|
| Формат | YAML/JSON | Python/TS/Java | DSL | HCL |
| Облако | AWS only | AWS only | Azure only | Мультиклауд |
| State | Управляемый AWS | Управляемый AWS | Azure | Файл/Backend |
| Drift detection | Да | Через CFn | Через Azure | terraform plan |
| Rollback | Автоматический | Через CFn | Ручной | terraform destroy |
| Обучение | Среднее | Лёгкое (если знаете язык) | Лёгкое | Среднее |
| Сообщество | Большое | Растущее | Растущее | Очень большое |
Рекомендация для CRC
- Если делаете только AWS: SAM (самый простой для serverless)
- Если хотите мультиклауд: Terraform
- Если Azure: Bicep
- Если любите Python: CDK