MiniStack Documentation

repository·main·Indexed 26 days ago

https://github.com/ministackorg/ministack

A free, open-source local AWS emulator and lightweight alternative to LocalStack. MiniStack provides over 60 AWS services on a single port, supporting multi-account and multi-region isolation for local development and CI/CD pipelines. It includes features such as a test_state API for Step Functions, IMDSv1/v2 emulation, ECS Task Metadata V4, and internal API endpoints for health checks and state resets.

Tokens
18.5K
Snippets
34
Records
87
Agent score
87%

What's inside MiniStack

  1. Explore Community Integrations

    main

    MiniStack has several community-driven integrations for architecture visualization, resource inspection, and .NET hosting:

    • OpenArchFlow: A PWA for generating interactive AWS architecture diagrams from natural language using AI/LLMs.
    • StackPort: A Web UI dashboard to browse and inspect AWS resources within MiniStack. Available via PyPI and Docker Hub.
    • McDoit.Aspire.Hosting.Ministack: A .NET Aspire hosting integration for MiniStack.
  2. Supported Core Services in MiniStack

    main

    MiniStack provides local emulation for several AWS core services. Key services include:

    • S3: Supports bucket and object lifecycle management, versioning, encryption, CORS, ACLs, and object locking. Use S3_PERSIST=1 for optional disk persistence.
    • SQS: Supports both Query API and JSON protocols, FIFO queues with deduplication, and Dead Letter Queues (DLQ).
    • SNS: Supports SNS→SQS and SNS→Lambda fanout, FIFO topics, and mobile-push endpoint lifecycles.
    • DynamoDB: Supports full CRUD, TTL (60s cadence), DynamoDB Streams (with StreamSpecification), and Kinesis streaming destinations.
    • Lambda: Supports Python and Node.js runtimes (warm worker pool), provided runtimes via Docker RIE, and Durable Functions (preview API 2025-12-01). Includes X-Ray active tracing support.
    • IAM & STS: Full identity and access management, including user/role/policy CRUD and session token generation.
    • IMDS (EC2 Metadata): Supports IMDSv1 and IMDSv2. Use MINISTACK_IMDS_V2_REQUIRED=1 to enforce token usage.
    • ECS Metadata & Credentials: Emulates ECS Task Metadata V4 and Container Credentials (v2) for seamless SDK integration in containerized tasks.
    • SecretsManager: Supports secret lifecycle and versioning.
    • CloudWatch Logs: Supports log group/stream management and advanced FilterLogEvents with globbing and exclusion patterns.
  3. Connect to real RDS database endpoints

    main

    When creating an RDS instance in MiniStack, it starts a real database container and returns the actual connection endpoint. You can connect directly to this instance using standard database drivers (e.g., psycopg2 for PostgreSQL).

    Supported engines include: postgres, mysql, mariadb, aurora-postgresql, and aurora-mysql.

    Note: For Aurora clusters, all members share a single database container. The reader endpoint resolves to the same process as the writer, so writes sent to the reader will be accepted.

    import boto3
    import psycopg2  # pip install psycopg2-binary
    
    # Initialize client pointing to MiniStack
    rds = boto3.client("rds", endpoint_url="http://localhost:4566",
                       aws_access_key_id="test", aws_secret_access_key="test", region_name="us-east-1")
    
    # Create the instance
    resp = rds.create_db_instance(
        DBInstanceIdentifier="mydb",
        DBInstanceClass="db.t3.micro",
        Engine="postgres",
        MasterUsername="admin",
        MasterUserPassword="password",
        DBName="appdb",
        AllocatedStorage=20,
    )
    
    # Extract endpoint and connect directly
    endpoint = resp["DBInstance"]["Endpoint"]
    conn = psycopg2.connect(
        host=endpoint["Address"],   # localhost
        port=endpoint["Port"],      # auto-assigned
        user="admin",
        password="password",
        dbname="appdb",
    )
  4. Add a new service to MiniStack

    main

    MiniStack services are implemented as self-contained Python files. To add a new service, follow these steps:

    1. Create a new file at ministack/services/myservice.py containing an async def handle_request(...) function and a reset() function.
    2. Register the service in ministack/app.py by adding it to the SERVICE_REGISTRY. This automatically generates the handler, aliases, and service filter.
    3. Add detection patterns to ministack/core/router.py.
    4. Add a fixture to tests/conftest.py and corresponding tests to tests/test_services.py.
  5. Use MiniStack startup scripts

    main

    MiniStack supports pre-start and post-ready initialization scripts. You can mount these via Docker Compose to automate resource creation (e.g., creating S3 buckets or SQS queues).

    Paths:

    • Pre-start: /docker-entrypoint-initaws.d/*.{sh,py} (or /etc/localstack/init/boot.d/ for LocalStack compatibility).
    • Post-ready: /docker-entrypoint-initaws.d/ready.d/*.{sh,py} (or /etc/localstack/init/ready.d/ for LocalStack compatibility).

    Scripts automatically have access to AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION, and AWS_ENDPOINT_URL. They also receive MINISTACK_INIT_SCRIPT_DIR and MINISTACK_INIT_SCRIPT_PATH.

    volumes:
      - ./init-scripts:/docker-entrypoint-initaws.d           # ministack-native
      # OR
      - ./init-scripts:/etc/localstack/init                    # localstack-compatible
  6. Install and run MiniStack

    main

    MiniStack can be installed and run using several methods depending on your environment requirements:

    Option 1: PyPI (Simplest)

    Install via pip and run the CLI. By default, it runs on http://localhost:4566. You can change the port using the GATEWAY_PORT environment variable.

    Option 2: Docker Hub

    Use standard Docker images for quick setup.

    • Standard image: Basic emulation.
    • With real infrastructure: Use the -v /var/run/docker.sock:/var/run/docker.sock flag to enable real RDS, ECS, and Lambda containers.
    • Full image: Use the :full tag for a Debian/glibc base that includes DuckDB (for Athena) and native PostgreSQL/MySQL drivers. This version reports edition: full on the /_ministack/health endpoint.

    Option 3: Clone and Build

    Clone the repository and use Docker Compose.

    To verify the installation, check the health endpoint.

    # Option 1: PyPI
    pip install ministack
    ministack
    
    # Option 2: Docker Hub
    docker run -p 4566:4566 ministackorg/ministack
    
    # Option 2b: Docker Hub with real infrastructure
    docker run -p 4566:4566 -v /var/run/docker.sock:/var/run/docker.sock ministackorg/ministack
    
    # Option 2c: Full image
    docker run -p 4566:4566 ministackorg/ministack:full
    
    # Option 3: Clone and build
    git clone https://github.com/ministackorg/ministack
    cd ministack
    docker compose up -d
    
    # Verify
    curl http://localhost:4566/_ministack/health
  7. Run MiniStack Java Testcontainers examples

    main

    To run the integration tests for S3, SQS, and DynamoDB using Testcontainers and the AWS SDK v2, ensure you have the prerequisites installed and then execute the Maven test command. Testcontainers will automatically pull the ministackorg/ministack:latest image, start the environment, run the tests, and perform a teardown once complete.

    mvn test
  8. Run real SQL queries with Athena

    main

    To run real SQL queries via DuckDB instead of mocked results, you must use the full image (ministackorg/ministack:full). The default light image returns mocked results (e.g., SELECT 1+1 returns 1).

    Athena queries in MiniStack can query files located in your local S3 data directory.

    import boto3, time
    
    athena = boto3.client("athena", endpoint_url="http://localhost:4566",
                          aws_access_key_id="test", aws_secret_access_key="test", region_name="us-east-1")
    
    # Query runs real SQL via DuckDB
    resp = athena.start_query_execution(
        QueryString="SELECT 42 AS answer, 'hello' AS greeting",
        ResultConfiguration={"OutputLocation": "s3://athena-results/"},
    )
    query_id = resp["QueryExecutionId"]
    
    # Poll for result
    while True:
        status = athena.get_query_execution(QueryExecutionId=query_id)
        if status["QueryExecution"]["Status"]["State"] == "SUCCEEDED":
            break
        time.sleep(0.1)
    
    results = athena.get_query_results(QueryExecutionId=query_id)
    for row in results["ResultSet"]["Rows"][1:]:
        print([col["VarCharValue"] for col in row["Data"]])
    # Output: ['42', 'hello']
  9. Run Lambda functions in Docker

    main

    By default, Lambda runs via a local subprocess. To achieve higher fidelity by running every invocation inside an AWS-supplied runtime container, set LAMBDA_EXECUTOR=docker.

    Note for Docker Compose users: If MiniStack is running in a Docker network, set DOCKER_NETWORK to your Compose network name. This allows Lambda containers to reach MiniStack services using the service name instead of localhost.

    services:
      ministack:
        image: ministackorg/ministack:latest
        container_name: infra_ministack
        ports:
          - "4566:4566"
        environment:
          LAMBDA_EXECUTOR: docker
          DOCKER_NETWORK: ${COMPOSE_PROJECT_NAME}_infra-network
          AWS_DEFAULT_REGION: ${AWS_REGION:-eu-central-1}
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
        networks:
          - infra-network
    
    networks:
      infra-network:

    In your Lambda code (e.g., using Boto3), point the endpoint to the service name:

    boto3.client("s3", endpoint_url="http://infra_ministack:4566", ...)
  10. Run real containers with ECS

    main

    MiniStack can run actual Docker containers when using the ECS service. When a task is run via RunTask, MiniStack injects standard ECS Task Metadata and credentials into the container:

    • ECS_CONTAINER_METADATA_URI_V4: Standard ECS Task Metadata V4 endpoint.
    • AWS_CONTAINER_CREDENTIALS_FULL_URI, AWS_CONTAINER_AUTHORIZATION_TOKEN, and AWS_ENDPOINT_URL: Used by unmodified AWS SDKs to fetch emulated credentials and route service calls through MiniStack.
    import boto3
    
    ecs = boto3.client("ecs", endpoint_url="http://localhost:4566",
                       aws_access_key_id="test", aws_secret_access_key="test", region_name="us-east-1")
    
    ecs.create_cluster(clusterName="dev")
    
    ecs.register_task_definition(
        family="web",
        containerDefinitions=[{
            "name": "nginx",
            "image": "nginx:alpine",
            "cpu": 128,
            "memory": 256,
            "portMappings": [{"containerPort": 80, "hostPort": 8080}],
        }],
    )
    
    # This actually runs an nginx container via Docker
    resp = ecs.run_task(cluster="dev", taskDefinition="web", count=1)
    task_arn = resp["tasks"][0]["taskArn"]
    
    # Stop it (removes the container)
    ecs.stop_task(cluster="dev", task=task_arn)
  11. Ensure stable API Gateway IDs in Terraform

    main

    To prevent API Gateway URLs from changing during terraform apply, use the ms-custom-id tag on aws_apigatewayv2_api (HTTP/WebSocket) or aws_apigateway_rest_api resources. This pins the generated apiId to your supplied value. Note that ls-custom-id is not supported and will result in a BadRequestException.

    resource "aws_apigatewayv2_api" "example" {
      name          = "example"
      protocol_type = "HTTP"
      tags = {
        ms-custom-id = "example"
      }
    }
    # → invoke URL stays "example.execute-api.localhost:4566" every apply