A robust and flexible local Kubernetes development environment setup using KinD, with support for local container registry, DNS resolution, HTTPS certificates, and various development services.
- π Quick and easy local Kubernetes cluster setup using KinD
- π¦ Built-in local container registry with TLS support
- π Automatic TLS certificate generation for local domains
- π Local wildcard DNS resolution for
<local-domain>
(configurable) domain - π§ Support for common development services:
- PostgreSQL
- MySQL
- MongoDB
- RabbitMQ
- Dragonfly (Redis-compatible)
- π οΈ Helm-based service deployment
- βοΈ Configurable via single YAML file
- π Automated dependency management with Renovate
The following are required:
- ο£Ώ macOS or π§ Linux (recent Ubuntu or Ubuntu-based distribution)
- π³ Docker (or docker-compatible runtime, e.g. OrbStack)
- π§° mise for tool version management
- (optional) nss (for macOS) or libnss3-tools (for Linux)
[!IMPORTANT] nss is needed to automatically trust mkcert-generated certificates in Firefox
NOTES:
- Podman is not supported yet as it is not a first-class citizen with KinD
- Ubuntu 24.04 and Pop!_OS 24.04 are tested and known to work, although distros with a standard systemd might work as well
All other dependencies are automatically managed by mise:
- π Python
- π¦ kubectl
- π¦ kind
- π¦ Helm
- π¦ Helmfile
- π¦ mkcert
- π¦ go-task
- π¦ yq
- π¦ kustomize
- π¦ kubeconform
- Clone this repository:
git clone <repository-url>
cd <repository-name>
- Install mise and initialize the environment:
# Install mise (if not already installed)
curl https://mise.run | sh
- Activate mise
Follow the instructions here to activate mise for your shell.
- Re-open your terminal, navigate to the project root directory and verify the mise environment:
mise trust
mise doctor
- Install tools, create Python virtual environment and install dependencies
mise install
mise run deps
- Configure your environment by editing
k8s-env.yaml
:
environment:
name: my-local-env
local-ip: 192.168.1.123 # Change to your IP; can't be 127.0.0.1
local-domain: me.local # Change if desired
- Create the environment:
task create-env
- Verify the setup:
task validate-env
.
βββ k8s-env.yaml # Main configuration file
βββ .mise.toml # Tool version management
βββ templates/ # Jinja2 templates for configuration
β βββ containerd/ # Containerd configuration templates
β βββ dnsmasq/ # DNSmasq configuration templates
β βββ helmfile/ # Helmfile configuration templates
β βββ kind/ # KinD cluster configuration templates
β βββ service_presets.yaml # Service presets and default values
βββ .local/ # Runtime data (git-ignored)
βββ .taskfiles/ # Task definitions
βββ generate_configs.py # Python script for generating configuration files
βββ Taskfile.yaml # Main task definitions
The templates/
directory contains all Jinja2 templates used to generate configurations:
containerd/
: Container runtime configurationscoredns/
: Kubernetes DNS service configurationsdnsmasq/
: Local DNS resolver configurationshelmfile/
: Helm release definitionskind/
: Kubernetes cluster configurationstests/
: Validation test configurationspresets.yaml
: Default service configurations and ports
The environment is configured through k8s-env.yaml
. Key configuration options:
name
: Environment name (used for cluster and resource naming)base-dir
: Directory for storing cluster data and configslocal-ip
: Your local machine's IP addresslocal-domain
: Domain for local servicesnodes
: Control plane and worker node countservices
: Enable/disable and configure development services
To view the full list of configuration options, review the comments in the k8s-env.yaml
file.
Use task --list
to see all available tasks. Main tasks include:
task create-env
: Create the complete environmenttask destroy-env
: Tear down the environmenttask recreate-env
: Rebuild the environment from scratchtask start-env
: Start a stopped environmenttask stop-env
: Stop the environmenttask validate-env
: Validate the environment setup
.
βββ k8s-env.yaml # Main configuration file
βββ .local/ # Default directory for cluster data and configs
β βββ <env-name>/ # Environment-specific directory (e.g. my-local-env)
β βββ 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.yaml # Container runtime config
β β βββ dnsmasq.conf # Local DNS configuration
β β βββ helmfile.yaml # Helm releases definition
β βββ logs/ # Kubernetes node logs
β β βββ control-0/ # Control plane logs
β β βββ worker-0/ # Worker node logs
β βββ storage/ # Persistent volume data
β β βββ control-0/ # Control plane storage
β β βββ worker-0/ # Worker node storage
β βββ kubeconfig # Cluster access configuration
β βββ service-secrets.txt # Generated service credentials
βββ .taskfiles/ # Task definitions and variables
β βββ help/ # Help tasks
β βββ kubernetes/ # Kubernetes-related tasks
β βββ validate/ # Validation tasks
β βββ vars/ # Common variables used in tasks
βββ tests/ # Test files for validation
βββ Taskfile.yaml # Main task definitions
The .local
directory (configurable via base-dir
in k8s-env.yaml
) is created when you first run task create-env
and contains all runtime data and configurations. Key points about the .local
directory:
- Location: By default, it's created in the project root but can be configured via
base-dir
ink8s-env.yaml
- Persistence: Contains all persistent data, including certificates, logs, and storage
- Environment Isolation: Each environment gets its own subdirectory (e.g.,
.local/my-local-env/
) - Backup: You may want to back up the
certs
andconfig
directories - Cleanup: The entire
.local
directory can be safely deleted to start fresh
Note: The
.local
directory is git-ignored by default. If you need to preserve any configurations, consider committing them to a separate repository, being mindful of any sensitive data, such as passwords/keys/secrets/etc.
Services are defined in two places:
k8s-env.yaml
: Service enablement and specific configurationstemplates/service_presets.yaml
: Default service configurations and ports
The service_presets.yaml
file defines default configurations for supported services:
service_ports:
mysql: 3306
postgres: 5432
# ... other service ports
service_values_presets:
mysql:
fullNameOverride: mysql
nameOverride: mysql
# ... other default values
Once the environment is running, services are accessible through:
-
Direct Port Access:
# Example for PostgreSQL psql -h localhost -p 5432 -U postgres
-
Domain Names:
# Example for PostgreSQL psql -h postgres.me.local -U postgres
NOTE: DNS resolution is handled by the local DNSMasq container, which is automatically started when you create or start the environment. It will resolve any hostname with the
<local-domain>
to the local IP address. This means that you can use any hostname to access the services via corresponding ports. The advice is to use the service name as the hostname, for examplepostgres.me.local
orrabbitmq.me.local
instead oflocalhost
. One additional advantage is that TLS certificates are automatically generated and trusted for the<local-domain>
and can be used for the services.
- Service Credentials:
- Passwords for password-protected services are automatically generated and stored in
<local-dir>/<env-name>/service-secrets.txt
- View them with:
cat <local-dir>/<env-name>/service-secrets.txt
- Passwords for password-protected services are automatically generated and stored in
The environment includes a local container registry accessible at <registry-name>.<local-domain>
. The value is configurable via registry.name
in k8s-env.yaml
.
To use it:
-
Push Images:
# Tag your image, for example: docker tag myapp:latest cr.me.local/myapp:latest # Push the image to your local registry, for example: docker push cr.me.local/myapp:latest
-
Use in Kubernetes:
Example deployment YAML:
# Example deployment apiVersion: apps/v1 kind: Deployment spec: template: spec: containers: - name: myapp image: cr.me.local/myapp:latest
Note: Replace
me.local
with your configuredlocal-domain
value fromk8s-env.yaml
-
DNS Resolution Issues
- Verify local DNS container is running:
docker ps | grep <env-name>-dns
- Check DNS configuration:
cat /etc/resolver/<your-domain>
- Verify local DNS container is running:
-
Certificate Issues
- Regenerate certificates:
task setup-certificates
- Verify cert location:
ls <local-dir>/<your-domain>/certs/
- Regenerate certificates:
-
Service Access Issues
- Validate TCP connectivity:
task validate:tcp-services
- Verify ingress:
kubectl get ingress -A
- Validate TCP connectivity:
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Commit your changes
- Push to your branch
- Create a Pull Request