Przejdź do głównej zawartości

Wzorce infrastruktury jako kod

Opanuj infrastrukturę jako kod z Cursor i Claude Code. Ten przewodnik obejmuje moduły Terraform, szablony CloudFormation, programy Pulumi, playbooki Ansible, przepływy pracy GitOps i produkcyjne wzorce IaC z asystą AI.

  1. Zainicjalizuj projekt IaC

    Okno terminala
    # Wygeneruj konfigurację IaC
    Agent: "Create infrastructure setup with:
    - Terraform modules for AWS
    - State management with S3
    - Environment separation
    - Security best practices
    - Cost optimization"
  2. Zainstaluj serwery MCP dla IaC (opcjonalnie)

    Okno terminala
    # AWS
    claude mcp add aws -- docker run -e AWS_ACCESS_KEY_ID=... ghcr.io/aws/mcp-server
    # Azure (brak endpointu URL - użyj pakietu npm)
    claude mcp add azure -- npx -y @azure/mcp@latest
    # Kubernetes
    claude mcp add k8s -- npx -y kubernetes-mcp-server
  3. Skonfiguruj reguły AI

    # .cursorrules lub CLAUDE.md
    IaC best practices:
    - Use remote state management
    - Implement proper tagging
    - Follow least privilege principle
    - Use modules for reusability
    - Version control everything
    - Test infrastructure changes
    - Document all resources
# AI Prompt
Agent: "Create Terraform module structure for:
- VPC with public/private subnets
- EKS cluster with node groups
- RDS with read replicas
- Application load balancer
- Security groups and IAM"
# modules/vpc/main.tf
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
locals {
common_tags = merge(
var.tags,
{
Module = "vpc"
ManagedBy = "terraform"
Environment = var.environment
LastModified = timestamp()
}
)
max_subnet_length = max(
length(var.private_subnets),
length(var.public_subnets),
length(var.database_subnets)
)
nat_gateway_count = var.single_nat_gateway ? 1 : var.one_nat_gateway_per_az ? length(var.azs) : local.max_subnet_length
}
# VPC
resource "aws_vpc" "this" {
cidr_block = var.cidr
enable_dns_hostnames = var.enable_dns_hostnames
enable_dns_support = var.enable_dns_support
tags = merge(
local.common_tags,
{
Name = format("%s-vpc", var.name)
}
)
}
# Internet Gateway
resource "aws_internet_gateway" "this" {
count = length(var.public_subnets) > 0 ? 1 : 0
vpc_id = aws_vpc.this.id
tags = merge(
local.common_tags,
{
Name = format("%s-igw", var.name)
}
)
}
# Public Subnets
resource "aws_subnet" "public" {
count = length(var.public_subnets)
vpc_id = aws_vpc.this.id
cidr_block = element(var.public_subnets, count.index)
availability_zone = element(var.azs, count.index)
map_public_ip_on_launch = var.map_public_ip_on_launch
tags = merge(
local.common_tags,
{
Name = format("%s-public-%s", var.name, element(var.azs, count.index))
Type = "public"
"kubernetes.io/role/elb" = "1"
"kubernetes.io/cluster/${var.cluster_name}" = "shared"
}
)
}
# Private Subnets
resource "aws_subnet" "private" {
count = length(var.private_subnets)
vpc_id = aws_vpc.this.id
cidr_block = element(var.private_subnets, count.index)
availability_zone = element(var.azs, count.index)
tags = merge(
local.common_tags,
{
Name = format("%s-private-%s", var.name, element(var.azs, count.index))
Type = "private"
"kubernetes.io/role/internal-elb" = "1"
"kubernetes.io/cluster/${var.cluster_name}" = "shared"
}
)
}
# Database Subnets
resource "aws_subnet" "database" {
count = length(var.database_subnets)
vpc_id = aws_vpc.this.id
cidr_block = element(var.database_subnets, count.index)
availability_zone = element(var.azs, count.index)
tags = merge(
local.common_tags,
{
Name = format("%s-database-%s", var.name, element(var.azs, count.index))
Type = "database"
}
)
}
# Elastic IPs for NAT Gateways
resource "aws_eip" "nat" {
count = var.enable_nat_gateway ? local.nat_gateway_count : 0
domain = "vpc"
tags = merge(
local.common_tags,
{
Name = format("%s-eip-%s", var.name, element(var.azs, count.index))
}
)
depends_on = [aws_internet_gateway.this]
}
# NAT Gateways
resource "aws_nat_gateway" "this" {
count = var.enable_nat_gateway ? local.nat_gateway_count : 0
allocation_id = element(aws_eip.nat[*].id, count.index)
subnet_id = element(aws_subnet.public[*].id, count.index)
tags = merge(
local.common_tags,
{
Name = format("%s-nat-%s", var.name, element(var.azs, count.index))
}
)
depends_on = [aws_internet_gateway.this]
}
# Route Tables
resource "aws_route_table" "public" {
count = length(var.public_subnets) > 0 ? 1 : 0
vpc_id = aws_vpc.this.id
tags = merge(
local.common_tags,
{
Name = format("%s-public-rt", var.name)
Type = "public"
}
)
}
resource "aws_route_table" "private" {
count = var.enable_nat_gateway ? local.nat_gateway_count : 0
vpc_id = aws_vpc.this.id
tags = merge(
local.common_tags,
{
Name = format("%s-private-rt-%s", var.name, element(var.azs, count.index))
Type = "private"
}
)
}
# Routes
resource "aws_route" "public_internet_gateway" {
count = length(var.public_subnets) > 0 ? 1 : 0
route_table_id = aws_route_table.public[0].id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.this[0].id
timeouts {
create = "5m"
}
}
resource "aws_route" "private_nat_gateway" {
count = var.enable_nat_gateway ? local.nat_gateway_count : 0
route_table_id = element(aws_route_table.private[*].id, count.index)
destination_cidr_block = "0.0.0.0/0"
nat_gateway_id = element(aws_nat_gateway.this[*].id, count.index)
timeouts {
create = "5m"
}
}
# Route Table Associations
resource "aws_route_table_association" "public" {
count = length(var.public_subnets)
subnet_id = element(aws_subnet.public[*].id, count.index)
route_table_id = aws_route_table.public[0].id
}
resource "aws_route_table_association" "private" {
count = length(var.private_subnets)
subnet_id = element(aws_subnet.private[*].id, count.index)
route_table_id = element(
aws_route_table.private[*].id,
var.single_nat_gateway ? 0 : count.index
)
}
# VPC Endpoints
resource "aws_vpc_endpoint" "s3" {
count = var.enable_s3_endpoint ? 1 : 0
vpc_id = aws_vpc.this.id
service_name = data.aws_vpc_endpoint_service.s3.service_name
tags = merge(
local.common_tags,
{
Name = format("%s-s3-endpoint", var.name)
}
)
}
resource "aws_vpc_endpoint_route_table_association" "s3_public" {
count = var.enable_s3_endpoint && length(var.public_subnets) > 0 ? 1 : 0
vpc_endpoint_id = aws_vpc_endpoint.s3[0].id
route_table_id = aws_route_table.public[0].id
}
resource "aws_vpc_endpoint_route_table_association" "s3_private" {
count = var.enable_s3_endpoint ? local.nat_gateway_count : 0
vpc_endpoint_id = aws_vpc_endpoint.s3[0].id
route_table_id = element(aws_route_table.private[*].id, count.index)
}
# Flow Logs
resource "aws_flow_log" "this" {
count = var.enable_flow_log ? 1 : 0
iam_role_arn = aws_iam_role.flow_log[0].arn
log_destination = aws_cloudwatch_log_group.flow_log[0].arn
traffic_type = var.flow_log_traffic_type
vpc_id = aws_vpc.this.id
tags = merge(
local.common_tags,
{
Name = format("%s-flow-log", var.name)
}
)
}
resource "aws_cloudwatch_log_group" "flow_log" {
count = var.enable_flow_log ? 1 : 0
name = "/aws/vpc/${var.name}"
retention_in_days = var.flow_log_retention_in_days
kms_key_id = var.flow_log_kms_key_id
tags = local.common_tags
}
resource "aws_iam_role" "flow_log" {
count = var.enable_flow_log ? 1 : 0
name = format("%s-flow-log-role", var.name)
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "vpc-flow-logs.amazonaws.com"
}
Action = "sts:AssumeRole"
}
]
})
tags = local.common_tags
}
resource "aws_iam_role_policy" "flow_log" {
count = var.enable_flow_log ? 1 : 0
name = format("%s-flow-log-policy", var.name)
role = aws_iam_role.flow_log[0].id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams"
]
Resource = "*"
}
]
})
}

Plik jest bardzo obszerny i składa się głównie z bloków kodu infrastruktury (CloudFormation, Pulumi, Ansible itp.), które nie podlegają tłumaczeniu. Pełna treść dostępna jest w wersji angielskiej — wszystkie bloki kodu, konfiguracje i szablony są identyczne.

Wytyczne infrastruktury jako kod

  • Przechowuj cały kod infrastruktury w Git
  • Używaj znaczących komunikatów commitów
  • Taguj wydania dla wdrożeń produkcyjnych
  • Wdrażaj reguły ochrony gałęzi
  • Recenzuj wszystkie zmiany przez pull requesty
  • Twórz moduły wielokrotnego użytku
  • Utrzymuj moduły skupione i jednozadaniowe
  • Wersjonuj swoje moduły
  • Dokumentuj interfejsy modułów
  • Testuj moduły niezależnie
  • Używaj zdalnych backendów stanu
  • Włącz blokowanie stanu
  • Zaimplementuj szyfrowanie plików stanu
  • Regularnie twórz kopie zapasowe stanu
  • Rozdzielaj stany według środowiska
  • Nigdy nie commituj sekretów
  • Używaj narzędzi do zarządzania sekretami
  • Wdrażaj zasadę najmniejszych uprawnień
  • Włącz logowanie audytu
  • Regularnie skanuj pod kątem bezpieczeństwa
  • Testy jednostkowe modułów
  • Testy integracyjne wdrożeń
  • Walidacja zgodności
  • Szacowanie kosztów
  • Testy wydajnościowe
  • Dokumentuj decyzje architektoniczne
  • Utrzymuj runbooki
  • Twórz przewodniki wdrożeniowe
  • Dokumentuj kroki rozwiązywania problemów
  • Aktualizuj przykłady
Okno terminala
# AI Prompt: "Debug Terraform state issues"
# Błąd blokady stanu
Error: Error acquiring the state lock
ConflictException: Unable to acquire lock
# Rozwiązanie 1: Wymuś odblokowanie (używaj ostrożnie)
terraform force-unlock <LOCK_ID>
# Rozwiązanie 2: Sprawdź tabelę blokad DynamoDB
aws dynamodb scan \
--table-name terraform-state-lock \
--filter-expression "attribute_exists(LockID)"
# Rozwiązanie 3: Ręczne czyszczenie
aws dynamodb delete-item \
--table-name terraform-state-lock \
--key '{"LockID": {"S": "<LOCK_ID>"}}'
# Detekcja dryfu stanu
terraform plan -refresh-only
# Import istniejących zasobów
terraform import aws_instance.example i-1234567890abcdef0
# Przenoszenie zasobów między stanami
terraform state mv aws_instance.old aws_instance.new
# Usuwanie zasobów ze stanu
terraform state rm aws_instance.obsolete
# Kopia zapasowa i przywracanie stanu
terraform state pull > backup.tfstate
terraform state push backup.tfstate
Okno terminala
# Włącz szczegółowe logowanie
export TF_LOG=DEBUG
export TF_LOG_PATH=terraform.log
# Konsola Terraform do testowania
terraform console
> aws_instance.web.private_ip
> [for instance in aws_instance.web : instance.private_ip]
# Graf zależności
terraform graph | dot -Tpng > graph.png
# Walidacja konkretnych modułów
terraform validate -json | jq '.diagnostics[] | select(.severity=="error")'
# Sprawdź atrybuty zasobów
terraform state show aws_instance.web
# Lista wszystkich zasobów
terraform state list
# Odśwież konkretny zasób
terraform apply -refresh-only -target=aws_instance.web
# Debugowanie problemów z providerem
terraform providers lock -platform=linux_amd64 -platform=darwin_amd64
# Sprawdź workspace
terraform workspace show
terraform workspace list
# Analizuj wyjście planu
terraform show -json tfplan | jq '.resource_changes[] | {address: .address, actions: .change.actions}'