KRules CLI
Krules CLI is a tool allow you to quickly create a project based on KRules and organize your microservices in a hierarchical structure.
Initial steps
Init project tree
To initialize a new Project run:
krules-py project init your/project/path
To generate default profile some params must be prompted, but sometimes you need to avoid user interaction, maybe because you want integrate a CI/CD solution. This could be achieved using this optional params:
- --name [default current folder name]: set project name;
- -n --namespace [default default] : set in which namespace will be deployed your components;
- -d --docker-registry. : set docker registry with which to push and deploy your image;
- -i --image-base : override ruleset image base.
Example
krules-py project init . --name my-project
The output will be:
. my-project │ ├── base │ │ │ ├── Dockerfile │ ├── ipython_config.py │ ├── Makefile │ ├── VERSION │ ├── app │ │ │ │ │ ├── env.py │ │ └── app_functions │ │ │ │ │ └── __init__.py │ └── k8s │ │ │ ├── brokers.yaml │ ├── config-krules.yaml │ ├── config-krules-subjects-mongodb.yaml │ ├── config-krules-subjects-mongodb-auth.yaml │ ├── config-krules-subjects-redis.yaml │ ├── config-krules-subjects-redis-auth.yaml │ ├── event-display.yaml │ ├── kustomization.yaml │ └── triggers.yaml └── rulesets │ └── patches.yaml
Config subject storage support
The next step is to choose the subject storage support.
The default storage class can be used just for local testing so you have to use another one in production environment, at now you can choose between redis and mongodb
Go to base/app/env.py to enable your preferred storage support.
First of all remove the default implementation:
from krules_core.tests.subject.sqlite_storage import SQLLiteSubjectStorage
subject_storage_factory.override(
providers.Factory(lambda x: SQLLiteSubjectStorage(x, ":memory:"))
)
If, for example, you want to use redis support uncomment this code part:
# Redis subjects storage support
subjects_redis_storage_settings = settings_factory() \
.get("subjects-backends") \
.get("redis")
from redis_subjects_storage import storage_impl as redis_storage_impl
subject_storage_factory.override(
providers.Factory(
lambda x: redis_storage_impl.SubjectsRedisStorage(x, subjects_redis_storage_settings.get("url"))
)
)
Then in base/k8s update ConfigMap and authorization data related to the storage support you choose. Continuing with redis example.
config-krules-subject-redis-auth.yaml
apiVersion: v1
data:
password: cGFzc3dvcmQ= # replace with your redis password in base64 format
kind: Secret
metadata:
name: config-krules-subjects-redis-auth
type: Opaque
config-krules-subject-redis.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: config-krules-subjects-redis
data:
config_subjects_redis.yaml: |
url: redis://:${KRULES_SUBJECTS_REDIS_PASSWORD}@redis.address/0 # replace with your redis address
Remember to include them in the kustomization.yaml.
The last step is to make those configurations known to your rulesets.
In rulesets/patches.yaml uncomment the patch related to your chosen storage support.
## Redis subjects backend
kinds:
- serving.knative.dev/v1beta1:Service
- apps/v1:Deployment
labelsMatch:
- airspot.krules.dev/type: ^ruleset$
patch:
spec:
template:
spec:
containers:
- patch__0:
env:
- name: KRULES_SUBJECTS_REDIS_PASSWORD
valueFrom:
secretKeyRef:
name: config-krules-subjects-redis-auth
key: password
volumeMounts:
- name: config-krules-subjects-redis-volume
mountPath: /krules/config/subjects-backends/redis
volumes:
- name: config-krules-subjects-redis-volume
configMap:
name: config-krules-subjects-redis
Build and push base image
Go to base folder and run make.
make command will take care of each needed operation to build and push your base image correctly. You can also run each step individually:
- VERSION: Detect changes checking your Dockerfile and each your .py file in the base/app folder and possibly build a new base image version;
- push: If there is a new image build in your local registry push it to your Docker repository;
- .lastResources: Apply all yaml in k8s folder to your namespace.
- clean: Clean all files generated by make command, useful to relaunch it without make any changes to your files.
Working with Rulesets
Init Ruleset tree
To create a new Ruleset go to rulesets folder and run:
krules-py ruleset create my-ruleset
The output will be:
. my-ruleset │ ├── Dockerfile.origin ├── Makefile ├── VERSION ├── app │ │ │ └── rules.py └── k8s │ ├── kustomization.yaml └── service.yaml
Deploy your Ruleset
To deploy your code on Kubernetes got to your ruleset folder and run make. make command will take care of each needed operation to deploy your ruleset correctly detecting files changes.
You can also run each step individually:
- Dockerfile: Detect changes in your Dockerfile.origin and generate a new Dockerfile if needed.
So, if you want to change the Dockerfile don't modify directly it but edit the Dockerfile.origin; - VERSION: Detect changes checking your Dockerfile and each your .py file in the rulesset app folder and possibly build a new rulesset image version; - push: If there is a new image build in your local registry push it to your Docker repository; - .lastResources: Apply all yaml in k8s folder to your namespace. - clean: Clean all files generated by make command, useful to relaunch it without make any changes to your files.
Each ruleset inherit your project image base, so if you change it you have to redeploy your ruleset using:
make clean && make
Generate your Ruleset manifest (using kustomize)
The KRules CLI integrate kubectl kustomize. command. In added to the kustomize standard functions, it provide to the user another patches logic.
Usage:
krules-py ruleset patch
patch command apply each patches.yaml file from the project root to the ruleset folder, so it is possible to define some patches shared by all rulesets or by group of ruleset.
Example:
. rulesets │ ├── patches.yaml ├── my-group │ │ │ ├── my-ruleset-2/ │ ├── my-ruleset-3/ │ ├── my-ruleset-4/ │ └── patches.yaml └── my-ruleset-1 │ ... ├── kustomization.yaml └── service.yaml
rulesets/patches.yaml will be applied to all rulesets, while rulesets/my-group/patches.yaml will modified just the rulesets inside my-group folder
Custom path
patch command search for kustomization file in the current folder or in k8s one. If you put your file in another path you can use the path parameter
Usage:
krules-py ruleset patch -p [--path] custom/path
Warning
path param refer to folder containing the kustomization file not to the file itself.
How to use
Basic Usage
Supposing you define this 3 files:
service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
template:
spec:
contatiners:
- name: my-container
---
triggers/my-trigger.yaml
apiVersion: eventing.knative.dev/v1alpha1
kind: Trigger
metadata:
name: my-trigger
kustomization.yaml
commonLabels:
airspot.krules.dev/ruleset: my-ruleset
resources:
- service.yaml
- triggers/my-trigger.yaml
You can override the previous components creating a file named patches.yaml in some of parent folders
kinds:
- v1:Service
- serving.knative.dev/v1alpha1:Service
patch:
metadata:
labels:
app: my-app
---
kinds:
- serving.knative.dev/v1alpha1:Trigger
patch:
spec:
broker: my-broker
kinds : list of kinds of components will be affected from the patch. Format: : patch : list of field will be modify with this patch labelsMatch: list of regex to filter components by metadata labels.
The output will be:
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
airspot.krules.dev/ruleset: my-ruleset
app: my-app
spec:
template:
spec:
contatiners:
- name: my-container
---
apiVersion: eventing.knative.dev/v1alpha1
kind: Trigger
metadata:
name: my-trigger
labels:
airspot.krules.dev/ruleset: my-ruleset
spec:
broker: my-broker
---
Adding a second container
To add element to a list just define the new elements in the patch inside the list key.
service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
template:
spec:
contatiners:
- name: my-first-container
---
patches.yaml
kinds:
- v1:Service
- serving.knative.dev/v1alpha1:Service
patch:
spec:
template:
spec:
containers:
- name: my-second-container
Output:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
template:
spec:
contatiners:
- name: my-first-container
- name: my-second-container
---
Adding volumeMount just to a specific container
To override a single list element use patch__<index> keyword, where index indicates the index of the element of the list to be modified.
service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
template:
spec:
contatiners:
- name: my-first-container
- name: my-second-container
- name: my-third-container
---
patches.yaml
kinds:
- v1:Service
- serving.knative.dev/v1alpha1:Service
labelsMatch:
- app: my-app
patch:
spec:
template:
spec:
containers:
- patch__1:
volumeMounts:
- name: my-volume
mountPath: /configs/
volumes:
- name: my-volume
configMap:
name: my-config
Output:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
template:
spec:
contatiners:
- name: my-first-container
- name: my-second-container
volumeMounts:
- name: my-volume
mountPath: /configs/
- name: my-third-container
volumes:
- name: my-volume
configMap:
name: my-config
---
Update a specific container image
service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
template:
spec:
containers:
- name: my-container
- name: my-other-container
---
krules-py ruleset patch set-image my-container=my-docker-registry/my-image:latest
Output:
service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
template:
spec:
containers:
- name: my-container
image: my-docker-registry/my-image:latest
- name: my-other-container
---
Custom ruleset template
It is possible that default ruleset template does not completely satisfy your requirements. You can override it using:
krules-py gen-rs-template your_template_dir [--set-default]
The selected template directory must be contained in your project. ** --set-default ** flag set your directory as the default one for each ruleset. The output will be:
. your_template_dir │ ├── Dockerfile.origin ├── Makefile ├── VERSION ├── app │ │ │ └── rules.py └── k8s │ ├── kustomization.yaml ├── service.yaml └── triggers.yaml
To reset default rulesets template folder use:
krules-py gen-rs-template --unset-default
Managing Version
Both base and rulesets folders contains a file VERSION. This file contains your current local image version. When you run make in a ruleset folder your local image will be deployed only if its version is greater than the cluster one.
Adding triggers
To work properly a rule must be registered to a trigger. To create a new trigger run
krules-py trigger create my-trigger
Output:
triggers.yaml
apiVersion: eventing.knative.dev/v1beta1
kind: Trigger
metadata:
name: my-trigger
spec:
filter:
attributes:
type: my-ruleset-my-trigger
subscriber:
ref:
apiVersion: v1
kind: Service
name: my-ruleset
---
This command updates the file triggers.yaml located in k8s folder. If the file does not exist a new one will be created.
You could have some particular requirements for your trigger.
If, for example, you want to add a filter for a certain type run:
krules-py trigger create my-type-trigger --type my-type
Output:
triggers.yaml
apiVersion: eventing.knative.dev/v1beta1
kind: Trigger
metadata:
name: my-type-trigger
spec:
filter:
attributes:
type: my-type
subscriber:
ref:
apiVersion: v1
kind: Service
name: my-ruleset
---
Another interesting feature could be raise a trigger when a property is changed. To achieve this run:
krules-py trigger create my-property-trigger --on-propchange my-property
Output:
triggers.yaml
apiVersion: eventing.knative.dev/v1beta1
kind: Trigger
metadata:
name: my-property-trigger
spec:
filter:
attributes:
propertyname: my-property
type: subject-property-changed
subscriber:
ref:
apiVersion: v1
kind: Service
name: my-ruleset
---
With CLI you can also create a trigger with your custom attributes running:
krules-py trigger create my-custom-trigger --attrs key1=val1 key2=val2
Output:
triggers.yaml
apiVersion: eventing.knative.dev/v1beta1
kind: Trigger
metadata:
name: my-custom-trigger
spec:
filter:
attributes:
key1: val1
key2: val2
subscriber:
ref:
apiVersion: v1
kind: Service
name: my-ruleset
---
Managing profiles
The KRules CLI provides also a profiles handler. A profile contains all useful defaults value as docker registry and kubernetes namespace.
Add new profile
krules-py profile add myProfile
Optional arguments
- --set-default: set the new profile as the default one;
- -ns --namespace: set profile namespace;
- -d --docker-registry: set profile Docker registry.
Set/Get default profile
$ krules-py profile set myProfile
$
$ krules-py profile get
$ myProfile
To list all available profiles run
krule-py profile list
Set/Get profile value
$ krule-py profile set-value namespace myNamespace
$
$ krule-py profile get-value namespace
$ myNamespace
To print all profile values run
krule-py profile values