LocalStack, або Як налаштувати локальне AWS-середовище
Усім привіт, мене звати Богдан, я Intermediate Software Engineer у компанії VITech. З Amazon Web Services (AWS) я познайомився два роки тому, з того часу активно працюю з багатьма їхніми сервісами кожен день.
AWS надає дуже потужні інструменти, але є один нюанс — локальне середовище з використанням цих сервісів. Звісно, ми можемо використовувати щось на зразок відокремленого dev/sandbox середовища, але й тут не без проблем: швидкість отримання відгуку щодо нових змін, ціна, використання багатьма розробниками одночасно, обмежені можливості модифікації середовища.
Саме тут на допомогу приходить LocalStack. Що ж це таке та як його використовувати?

LocalStack — це локальний емулятор AWS, написаний на Python, який дає змогу працювати відокремлено та без підключення до інтернету.
Як використовувати
Є дві можливості запуску та використання:
- localstack cli
python3 -m pip install --upgrade localstack localstack start
- docker
docker run -d -p 4566:4566 localstack/localstack:2.2.0
Особисто я надаю перевагу docker-у, тому, що він незалежний щодо операційної системи та не вимагає встановлення додаткових речей, а ще можна зробити docker-compose та використовувати одну конфігурацію запуску на всьому проєкті. На відміну від docker-у, localstack cli використовує Python та вимагає попереднього встановлення.
Якщо ми вже згадали docker-compose, то розгляньмо приклад:
version: '3.9' services: localstack: container_name: localstack image: localstack/localstack:2.2.0 network_mode: bridge ports: - "4566:4566" environment: - LAMBDA_DOCKER_NETWORK=bridge - AWS_DEFAULT_REGION=us-east-2 - DEBUG=1 - DOCKER_HOST=unix:///var/run/docker.sock volumes: - ./init-aws.sh:/etc/localstack/init/ready.d/init-aws.sh - /var/run/docker.sock:/var/run/docker.sock
З важливого:
- я використовую
network_mode: bridge(можна й host), бо якщо ми будемо запускати lambda локально в docker, я хочу мати можливість туди підключатись (container-to-container); - init-aws.sh — це скрипт, який виконується після успішного запуску контейнера, тут ми можемо підготувати створення необхідних ресурсів за допомогою AWS CLI.
Приклади використання
AWS CLI
Тут дуже легко. Все, що потрібно, це додати --endpoint-url http://localhost:4566
aws s3 mb s3://local-bucket --endpoint-url http://localhost:4566 aws s3api list-buckets --query "Buckets[].Name" --endpoint-url http://localhost:4566
Дуже зручно використовувати alias - alias awslocal="aws --endpoint-url=http://localhost:4566”. Після цього можна використовувати команду awslocal (або ж іншу, залежно від того, як ви назвете alias), яка ****автоматично буде додавати це поле.
awslocal s3 mb s3://local-bucket2 awslocal s3api list-buckets --query "Buckets[].Name"
AWS SDK (Java)
Для роботи з AWS нам необхідно підтягнути залежності, які містять імплементацію клієнтів для роботи з AWS-сервісами. Ми розглядаємо приклад на Gradle та Java, але всюди логіка однакова.
implementation platform('software.amazon.awssdk:bom:2.20.115')
implementation 'software.amazon.awssdk:s3'
Створення S3 клієнта:
private static final S3Client S3 = S3Client.builder().build();
Отож, так само як і в попередньому прикладі, нам потрібно змінити ендпоінт, на який буде звертатись клієнт:
private static final S3Client S3 = S3Client.builder()
.endpointOverride(URI.create("https://localhost:4566"))
.build();
Spring
Варто почати з того, що всі налаштування, які підходять для Java, підходять і тут, але додатково ми отримуємо нові та спрощені можливості для налаштування. Перша така можливість — це анотація @Configuration, яка додається до класу, в якому описані створення необхідних bean-нів. Друга — @Profile, за допомогою цієї анотації дуже зручно розділити конфігураційні класи на ті, які працюють із AWS, і ті, які працюють із localStack.
Конфігурація:
@Configuration
@Profile("localstack")
public class Configurations {
@Bean
public S3Client s3Client() {
return S3Client.builder()
.endpointOverride(URI.create("https://s3.localhost.localstack.cloud:4566"))
.build();
}
}
Зверніть увагу, що тут використовується DNS https://s3.localhost.localstack.cloud:4566, це аналогічно до https://localhost:4566/.
Spring Cloud
На цей час актуальна версія провайдера для AWS — v3. Тут нам стає ще зручніше працювати з клієнтами. Ми можемо задати ендпоінт через параметр.
spring: cloud: aws: region: static: us-east-2 s3: endpoint: http://s3.localhost.localstack.cloud:456
Необхідні залежності:
implementation platform('io.awspring.cloud:spring-cloud-aws-dependencies:3.0.1')
implementation 'io.awspring.cloud:spring-cloud-aws-starter-s3'
Testcontainers
Сьогодні всі активно використовують тестові контейнери для інтеграційних тестів, давайте й ми оглянемо такий приклад із Spring.
Необхідні залежності:
implementation platform('org.testcontainers:testcontainers-bom:1.18.3')
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation 'org.testcontainers:localstack'
Тест:
@Testcontainers
@SpringBootTest
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = ApplicationTests.TestConfig.class)
class ApplicationTests {
private static final DockerImageName LOCALSTACK_IMAGE = DockerImageName.parse("localstack/localstack:2.2.0");
@Container
private static final LocalStackContainer LOCAL_STACK_CONTAINER = new LocalStackContainer(LOCALSTACK_IMAGE)
.withEnv("AWS_DEFAULT_REGION", Region.US_EAST_2.toString())
@Autowired
private S3Client s3Client;
@Test
void test() {
// GIVEN
// WHEN
// THEN
}
@TestConfiguration
public static class TestConfig {
@Bean("s3ClientTest")
@Primary
public S3Client s3Client() {
return S3Client.builder()
.endpointOverride(LOCAL_STACK_CONTAINER.getEndpointOverride(LocalStackContainer.Service.S3))
.build();
}
}
}
Із важливого:
- анотація @Container запускає контейнер перед тестами;
- анотація @TestConfiguration описує налаштування клієнтів для тестів;
- анотація @ContextConfiguration(classes = ApplicationTests.TestConfig.class) дозволяє використати налаштування клієнтів, які ми змінили.
Terraform
Для використання Terraform та LocalStack, нам необхідно встановити спеціальний сервіс:
pip install terraform-local
Для роботи з AWS основна вимога — це provider:
provider "aws" {
region = "us-east-2"
}
Якщо раніше ми змінювали ендпоінт для клієнтів, то тепер нам необхідно змінити ендпоінт для провайдера:
provider "aws" {
region = "us-east-2"
endpoints {
s3 = "https://s3.localhost.localstack.cloud:4566"
sqs = "https://sqs.localhost.localstack.cloud:4566"
}
}
Наступними кроками нам потрібно виконувати tflocal init та tflocal apply (замість tf init та tf apply).
Підсумок
Це був швидкий огляд, з чого можна та варто почати впровадження LocalStack-у на вашому проєкті, але я можу з впевненістю сказати, що ця річ дійсно пришвидшує розробку.
Також ось репозиторій із готовою аплікацією та вище зазначеними сервісами.

15 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів