Local Kubernetes Environment Manager - Simplified local K8s development with Kind
Project description
LoKO - Local Kubernetes Oasis - simplified Kubernetes development environments
A Python CLI utility to manage local Kubernetes environments with Kind, providing simplified configuration management, version upgrades, DNS, wildcard certificates, local container registry, and extensive customization options.
Features
- Easy Setup: Initialize local Kubernetes clusters with a single command
- Smart Version Management: Upgrade component versions using loko-updater comments
- Automatic Backups: Config files are automatically backed up before upgrades
- Custom Templates: Use your own Jinja2 templates for configuration generation
- Extensive CLI Overrides: Override any configuration value via command-line flags
- Built-in Local Registry: Local container registry with TLS support
- Automatic HTTPS: Built-in certificate management with mkcert
- Local DNS: Automatic DNS configuration for local development
- Metrics & Monitoring: Built-in metrics-server for resource monitoring and HPA support
- Comprehensive Status: Detailed view of cluster resources with
loko status - Granular Workload Management: List, deploy, and undeploy individual workloads with
loko workload - Advanced Node Scheduling: Flexible node labeling and workload placement
- Registry Mirroring: Automatic caching/mirroring of external registries (Docker Hub, Quay, etc.)
- Workload Presets: Pre-configured settings for common workloads (MySQL, PostgreSQL, Valkey, etc.)
- Helm-based Deployment: Deploy workloads from public repositories (groundhog2k, etc.)
- Centralized Helm Repos: Define repositories once, reference everywhere
- Automatic Secrets Management: Automatically generate, fetch and save workload credentials with deduplication
- Port Availability Checking: Pre-flight validation ensures all required ports are available before cluster creation
- Smart Error Handling: Clear, actionable error messages guide you to solutions
Breaking Changes in v0.1.0
Important for existing users: The configuration schema has been restructured for better organization and clarity. If you have an existing
loko.yaml, you'll need to regenerate it.
Migration Steps
-
Backup your existing config (if you have customizations):
cp loko.yaml loko.yaml.backup
-
Regenerate the config:
loko config generate --force
-
Re-apply your customizations to the new config structure.
Key Schema Changes
| Old Path | New Path |
|---|---|
local-ip |
network.ip |
local-domain |
network.domain |
local-dns-port |
network.dns-port |
local-lb-ports |
network.lb-ports |
use-apps-subdomain |
network.subdomain.enabled |
apps-subdomain |
network.subdomain.value |
provider |
cluster.provider |
kubernetes |
cluster.kubernetes |
nodes |
cluster.nodes |
nodes.allow-scheduling-on-control-plane |
cluster.nodes.scheduling.control-plane.allow-workloads |
nodes.internal-components-on-control-plane |
cluster.nodes.scheduling.control-plane.isolate-internal-components |
run-workloads-on-workers-only |
cluster.nodes.scheduling.workers.isolate-workloads |
internal-components (list) |
internal-components (dict with named components) |
helm-repositories |
workloads.helm-repositories |
Prerequisites
- Python 3.9 or higher
- Docker
- Kind
- mkcert (for HTTPS certificates)
- Helm
- Helmfile
- (optional) nss (for macOS) or libnss3-tools (for Linux) - needed for Firefox to trust mkcert certificates
Installing Prerequisites with Mise (Recommended)
Mise is the recommended way to install and manage CLI tools. Clone the repo and run mise install from the project root to install all prerequisites:
git clone https://github.com/bojanraic/loko.git
cd loko
mise install # Installs kind, helm, kubectl, mkcert, helmfile
Installation
From PyPI (recommended)
Using pip:
pip install loko-k8s
Using uv:
uv tool install loko-k8s
From Source
git clone https://github.com/bojanraic/loko.git
cd loko
pip install -e .
Using uv (for development)
git clone https://github.com/bojanraic/loko.git
cd loko
uv sync
uv run loko --help
Quick Start
-
Check prerequisites:
loko check-prerequisites -
Generate a default configuration:
loko config generate # Or use --minimal for a compact config without comments/disabled sections: # loko config generate --minimal
-
Initialize your environment:
loko init -
Create the full environment:
loko create
Demo
Watch Loko in action - see the complete workflow from installation to cluster validation:
Demo highlights:
- Installing loko
- Generating a default configuration with auto-detected IP
- Creating a local Kubernetes cluster with Kind
- Deploying workloads (Traefik, container registry, PostgreSQL) with Helm
- Validating the cluster setup
- Checking environment status
- Upgrading component versions
- Viewing workload secrets & connecting to PostgreSQL and test application
- Stopping and starting environment
- Installing shell completion (via
loko completion <shell>)
Commands
Environment Lifecycle
loko init- Initialize environment (generate configs, setup certs, network)loko create- Create full environment with complete workflowloko start- Start all cluster containersloko stop- Stop all cluster containersloko destroy- Destroy the environmentloko recreate- Destroy and recreate the environmentloko clean- Destroy environment and remove all artifacts
Status & Validation
loko status- Show comprehensive environment statusloko validate- Validate the environmentloko check-prerequisites- Check if required tools are installedloko completion <shell>- Generate shell completion script (bash, zsh, fish)
Configuration & Secrets
loko config generate- Generate default loko.yaml with auto-detected local IP (use--minimalfor compact config without comments)loko config compact- Compact existing config by removing comments and disabled sectionsloko config detect-ip- Detect and display the local IP addressloko config validate- Validate configuration file structure and valuesloko config port-check- Check availability of all configured portsloko config dns-check- Check DNS configuration and resolution statusloko config upgrade- Upgrade component versions using loko-updater commentsloko config helm-repo-add- Add Helm repositories to configloko config helm-repo-remove- Remove Helm repositories from configloko workload list- List workloads and their status (with filtering options)loko workload deploy- Deploy all or specific workloadsloko workload undeploy- Undeploy all or specific workloadsloko secret fetch- Fetch workload credentials from clusterloko secret show- Display saved workload credentialsloko registry status- Show registry statistics and configurationloko registry list-repos- List all repositories in the registryloko registry show-repo <name>- Show details about a specific repositoryloko registry list-tags <name>- List all tags for a repository
Checking Cluster Status
Use the status command to get a comprehensive overview of your local Kubernetes environment:
loko status
This will display:
- Cluster Status: Overall health of the Kubernetes cluster
- Container Status: Status of all related containers (nodes, DNS, etc.)
- Node Status: List of all nodes with their roles and status
- DNS Status: Status of the local DNS service
Version Management & Upgrades
Migration Note: If you're upgrading from an earlier version of Loko that used
# renovate:comments, you'll need to update them to# loko-updater:. A simple find-and-replace in yourloko.yamlwill do:sed -i '' 's/# renovate:/# loko-updater:/g' loko.yaml # macOS sed -i 's/# renovate:/# loko-updater:/g' loko.yaml # Linux
Loko uses loko-updater comments in your configuration file to track and upgrade component versions. This approach allows you to:
- Keep component versions up-to-date
- Track version sources directly in your config
- Automatically query Docker Hub and Helm repositories for latest versions
How It Works
Add loko-updater comments above the version fields in your loko.yaml:
cluster:
kubernetes:
image: kindest/node
# loko-updater: datasource=docker depName=kindest/node
tag: v1.35.0
internal-components:
traefik:
# loko-updater: datasource=helm depName=traefik repositoryUrl=https://traefik.github.io/charts
version: "38.0.2"
workloads:
system:
- name: mysql
config:
chart: groundhog2k/mysql
# loko-updater: datasource=helm depName=mysql repositoryUrl=https://groundhog2k.github.io/helm-charts
version: 3.0.8
Supported Datasources
- Docker Hub (
datasource=docker): Fetches latest tags from Docker Hub - Helm Repositories (
datasource=helm): Fetches latest chart versions from Helm repos
Running Upgrades
loko config upgrade
This will:
- Scan your config for loko-updater comments
- Query each datasource for the latest version (in parallel)
- Create a backup (
loko-prev.yaml) - Update versions in place
- Show a summary of changes
Performance: Helm repository checks are performed in parallel, significantly reducing upgrade time when checking multiple repositories.
Example output:
Upgrading component versions...
Updates found:
kindest/node: v1.34.0 → v1.35.0
traefik: 37.3.0 → 38.0.2
mysql: 3.0.7 → 3.0.8
Backup created: loko-prev.yaml
Updated 3 version(s) in loko.yaml
Total fetch time: 8.18s (Helm ops: 8.18s)
Restoring from Backup
If an upgrade causes issues, easily revert:
mv loko-prev.yaml loko.yaml
Managing Helm Repositories
Loko provides commands to manage Helm repositories in your configuration file:
Adding Repositories
# Add a single repository
loko config helm-repo-add \
--helm-repo-name bitnami \
--helm-repo-url https://charts.bitnami.com/bitnami
# Add multiple repositories at once
loko config helm-repo-add \
--helm-repo-name bitnami --helm-repo-url https://charts.bitnami.com/bitnami \
--helm-repo-name jetstack --helm-repo-url https://charts.jetstack.io
Removing Repositories
# Remove a single repository
loko config helm-repo-remove --helm-repo-name bitnami
# Remove multiple repositories
loko config helm-repo-remove \
--helm-repo-name bitnami \
--helm-repo-name jetstack
Using Added Repositories
Added repositories appear in your config and can be referenced:
environment:
workloads:
helm-repositories:
- name: bitnami
url: https://charts.bitnami.com/bitnami/
user:
- name: my-app
config:
repo:
ref: bitnami # Reference the added repository
chart: bitnami/nginx
version: 1.0.0
Managing Workload Credentials
Workload credentials (database passwords, etc.) are automatically generated during deployment:
# Fetch credentials from the cluster
loko secret fetch
# Display saved credentials
loko secret show
Tip:
loko secret showwill automatically trigger afetchif the secrets file doesn't exist yet.
Credentials are saved locally to:
<base-dir>/<env-name>/workload-secrets.txt
Example workloads with auto-generated credentials:
- MySQL (root password)
- PostgreSQL (postgres password)
- MongoDB (root password)
- RabbitMQ (admin password)
- Valkey (default password)
Directory Structure
When you run loko init or loko create, a .loko directory is created (configurable via base-dir).
.
├── loko.yaml # Main configuration file
├── .loko/ # Default directory for cluster data and configs
│ └── <env-name>/ # Environment-specific directory (e.g. dev-me)
│ ├── certs/ # TLS certificates and keys
│ │ ├── rootCA.pem # Root CA certificate
│ │ ├── <domain>.pem # Domain certificate
│ │ ├── <domain>-key.pem # Domain private key
│ │ └── <domain>-combined.pem # Combined cert and key
│ ├── config/ # Generated configuration files
│ │ ├── cluster.yaml # KinD cluster configuration
│ │ ├── containerd/ # Container runtime config (per registry)
│ │ │ ├── cr.dev.me/hosts.toml
│ │ │ └── docker.io/hosts.toml
│ │ ├── dnsmasq.conf # Local DNS configuration
│ │ └── helmfile.yaml # Helm releases definition
│ ├── logs/ # Kubernetes node logs
│ ├── storage/ # Persistent volume data
│ ├── kubeconfig # Cluster access configuration
│ └── workload-secrets.txt # Generated workload credentials
Note: The
.lokodirectory is git-ignored by default.
Workload Management
Loko permits granular control over your workloads through the workload command group.
Listing Workloads
View all enabled workloads, their type, namespace, and current status:
loko workload list
Filter by type or status:
loko workload list --all # All workloads including disabled
loko workload list --user # Only enabled user workloads
loko workload list --system # Only enabled system workloads
loko workload list --internal # Only enabled internal components (Traefik, Registry, etc.)
loko workload list --disabled # Only disabled workloads
loko workload list --system --disabled # Disabled system workloads only
Deploying and Undeploying
Deploy or undeploy specific workloads:
# Deploy all user and system workloads
loko workload deploy
# Deploy a specific workload
loko workload deploy mongodb
# Undeploy a specific workload
loko workload undeploy garage
# Include internal workloads
loko workload deploy --internal
The deploy and undeploy commands default to targeting user and system workloads. Use --all or specific type flags to include internal components.
Note: Selective deployment uses
helmfile --selectorunder the hood.
Workload Types and DNS Structure
-
System Workloads (
workload.network.domain):- Core infrastructure workloads (databases, message queues, etc.)
- Direct DNS resolution (e.g.,
mysql.dev.me,postgres.dev.me)
-
User Workloads (
workload.network.subdomain.value.network.domain):- Custom applications and workloads
- Either under subdomain (
myapp.apps.dev.me) or direct domain (myapp.dev.me) - Configurable via
network.subdomain.enabledsetting
-
Internal Components:
- Registry (e.g.,
cr.dev.me) - Traefik ingress controller
- DNS service (dnsmasq)
- Metrics server (optional)
- Registry (e.g.,
Accessing Workloads
Once the environment is running, workloads are accessible through:
-
Direct Port Access:
# Example for PostgreSQL psql -h localhost -p 5432 -U postgres
-
Domain Names:
# Example for system workload psql -h postgres.dev.me -U postgres
-
Workload Credentials:
- Passwords are automatically generated and stored in
<base-dir>/<env-name>/workload-secrets.txt - Or fetch them with:
loko secret show
- Passwords are automatically generated and stored in
Using the Local Container Registry
The environment includes a local container registry accessible at <registry.name>.<network.domain>.
-
Push Images:
docker tag myapp:latest cr.dev.me/myapp:latest docker push cr.dev.me/myapp:latest
-
Use in Kubernetes:
image: cr.dev.me/myapp:latest
Node Scheduling and Workload Placement
The environment supports advanced node scheduling configurations to separate infrastructure and application workloads.
Node Labels
Configure custom labels in loko.yaml:
cluster:
nodes:
labels:
control-plane:
tier: "infrastructure"
worker:
tier: "application"
Scheduling Configuration
Control workload placement with the scheduling section:
cluster:
nodes:
scheduling:
control-plane:
allow-workloads: true # Allow user/system workloads on control-plane
isolate-internal-components: true # Force Traefik/registry to control-plane only
workers:
isolate-workloads: true # Force user/system workloads to workers only
OCI Registry and Helm Chart Validation
Loko includes validation workflows for testing OCI registry functionality.
Run validation with:
loko validate
This runs a comprehensive check including:
- Cluster status and node readiness
- DNS service health
- System pods status
- Kubectl connectivity
- Registry & TLS Validation: Builds a test image, pushes to local registry, deploys a test app, and verifies connectivity.
Inspecting the Registry
Use the registry command group to inspect and manage the local container registry:
# Show registry statistics and configuration
loko registry status
# List all repositories (local and mirrored)
loko registry list-repos
# Show details about a specific repository
loko registry show-repo myapp
loko registry show-repo docker.io/library/nginx
# List all tags for a repository
loko registry list-tags myapp
When mirroring is enabled, images pulled through the cluster are cached in the local registry. Use list-repos to verify mirroring is working.
Configuration
The environment is configured through loko.yaml. Generate a default one with loko config generate.
Schema Structure
environment:
# General settings
name: string # Name of the environment
base-dir: string # Base directory for storage
expand-env-vars: boolean # Whether to expand OS and loko variables
# Cluster configuration
cluster:
provider:
name: string # Provider name (currently only "kind" supported)
runtime: string # Container runtime (docker or podman)
kubernetes:
api-port: integer # API server port
image: string # Node image
tag: string # Node image tag
nodes:
servers: integer # Number of control-plane nodes
workers: integer # Number of worker nodes
scheduling:
control-plane:
allow-workloads: boolean
isolate-internal-components: boolean
workers:
isolate-workloads: boolean
labels: # Optional custom node labels
control-plane: {}
worker: {}
# Network configuration
network:
ip: string # Local IP for DNS resolution
domain: string # Domain name
dns-port: integer # DNS resolver port (default 53)
subdomain:
enabled: boolean # Use subdomain for user apps
value: string # Subdomain value (e.g., "apps")
lb-ports: array # Load balancer ports [80, 443]
# Registry configuration
registry:
name: string # Registry name (e.g., "cr")
storage:
size: string # PVC size (e.g., "10Gi")
mirroring:
enabled: boolean
sources: array # List of mirror sources
# Internal components (infrastructure)
internal-components:
traefik:
version: string
zot:
version: string
dnsmasq:
version: string
metrics-server:
version: string
enabled: boolean # Only metrics-server is optional
# Workload configuration
workloads:
use-presets: boolean # Whether to use workload presets
helm-repositories: array # Centralized Helm repo definitions
system: array # List of system workloads
user: array # List of user-defined workloads
CLI Overrides
Loko provides extensive CLI options to override almost any configuration value during initialization:
loko init --name my-cluster --workers 3 --registry-storage 50Gi --no-schedule-on-control
See loko init --help for all available overrides.
Custom DNS Port
Loko runs a lightweight DNS container on your machine so that services such as postgres.dev.me resolve locally. By default it binds to the standard DNS port 53, but some hosts already listen on that port. If you need to avoid a conflict, set network.dns-port in loko.yaml (or pass --dns-port to loko init). Loko will start the DNS container on the specified port and automatically update the /etc/resolver/<domain> entry so lookups continue to work.
Troubleshooting
-
DNS Resolution Issues
- Run DNS diagnostics:
loko config dns-check - Verify local DNS container is running:
loko status - Check DNS configuration:
cat /etc/resolver/<your-domain>
- Run DNS diagnostics:
-
Certificate Issues
- Regenerate certificates:
loko init(will re-run certificate setup) - Verify cert location:
ls <base-dir>/<env-name>/certs/
- Regenerate certificates:
-
Workload Access Issues
- Validate environment:
loko validate - Verify ingress:
kubectl get ingress -A - Check credentials:
loko secret show
- Validate environment:
-
OCI Registry Issues
- Test registry connectivity:
docker pull cr.dev.me/test:latest - Run validation:
loko validate
- Test registry connectivity:
-
Version Upgrade Issues
- Restore from backup:
mv loko-prev.yaml loko.yaml - Check loko-updater comment syntax in config file
- Restore from backup:
-
Port Conflicts
- Check what's using a port:
sudo lsof -i :53(macOS) orsudo netstat -tlnp | grep :53(Linux) - Change the DNS port in config:
network.dns-port: 5353
- Check what's using a port:
Development
Setup
git clone https://github.com/bojanraic/loko.git
cd loko
uv sync
uv run loko --help
Running Tests
# Run all unit tests
uv run pytest tests/ --ignore=tests/integration
# Run with verbose output
uv run pytest tests/ -v --ignore=tests/integration
Code Quality
uv run ruff check loko/
uv run ruff format loko/
License
This project is licensed under the MIT License - see the LICENSE file for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file loko_k8s-0.1.2.tar.gz.
File metadata
- Download URL: loko_k8s-0.1.2.tar.gz
- Upload date:
- Size: 73.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
923e0016f57e823f1ccb8391385ae799c332673215c1e7c4ff7dfda9e4fd98d8
|
|
| MD5 |
60af04bc23812eca196f8ff609293074
|
|
| BLAKE2b-256 |
6b7b58f3d288955a36bd9b1da69042a2d073b9c839d4d7c72b58e41c8b62067d
|
Provenance
The following attestation bundles were made for loko_k8s-0.1.2.tar.gz:
Publisher:
publish.yml on bojanraic/loko
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
loko_k8s-0.1.2.tar.gz -
Subject digest:
923e0016f57e823f1ccb8391385ae799c332673215c1e7c4ff7dfda9e4fd98d8 - Sigstore transparency entry: 833780272
- Sigstore integration time:
-
Permalink:
bojanraic/loko@a4bc83de19c04a54bf9c722e34d74ebf71b33005 -
Branch / Tag:
refs/tags/0.1.2 - Owner: https://github.com/bojanraic
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a4bc83de19c04a54bf9c722e34d74ebf71b33005 -
Trigger Event:
release
-
Statement type:
File details
Details for the file loko_k8s-0.1.2-py3-none-any.whl.
File metadata
- Download URL: loko_k8s-0.1.2-py3-none-any.whl
- Upload date:
- Size: 88.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
061aadbecb91ee42216bac58587a0e2114c0e03e958c068f91fafdbd6a2f338f
|
|
| MD5 |
fe37332c1fc409c43239f4c3482fa573
|
|
| BLAKE2b-256 |
0a4c58f329bc748c12d14940e0f7e764271ffee13632cc069970763a7286da9a
|
Provenance
The following attestation bundles were made for loko_k8s-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on bojanraic/loko
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
loko_k8s-0.1.2-py3-none-any.whl -
Subject digest:
061aadbecb91ee42216bac58587a0e2114c0e03e958c068f91fafdbd6a2f338f - Sigstore transparency entry: 833780275
- Sigstore integration time:
-
Permalink:
bojanraic/loko@a4bc83de19c04a54bf9c722e34d74ebf71b33005 -
Branch / Tag:
refs/tags/0.1.2 - Owner: https://github.com/bojanraic
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a4bc83de19c04a54bf9c722e34d74ebf71b33005 -
Trigger Event:
release
-
Statement type: