This starter kit provides a complete development environment for Apache Polaris with LocalStack integration running on k3s Kubernetes. It includes automated setup of PostgreSQL metastore, S3 integration via LocalStack, and all necessary configurations for immediate development use.
Key features:
- π Automated k3s cluster setup with k3d
- βοΈ Integrated LocalStack for AWS S3 emulation
- ποΈ PostgreSQL metastore configuration
- π€ Task-based automation for easy management
- π Jupyter notebook for verification
Get Apache Polaris running locally in 3 steps:
git clone https://github.com/snowflake-labs/polaris-local-forge
cd polaris-local-forgeInstall Task (if not already installed):
# macOS
brew install go-task/tap/go-task
# Linux
curl -sL https://taskfile.dev/install.sh | sh
sudo mv bin/task /usr/local/bin/
# Windows (Scoop)
scoop install task
# Windows (Chocolatey)
choco install go-taskSetup Python environment:
# Install uv and setup Python environment
task setup:pythonNote: Task commands automatically use the virtual environment. You only need to manually activate it if running Python/Jupyter commands directly:
source .venv/bin/activate # On Unix-like systems .venv\Scripts\activate # On Windows
task setup:allThis single command will:
- β Generate required configuration files
- β Create the k3s cluster with k3d
- β Deploy PostgreSQL and LocalStack
- β Deploy Apache Polaris
- β Create a demo catalog
That's it! β¨
After completion, open and run notebooks/verify_setup.ipynb to verify your setup.
Once setup completes, you'll have the following services running:
| Service | URL | Credentials/Details |
|---|---|---|
| π Polaris API | http://localhost:18181 | See k8s/polaris/.bootstrap-credentials.env for login |
| βοΈ LocalStack | http://localhost:14566 | AWS S3 emulator - Use test/test for credentials |
Quick access:
task urls # Display all service URLs
task status # Check deployment statusThe project uses Task to automate common workflows. Here are the most useful commands:
task install:uv # Install uv Python package manager
task setup:python # Setup Python environment (installs uv + creates venv)
task setup:dnsmasq # Configure DNSmasq for .localstack domain (macOS only)
task prepare # Generate required configuration filestask help # List all available tasks
task setup:all # Complete setup (prepare β cluster β deploy β catalog)
task reset:all # Complete reset (delete cluster β recreate everything)
task urls # Show all service URLs and credentials
task status # Check deployment status
task clean:all # Delete cluster and all resourcestask cluster:create # Create k3d cluster
task cluster:bootstrap-check # Wait for bootstrap deployments
task cluster:polaris-check # Wait for Polaris deployment
task cluster:delete # Delete the cluster
task cluster:reset # Delete and recreate cluster with fresh catalogtask polaris:deploy # Deploy Polaris to the cluster
task polaris:reset # Purge and re-bootstrap Polaris
task polaris:purge # Purge Polaris data
task polaris:bootstrap # Bootstrap Polaris (run after purge)task catalog:setup # Setup demo catalog (bucket, catalog, principal, roles)
task catalog:verify # Generate verification notebook
task catalog:cleanup # Cleanup catalog resources
task catalog:reset # Cleanup and recreate catalog (keeps cluster running)# View logs
task logs:polaris # Stream Polaris server logs
task logs:postgresql # Stream PostgreSQL logs
task logs:localstack # Stream LocalStack logs
task logs:bootstrap # View bootstrap job logs
task logs:purge # View purge job logs
# Troubleshooting
task troubleshoot:polaris # Diagnose Polaris issues
task troubleshoot:postgresql # Check database connectivity
task troubleshoot:localstack # Verify LocalStack connectivity
task troubleshoot:events # Show recent events in polaris namespaceBefore you begin, ensure you have the following tools installed:
- Docker Desktop (>= 4.27) or Docker Engine
- kubectl - Kubernetes command-line tool
- k3d (>= 5.0.0) - Lightweight wrapper to run k3s in Docker
- Python (>= 3.11)
- uv - Python packaging tool
- Task - Task runner (see installation above)
- Dnsmasq - Avoid editing
/etc/hosts(see Advanced Configuration) - direnv - Automatic environment variable loading
Important Ensure all required tools are installed and on your PATH before running
task setup:all.
# Check required tools
docker --version
kubectl version --client
k3d version
python3 --version
uv --version
task --version
# Check Docker is running
docker psThe Taskfile automatically manages most environment variables. If you need to customize them, create a .env file:
# Optional: Override default values
export PROJECT_HOME="$PWD"
export KUBECONFIG="$PWD/.kube/config"
export K3D_CLUSTER_NAME=polaris-local-forge
export K3S_VERSION=v1.32.1-k3s1
export FEATURES_DIR="$PWD/k8s"Tip: Use direnv to automatically load environment variables when entering the project directory.
For seamless access to services, you can configure DNSmasq instead of editing /etc/hosts.
macOS Setup:
# Configure DNSmasq
echo "address=/.localstack/127.0.0.1" >> $(brew --prefix)/etc/dnsmasq.conf
# Add resolver
sudo tee /etc/resolver/localstack <<EOF
nameserver 127.0.0.1
EOF
# Restart DNSmasq
sudo brew services restart dnsmasqOr use Task:
task setup:dnsmasq # macOS only# Pin a different Python version
uv python pin 3.11 # or 3.13
# Recreate virtual environment
uv venv --force
source .venv/bin/activate
uv syncAfter running task setup:all, verify your setup:
Activate the virtual environment (if not already activated) and open the notebook:
source .venv/bin/activate # On Unix-like systems
# .venv\Scripts\activate # On Windows
jupyter notebook notebooks/verify_setup.ipynbThe notebook will:
- Create a test namespace
- Create a test table
- Insert sample data
- Query the data back
Open https://app.localstack.cloud/inst/default/resources/s3/polardb to view your Iceberg files:
You should see the catalog structure with metadata and data files:
# Check all deployments
task status
# Or manually
kubectl get all -n polaris
kubectl get all -n localstackExpected output in polaris namespace:
NAME READY STATUS RESTARTS AGE
pod/polaris-694ddbb476-m2trm 1/1 Running 0 13m
pod/polaris-bootstrap-xxxxx 0/1 Completed 0 13m
pod/postgresql-0 1/1 Running 0 15m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/polaris LoadBalancer 10.43.202.93 172.19.0.3,172.19.0.4 8181:32181/TCP 13m
service/postgresql ClusterIP 10.43.182.31 <none> 5432/TCP 15m
service/postgresql-hl ClusterIP None <none> 5432/TCP 15m
# Check deployment status
task status
# View events
task troubleshoot:events
# Check specific component
task troubleshoot:polaris
task troubleshoot:postgresql
task troubleshoot:localstack# Check Polaris logs
task logs:polaris
# Check pod status and events
task troubleshoot:polaris# Verify LocalStack is running
kubectl get pods -n localstack
# Check connectivity
task troubleshoot:localstack# Check PostgreSQL logs
task logs:postgresql
# Verify connectivity
task troubleshoot:postgresql# View bootstrap logs
task logs:bootstrap
# Reset Polaris
task polaris:resetIf Task commands don't help, you can use these manual commands:
# Check events
kubectl get events -n polaris --sort-by='.lastTimestamp'
# Describe pods
kubectl describe pod -n polaris -l app=polaris
# Check logs
kubectl logs -f -n polaris deployment/polaris
kubectl logs -f -n polaris jobs/polaris-bootstrap
kubectl logs -f -n polaris statefulset/postgresql
kubectl logs -f -n localstack deployment/localstack
# Check services
kubectl get svc -n polaris
kubectl get svc -n localstack
# Verify PostgreSQL
kubectl exec -it -n polaris postgresql-0 -- pg_isready -h localhost
# Verify LocalStack
kubectl exec -it -n localstack deployment/localstack -- \
aws --endpoint-url=http://localhost:4566 s3 lsClean and recreate the catalog with fresh data:
task catalog:resetOr just cleanup without recreating:
task catalog:cleanupComplete reset - deletes cluster and recreates everything with fresh catalog:
task reset:all
# Same as: task cluster:resetDelete the k3d cluster and all resources:
task clean:allThis removes:
- k3d cluster
- All Kubernetes resources
- Catalog data in LocalStack
- PostgreSQL data
Note: Your configuration files in
k8s/polaris/(credentials, secrets, keys) are preserved. Runtask prepareto regenerate them if needed.
Now that you have Apache Polaris running locally, you can:
- Connect query engines: Use with Apache Spark, Trino, or Risingwave
- Explore the API: Check the Polaris API documentation
- Create more catalogs: Run
task catalog:setupwith custom parameters - Develop integrations: Use the LocalStack S3 endpoint for testing
- Experiment with Iceberg: Create tables, partitions, and time-travel queries
- Apache Polaris - Data Catalog and Governance Platform
- Apache Iceberg - Open table format for data lakes
- PyIceberg - Python library to interact with Apache Iceberg
- LocalStack - AWS Cloud Service Emulator
- k3d - k3s in Docker
- k3s - Lightweight Kubernetes Distribution
- Docker - Container Platform
- Kubernetes - Container Orchestration
- kubectl - Kubernetes CLI
- Task - Modern task runner and build tool
- uv - Fast Python packaging tool
- Ansible - Automation and configuration management
- Polaris Documentation
- Iceberg Documentation
- LocalStack Documentation
- k3d Documentation
- Kubernetes Documentation
- Task Documentation
Copyright (c) Snowflake Inc. All rights reserved.
Licensed under the Apache 2.0 license.
Contributions are welcome! Please feel free to submit a Pull Request.
π§ Advanced: Manual Setup (Click to expand)
If you prefer to run commands manually instead of using Task, here's the step-by-step process:
Generate required sensitive files from templates:
ansible-playbook polaris-forge-setup/prepare.ymlbin/setup.shWait for bootstrap deployments:
ansible-playbook polaris-forge-setup/cluster_checks.yml --tags=bootstrapPostgreSQL:
kubectl get pods,svc -n polarisLocalStack:
kubectl get pods,svc -n localstackkubectl apply -k k8s/polarisWait for Polaris deployment:
ansible-playbook polaris-forge-setup/cluster_checks.yml --tags=polarisExport AWS environment variables:
unset AWS_PROFILE
export AWS_ENDPOINT_URL=http://localstack.localstack:4566
export AWS_ACCESS_KEY_ID=test
export AWS_SECRET_ACCESS_KEY=test
export AWS_REGION=us-east-1Create catalog:
ansible-playbook polaris-forge-setup/catalog_setup.ymlansible-playbook polaris-forge-setup/catalog_setup.yml --tags=verifyPurge:
kubectl patch job polaris-purge -n polaris -p '{"spec":{"suspend":false}}'
kubectl wait --for=condition=complete --timeout=300s job/polaris-purge -n polaris
kubectl logs -n polaris jobs/polaris-purgeRe-bootstrap:
kubectl delete -k k8s/polaris/job
kubectl apply -k k8s/polaris/job
kubectl wait --for=condition=complete --timeout=300s job/polaris-bootstrap -n polaris
kubectl logs -n polaris jobs/polaris-bootstrapCleanup catalog:
ansible-playbook polaris-forge-setup/catalog_cleanup.ymlDelete cluster:
bin/cleanup.sh


