# LocalStack: учебный AWS, который живёт в Docker _Провайдеры · TerraformLab Knowledge Base_ **TL;DR:** LocalStack эмулирует AWS API локально, в Docker-контейнере. Terraform думает что работает с настоящим AWS, но никаких реальных ресурсов не создаётся и денег не тратится. Идеально для учёбы и тестов. ## Зачем нужен LocalStack Учиться Terraform на настоящем AWS, это: - Регистрация AWS-аккаунта, привязка кредитки. - Постоянный страх «забыл прибить EC2-инстанс, теперь должен 30 баксов». - Реальные credentials, которые могут утечь через git. - Медленные операции: создать RDS-инстанс, 15 минут. **LocalStack** решает это: ставит Docker-контейнер, который притворяется AWS. У него тот же API, те же HTTP-эндпоинты, те же JSON-ответы. Terraform не видит разницы, для него это AWS. Что Terraform на LocalStack умеет (community edition): - **S3**, бакеты, объекты, lifecycle, версионирование. - **EC2**, инстансы, VPC, subnets, security groups. - **IAM**, роли, политики, пользователи. - **Lambda**, функции, layers, alias. - **SQS, DynamoDB, SNS, CloudWatch Logs, STS**, базовая функциональность. Чего не умеет (community): EKS, ECS Fargate, Cognito, KMS (частично), RDS (только частично). Полный список, на сайте LocalStack. ## Как Terraform с ним соединяется Идея простая. По умолчанию AWS-провайдер стучится в публичные AWS-эндпоинты вида `https://s3.us-east-1.amazonaws.com`. Мы переучиваем его ходить на адрес LocalStack, внутри docker network нашего sandbox это `http://localstack:4566` (DNS-имя соседнего контейнера). Делается это через блок `endpoints` в провайдере: ```hcl provider "aws" { region = "us-east-1" access_key = "test" secret_key = "test" # Без этих флагов провайдер пойдёт проверять creds в реальный AWS и упадёт. skip_credentials_validation = true skip_metadata_api_check = true skip_requesting_account_id = true # S3 в LocalStack работает только в path-style URL. s3_use_path_style = true endpoints { s3 = "http://localstack:4566" ec2 = "http://localstack:4566" iam = "http://localstack:4566" lambda = "http://localstack:4566" sqs = "http://localstack:4566" dynamodb = "http://localstack:4566" sts = "http://localstack:4566" cloudwatch = "http://localstack:4566" logs = "http://localstack:4566" } } ``` В sandbox-сессии курса этот блок уже лежит в готовом виде по пути `/opt/skeletons/aws-localstack-provider.tf` и автоматически копируется в директорию урока. Тебе остаётся писать только ресурсы, настройку трогать не надо. Если запускаешь LocalStack локально вне курса, имя контейнера может быть другим. Тогда меняй адрес на тот, по которому контейнер доступен снаружи, например, `http://localhost:4566` при простом `docker run -p 4566:4566 localstack/localstack:3.x`. ## Разбор флагов - **`access_key = "test"`, `secret_key = "test"`**. LocalStack принимает любые credentials. Литералы `"test"`, конвенция документации LocalStack. - **`skip_credentials_validation = true`**, провайдер AWS обычно дёргает STS чтобы проверить кредитов. В LocalStack STS работает, но криво, лучше выключить. - **`skip_metadata_api_check = true`**, провайдер пытается читать EC2 instance metadata (вдруг мы внутри EC2). На локалке это бессмысленно и затягивает старт. - **`skip_requesting_account_id = true`**, без этого провайдер ходит в STS за account ID; в LocalStack это просто лишний запрос. - **`s3_use_path_style = true`**. S3 поддерживает два формата URL: - subdomain-style: `https://my-bucket.s3.amazonaws.com/key` - path-style: `https://s3.amazonaws.com/my-bucket/key` LocalStack умеет только path-style, поэтому флаг обязателен. ## Шаблон, который мы используем в курсе В этом курсе sandbox-контейнер автоматически делает: ```bash cp /opt/skeletons/aws-localstack-provider.tf provider.tf ``` Файл-скелет уже содержит весь нужный блок. Вам остаётся только написать ресурсы: ```hcl # provider.tf, это уже есть, не трогайте # main.tf, это вы пишете resource "aws_s3_bucket" "hello" { bucket = "my-first-bucket" tags = { Owner = "student" } } ``` ## Проверка что LocalStack работает Healthcheck возвращает статус всех сервисов: ```bash curl http://localstack:4566/_localstack/health # {"services": {"s3": "available", "ec2": "running", ...}} ``` Если `available` или `running`, сервис готов. Если `disabled` или ошибка, что-то не так с контейнером. ## Подводные камни - **State от LocalStack не переедет в реальный AWS.** Если поучились локально, потом перешли на настоящий AWS, `terraform.tfstate` нельзя просто скопировать. Это снапшот «псевдо-AWS», в реальном AWS этих ресурсов нет. - **Не все ресурсы 1-в-1.** Иногда atribute, который реальный AWS возвращает, LocalStack возвращает в другом формате. Тесты `terraform_state_resource` могут пройти на LocalStack, но не на реальном AWS. Учитывайте это при переходе. - **Persistence по умолчанию выключен.** Если перезапустить Docker-контейнер LocalStack, все ваши бакеты пропадут. Это удобно для учёбы (всегда чистая среда), но неожиданно если не знать. Сохранить можно через `PERSISTENCE=1` в env LocalStack. - **`endpoints`, это hack.** В реальном проекте `endpoints` в HCL быть не должно. Если видите в чужом коде, это либо тестовая среда, либо запах продакшен-проблемы. - **Community vs Pro.** LocalStack Pro платный и эмулирует больше сервисов (EKS, IAM Identity Center, KMS). В курсе используется только community, бесплатный. ## Команды ```bash curl http://localstack:4566/_localstack/health ``` Проверить состояние всех LocalStack-сервисов одним запросом. Внутри sandbox курса именно такой адрес. ```bash AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test aws --endpoint-url=http://localstack:4566 s3 ls ``` Проверить S3 через aws CLI напрямую, без terraform. Полезно когда непонятно, на чьей стороне баг. ```bash docker run -d -p 4566:4566 localstack/localstack:3 ``` Поднять LocalStack standalone: для экспериментов вне курсового sandbox. Внутри урока этого делать не надо, он уже поднят. ```bash docker logs localstack-1 --tail 50 ``` Если что-то падает: посмотреть лог контейнера. Часто там сразу видно причину. ## См. также - [AWS Provider: настройки и где Terraform берёт ключи](/terraform/kb/aws-provider.md) - [Блок provider: кому Terraform будет звонить](/terraform/kb/tf-provider-block.md) - [terraform init: первая команда в любом проекте](/terraform/kb/tf-init.md)