https://github.com/bojanraic/loko
LoKO - Local Kubernetes Oasis
https://github.com/bojanraic/loko
developer-tools development kubernetes kubernetes-setup local-development
Last synced: 5 months ago
JSON representation
LoKO - Local Kubernetes Oasis
- Host: GitHub
- URL: https://github.com/bojanraic/loko
- Owner: bojanraic
- License: mit
- Created: 2025-11-19T21:01:51.000Z (7 months ago)
- Default Branch: main
- Last Pushed: 2026-01-18T00:07:03.000Z (5 months ago)
- Last Synced: 2026-01-18T04:37:22.565Z (5 months ago)
- Topics: developer-tools, development, kubernetes, kubernetes-setup, local-development
- Language: Python
- Homepage:
- Size: 574 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# LoKO - Local Kubernetes Oasis - simplified Kubernetes development environments
[](https://badge.fury.io/py/loko-k8s)
[](https://pypi.org/project/loko-k8s/)
[](https://opensource.org/licenses/MIT)
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
1. **Backup your existing config** (if you have customizations):
```bash
cp loko.yaml loko.yaml.backup
```
2. **Regenerate the config**:
```bash
loko config generate --force
```
3. **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](https://kind.sigs.k8s.io/docs/user/quick-start/#installation)
- [mkcert](https://github.com/FiloSottile/mkcert#installation) (for HTTPS certificates)
- [Helm](https://helm.sh/docs/intro/install/)
- [Helmfile](https://github.com/helmfile/helmfile#installation)
- (optional) nss (for macOS) or libnss3-tools (for Linux) - needed for Firefox to trust mkcert certificates
### Installing Prerequisites with Mise (Recommended)
[Mise](https://mise.jdx.dev/) 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:
```bash
git clone https://github.com/bojanraic/loko.git
cd loko
mise install # Installs kind, helm, kubectl, mkcert, helmfile
```
## Installation
### From PyPI (recommended)
Using pip:
```bash
pip install loko-k8s
```
Using uv:
```bash
uv tool install loko-k8s
```
### From Source
```bash
git clone https://github.com/bojanraic/loko.git
cd loko
pip install -e .
```
### Using uv (for development)
```bash
git clone https://github.com/bojanraic/loko.git
cd loko
uv sync
uv run loko --help
```
## Quick Start
1. Check prerequisites:
```bash
loko check-prerequisites
```
2. Generate a default configuration:
```bash
loko config generate
# Or use --minimal for a compact config without comments/disabled sections:
# loko config generate --minimal
```
3. Initialize your environment:
```bash
loko init
```
4. Create the full environment:
```bash
loko create
```
## Demo
Watch Loko in action - see the complete workflow from installation to cluster validation:
[](https://asciinema.org/a/ZU2gJvGoCxTkJeYgGiFdpwe9k)
**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 `)
## Commands
### Environment Lifecycle
- `loko init` - Initialize environment (generate configs, setup certs, network)
- `loko create` - Create full environment with complete workflow
- `loko start` - Start all cluster containers
- `loko stop` - Stop all cluster containers
- `loko destroy` - Destroy the environment
- `loko recreate` - Destroy and recreate the environment
- `loko clean` - Destroy environment and remove all artifacts
### Status & Validation
- `loko status` - Show comprehensive environment status
- `loko validate` - Validate the environment
- `loko check-prerequisites` - Check if required tools are installed
- `loko completion ` - Generate shell completion script (bash, zsh, fish)
### Configuration & Secrets
- `loko config generate` - Generate default loko.yaml with auto-detected local IP (use `--minimal` for compact config without comments)
- `loko config compact` - Compact existing config by removing comments and disabled sections
- `loko config detect-ip` - Detect and display the local IP address
- `loko config validate` - Validate configuration file structure and values
- `loko config port-check` - Check availability of all configured ports
- `loko config dns-check` - Check DNS configuration and resolution status
- `loko config upgrade` - Upgrade component versions using loko-updater comments
- `loko config helm-repo-add` - Add Helm repositories to config
- `loko config helm-repo-remove` - Remove Helm repositories from config
- `loko workload list` - List workloads and their status (with filtering options)
- `loko workload deploy` - Deploy all or specific workloads
- `loko workload undeploy` - Undeploy all or specific workloads
- `loko secret fetch` - Fetch workload credentials from cluster
- `loko secret show` - Display saved workload credentials
- `loko registry status` - Show registry statistics and configuration
- `loko registry list-repos` - List all repositories in the registry
- `loko registry show-repo ` - Show details about a specific repository
- `loko registry list-tags ` - List all tags for a repository
## Checking Cluster Status
Use the `status` command to get a comprehensive overview of your local Kubernetes environment:
```bash
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 your `loko.yaml` will do:
> ```bash
> 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`:
```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
```bash
loko config upgrade
```
This will:
1. Scan your config for loko-updater comments
2. Query each datasource for the latest version (in parallel)
3. Create a backup (`loko-prev.yaml`)
4. Update versions in place
5. 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:
```bash
mv loko-prev.yaml loko.yaml
```
## Managing Helm Repositories
Loko provides commands to manage Helm repositories in your configuration file:
### Adding Repositories
```bash
# 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
```bash
# 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:
```yaml
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:
```bash
# Fetch credentials from the cluster
loko secret fetch
# Display saved credentials
loko secret show
```
> **Tip**: `loko secret show` will automatically trigger a `fetch` if the secrets file doesn't exist yet.
Credentials are saved locally to:
```
//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
│ └── / # Environment-specific directory (e.g. dev-me)
│ ├── certs/ # TLS certificates and keys
│ │ ├── rootCA.pem # Root CA certificate
│ │ ├── .pem # Domain certificate
│ │ ├── -key.pem # Domain private key
│ │ └── -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 `.loko` directory 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:
```bash
loko workload list
```
Filter by type or status:
```bash
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:
```bash
# 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 --selector` under the hood.
### Workload Types and DNS Structure
1. **System Workloads** (`workload.network.domain`):
- Core infrastructure workloads (databases, message queues, etc.)
- Direct DNS resolution (e.g., `mysql.dev.me`, `postgres.dev.me`)
2. **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.enabled` setting
3. **Internal Components**:
- Registry (e.g., `cr.dev.me`)
- Traefik ingress controller
- DNS service (dnsmasq)
- Metrics server (optional)
### Accessing Workloads
Once the environment is running, workloads are accessible through:
1. **Direct Port Access**:
```bash
# Example for PostgreSQL
psql -h localhost -p 5432 -U postgres
```
2. **Domain Names**:
```bash
# Example for system workload
psql -h postgres.dev.me -U postgres
```
3. **Workload Credentials**:
- Passwords are automatically generated and stored in `//workload-secrets.txt`
- Or fetch them with: `loko secret show`
### Using the Local Container Registry
The environment includes a local container registry accessible at `.`.
1. **Push Images**:
```bash
docker tag myapp:latest cr.dev.me/myapp:latest
docker push cr.dev.me/myapp:latest
```
2. **Use in Kubernetes**:
```yaml
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`:
```yaml
cluster:
nodes:
labels:
control-plane:
tier: "infrastructure"
worker:
tier: "application"
```
### Scheduling Configuration
Control workload placement with the scheduling section:
```yaml
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:
```bash
loko validate
```
This runs a comprehensive check including:
1. Cluster status and node readiness
2. DNS service health
3. System pods status
4. Kubectl connectivity
5. **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:
```bash
# 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
```yaml
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:
```bash
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/` entry so lookups continue to work.
## Troubleshooting
1. **DNS Resolution Issues**
- Run DNS diagnostics: `loko config dns-check`
- Verify local DNS container is running: `loko status`
- Check DNS configuration: `cat /etc/resolver/`
2. **Certificate Issues**
- Regenerate certificates: `loko init` (will re-run certificate setup)
- Verify cert location: `ls //certs/`
3. **Workload Access Issues**
- Validate environment: `loko validate`
- Verify ingress: `kubectl get ingress -A`
- Check credentials: `loko secret show`
4. **OCI Registry Issues**
- Test registry connectivity: `docker pull cr.dev.me/test:latest`
- Run validation: `loko validate`
5. **Version Upgrade Issues**
- Restore from backup: `mv loko-prev.yaml loko.yaml`
- Check loko-updater comment syntax in config file
6. **Port Conflicts**
- Check what's using a port: `sudo lsof -i :53` (macOS) or `sudo netstat -tlnp | grep :53` (Linux)
- Change the DNS port in config: `network.dns-port: 5353`
## Development
### Setup
```bash
git clone https://github.com/bojanraic/loko.git
cd loko
uv sync
uv run loko --help
```
### Running Tests
```bash
# 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
```bash
uv run ruff check loko/
uv run ruff format loko/
```
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.