Skip to main content

Working with Modules

Modules are the building blocks of KubeZero. They are reusable, self-contained components that can be combined to create complete platform solutions. This guide shows you how to work with existing modules and create your own.

Understanding Modules

A module in KubeZero is a directory containing Kubernetes manifests, Helm charts, or Kustomize configurations that represent a specific technology or service.

Module Structure

modules/my-module/
├── kustomization.yaml # Kustomize configuration
├── namespace.yaml # Namespace definition
├── values.yaml # Helm chart values (if using Helm)
├── configmap.yaml # Configuration maps
├── secret.yaml # Secrets (base templates only)
└── README.md # Documentation

Module Characteristics

  • Self-contained: Can be deployed independently
  • Reusable: Used across multiple stacks and environments
  • Technology-focused: Represents a specific tool or service
  • Environment-agnostic: No hardcoded environment-specific values

Using Existing Modules

Available Modules

KubeZero comes with several pre-built modules:

  • argo-cd: GitOps continuous delivery platform
  • cert-manager: Automatic TLS certificate management
  • crossplane: Infrastructure as code
  • external-dns: Automatic DNS record management
  • external-secrets: External secret management integration
  • ingress-nginx: HTTP/HTTPS ingress controller
  • vcluster: Virtual Kubernetes clusters

Referencing Modules in Stacks

To use a module in a stack, reference it in your kustomization.yaml:

# stacks/my-stack/manifests/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../../modules/ingress-nginx
- ../../../modules/cert-manager
- ../../../modules/external-dns

namespace: my-stack

Customizing Module Behavior

You can customize modules using Kustomize patches:

# stacks/my-stack/manifests/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- ../../../modules/cert-manager

patches:
- target:
kind: ClusterIssuer
name: letsencrypt-prod
patch: |-
- op: replace
path: /spec/acme/email
value: [email protected]
- op: add
path: /spec/acme/solvers/0/dns01
value:
route53:
region: us-west-2

Creating Custom Modules

Step 1: Create Module Directory

mkdir -p modules/my-custom-service
cd modules/my-custom-service

Step 2: Create Basic Structure

Create the basic files for your module:

kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- namespace.yaml
- deployment.yaml
- service.yaml
- configmap.yaml

commonLabels:
app.kubernetes.io/name: my-custom-service
app.kubernetes.io/managed-by: kubezero
app.kubernetes.io/part-of: kubezero-platform

namespace: my-custom-service

namespace.yaml

apiVersion: v1
kind: Namespace
metadata:
name: my-custom-service
labels:
name: my-custom-service

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: my-custom-service
namespace: my-custom-service
spec:
replicas: 3
selector:
matchLabels:
app: my-custom-service
template:
metadata:
labels:
app: my-custom-service
spec:
containers:
- name: my-custom-service
image: my-custom-service:latest
ports:
- containerPort: 8080
env:
- name: CONFIG_PATH
value: /etc/config/app.yaml
volumeMounts:
- name: config
mountPath: /etc/config
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "100m"
volumes:
- name: config
configMap:
name: my-custom-service-config

service.yaml

apiVersion: v1
kind: Service
metadata:
name: my-custom-service
namespace: my-custom-service
spec:
selector:
app: my-custom-service
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
type: ClusterIP

configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
name: my-custom-service-config
namespace: my-custom-service
data:
app.yaml: |
server:
port: 8080
host: 0.0.0.0
logging:
level: info
format: json
features:
metrics: true
health_checks: true

Step 3: Add Helm Support (Optional)

If your module uses Helm charts, modify the kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- namespace.yaml

helmCharts:
- name: my-custom-service
repo: https://charts.example.com
version: 1.0.0
namespace: my-custom-service
valuesFile: values.yaml

commonLabels:
app.kubernetes.io/managed-by: kubezero

Create values.yaml for Helm customization:

# values.yaml
replicaCount: 3

image:
repository: my-custom-service
tag: latest
pullPolicy: IfNotPresent

service:
type: ClusterIP
port: 80
targetPort: 8080

ingress:
enabled: false
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: my-service.example.com
paths:
- path: /
pathType: Prefix

resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "100m"

autoscaling:
enabled: false
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 80

Step 4: Add Documentation

Create a README.md file for your module:

# My Custom Service Module

This module deploys My Custom Service, a sample application for demonstrating KubeZero module development.

## Features

- Highly available deployment with 3 replicas
- Health checks and monitoring endpoints
- Configurable through ConfigMaps
- Resource limits and requests defined
- Optional ingress support

## Configuration

### Basic Configuration

The service can be configured through the `my-custom-service-config` ConfigMap:

```yaml
server:
port: 8080
host: 0.0.0.0
logging:
level: info
format: json

Using in Stacks

Reference this module in your stack:

# stacks/my-stack/manifests/kustomization.yaml
resources:
- ../../../modules/my-custom-service

Customization Examples

Enable ingress:

patches:
- target:
kind: Service
name: my-custom-service
patch: |-
- op: add
path: /metadata/annotations
value:
external-dns.alpha.kubernetes.io/hostname: my-service.example.com

Scale replicas:

patches:
- target:
kind: Deployment
name: my-custom-service
patch: |-
- op: replace
path: /spec/replicas
value: 5

Dependencies

  • Kubernetes 1.20+
  • Optional: Ingress controller for ingress support
  • Optional: External-DNS for automatic DNS management

## Advanced Module Patterns

### Multi-Component Modules

Some modules might include multiple related components:

modules/monitoring-stack/ ├── kustomization.yaml ├── namespace.yaml ├── prometheus/ │ ├── deployment.yaml │ ├── service.yaml │ └── configmap.yaml ├── grafana/ │ ├── deployment.yaml │ ├── service.yaml │ └── configmap.yaml └── alertmanager/ ├── deployment.yaml ├── service.yaml └── configmap.yaml


```yaml
# modules/monitoring-stack/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- namespace.yaml
- prometheus/deployment.yaml
- prometheus/service.yaml
- prometheus/configmap.yaml
- grafana/deployment.yaml
- grafana/service.yaml
- grafana/configmap.yaml
- alertmanager/deployment.yaml
- alertmanager/service.yaml
- alertmanager/configmap.yaml

commonLabels:
app.kubernetes.io/name: monitoring-stack
app.kubernetes.io/managed-by: kubezero

Configurable Modules

Make modules configurable through replacements:

# modules/database/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
- deployment.yaml
- service.yaml

replacements:
- source:
kind: ConfigMap
name: database-config
fieldPath: data.database_name
targets:
- select:
kind: Deployment
name: database
fieldPaths:
- spec.template.spec.containers.[name=database].env.[name=DATABASE_NAME].value

Conditional Components

Use Kustomize components for optional features:

modules/web-app/
├── kustomization.yaml
├── base/
│ ├── deployment.yaml
│ └── service.yaml
└── components/
├── ingress/
│ ├── kustomization.yaml
│ └── ingress.yaml
└── monitoring/
├── kustomization.yaml
├── servicemonitor.yaml
└── grafana-dashboard.yaml
# modules/web-app/components/ingress/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1alpha1
kind: Component

resources:
- ingress.yaml

Testing Modules

Local Testing

Test your module locally before using it in stacks:

# Test the module
kubectl apply --dry-run=client -k modules/my-custom-service

# Apply to a test namespace
kubectl apply -k modules/my-custom-service

# Verify deployment
kubectl get pods -n my-custom-service
kubectl get services -n my-custom-service

Validation Scripts

Create validation scripts for your modules:

#!/bin/bash
# test-module.sh

MODULE_NAME="my-custom-service"
NAMESPACE="test-${MODULE_NAME}"

echo "Testing module: ${MODULE_NAME}"

# Create test namespace
kubectl create namespace ${NAMESPACE} --dry-run=client -o yaml | kubectl apply -f -

# Apply module with test namespace
cat modules/${MODULE_NAME}/kustomization.yaml | \
sed "s/namespace: ${MODULE_NAME}/namespace: ${NAMESPACE}/" | \
kubectl apply -f -

# Wait for deployment
kubectl wait --for=condition=available --timeout=300s deployment/${MODULE_NAME} -n ${NAMESPACE}

# Test connectivity
kubectl port-forward -n ${NAMESPACE} svc/${MODULE_NAME} 8080:80 &
PF_PID=$!
sleep 5

# Make test request
curl -f http://localhost:8080/health || exit 1

# Cleanup
kill ${PF_PID}
kubectl delete namespace ${NAMESPACE}

echo "Module test passed!"

Module Versioning

Semantic Versioning

Tag your modules with semantic versions:

# Tag a module version
git tag modules/my-custom-service/v1.0.0
git push origin modules/my-custom-service/v1.0.0

Version Pinning in Stacks

Pin to specific module versions:

# stacks/production/manifests/kustomization.yaml
resources:
- https://github.com/kubezero/kubezero/modules/my-custom-service?ref=v1.0.0

Best Practices

1. Keep Modules Focused

Each module should have a single responsibility:

Don't: Create a module that includes web server + database + cache ✅ Do: Create separate modules for web-server, database, and cache

2. Use Appropriate Labels

Always include standard Kubernetes labels:

commonLabels:
app.kubernetes.io/name: my-service
app.kubernetes.io/instance: my-service-prod
app.kubernetes.io/version: "1.0.0"
app.kubernetes.io/component: web-server
app.kubernetes.io/part-of: my-application
app.kubernetes.io/managed-by: kubezero

3. Include Resource Limits

Always define resource requests and limits:

resources:
requests:
memory: "64Mi"
cpu: "50m"
limits:
memory: "128Mi"
cpu: "100m"

4. Add Health Checks

Include liveness and readiness probes:

livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5

5. Use ConfigMaps for Configuration

Externalize configuration using ConfigMaps:

env:
- name: CONFIG_FILE
value: /etc/config/app.yaml
volumeMounts:
- name: config
mountPath: /etc/config
volumes:
- name: config
configMap:
name: my-service-config

6. Security Considerations

  • Never include secrets directly in modules
  • Use service accounts with minimal permissions
  • Run containers as non-root users
  • Use security contexts and pod security standards
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
capabilities:
drop:
- ALL

Common Patterns

Database Modules

# Example: PostgreSQL module
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgresql
spec:
serviceName: postgresql
replicas: 1
template:
spec:
containers:
- name: postgresql
image: postgres:15
env:
- name: POSTGRES_DB
valueFrom:
configMapKeyRef:
name: postgresql-config
key: database_name
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgresql-secret
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgresql-secret
key: password
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi

Web Application Modules

# Example: Web application with ingress
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:
replicas: 3
template:
spec:
containers:
- name: webapp
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: config
mountPath: /etc/nginx/conf.d
volumes:
- name: config
configMap:
name: webapp-config
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: webapp
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
external-dns.alpha.kubernetes.io/hostname: webapp.example.com
spec:
tls:
- hosts:
- webapp.example.com
secretName: webapp-tls
rules:
- host: webapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp
port:
number: 80

Troubleshooting Modules

Common Issues

  1. Resource conflicts: Ensure unique names and labels
  2. Missing dependencies: Document and validate dependencies
  3. Permission issues: Check RBAC and security contexts
  4. Configuration errors: Validate ConfigMaps and environment variables

Debugging Commands

# Check module application
kubectl apply --dry-run=client -k modules/my-module

# Validate resources
kubectl get all -n my-module-namespace

# Check logs
kubectl logs -l app=my-module -n my-module-namespace

# Describe resources for events
kubectl describe deployment my-module -n my-module-namespace

Next Steps

Modules are the foundation of KubeZero's flexibility and reusability. Master them to build powerful, maintainable platform solutions.