Skip to content

Commit

Permalink
Improve self-presentation on the main page with all the features
Browse files Browse the repository at this point in the history
  • Loading branch information
nolar committed Aug 18, 2020
1 parent 97058d8 commit 5288f1a
Showing 1 changed file with 80 additions and 36 deletions.
116 changes: 80 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/nolar/kopf.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/nolar/kopf/context:python)

**Kopf** —Kubernetes Operator Pythonic Framework— is a framework and a library
to make Kubernetes operators development easier, just in few lines of Python code.
to make Kubernetes operators development easier, just in a few lines of Python code.

The main goal is to bring the Domain-Driven Design to the infrastructure level,
with Kubernetes being an orchestrator/database of the domain objects (custom resources),
and the operators containing the domain logic (with no or minimal infrastructure logic).

The project was originally started as `zalando-incubator/kopf` in March 2019,
and then forked as `nolar/kopf`: but it is the same codebase, the same packages,
the same developer(s).
and then forked as `nolar/kopf` in August 2020: but it is the same codebase,
the same packages, the same developer(s).


## Documentation
Expand All @@ -25,54 +25,98 @@ the same developer(s).

## Features

* A full-featured operator in just 2 files: `Dockerfile` + a Python module.
* Implicit object's status updates, as returned from the Python functions.
* Multiple creation/update/deletion handlers to track the object handling process.
* Update handlers for the selected fields with automatic value diffs.
* Dynamically generated sub-handlers using the same handling tracking feature.
* Retries of the handlers in case of failures or exceptions.
* Easy object hierarchy building with the labels/naming propagation.
* Built-in _events_ for the objects to reflect their state (as seen in `kubectl describe`).
* Automatic logging/reporting of the handling process (as logs + _events_).
* Handling of multiple CRDs in one process.
* The development instance temporarily suppresses the deployed ones.
* Simple, but powerful:
* A full-featured operator in just 2 files: a `Dockerfile` + a Python file (*).
* Handling functions registered via decorators with declarative approach.
* No infrastructure boilerplate code with K8s API communication.
* Both sync and async handlers, with sync ones being threaded under the hood.
* Detailed documentation with examples.
* Intuitive mapping of Python concepts to Kubernetes concepts and back:
* Marshalling of resources' data to the handlers' kwargs.
* Marshalling of handlers' results to the resources' statuses.
* Publishing of logging messages as Kubernetes events linked to the resources.
* Support anything that exists in K8s:
* Custom K8s resources, obviously.
* Builtin K8s resources (pods, namespaces, etc).
* Multiple resource types in one operator.
* Both cluster and namespaced operators.
* All the ways of handling that a developer can wish for:
* Low-level handlers for events received from K8s APIs "as is" (an equivalent of _informers_).
* High-level handlers for detected causes of changes (creation, updates with diffs, deletion).
* Handling of selected fields only instead of the whole objects (if needed).
* Dynamically generated or conditional sub-handlers (an advanced feature).
* Timers that tick as long as the resource exists, optionally with a delay since the last change.
* Daemons that run as long as the resource exists (in threads or asyncio-tasks).
* Filtering with stealth mode (no logging): by arbitrary filtering functions,
by labels/annotations with values, presence/absence, or dynamic callbacks.
* In-memory all-purpose containers to store non-serializable objects for individual resources.
* Eventual consistency of handling:
* Retrying the handlers in case of arbitrary errors until they succeed.
* Special exceptions to request a special retry or to never retry again.
* Custom limits for the number of attempts or the time.
* Implicit persistence of the progress that survives the operator restarts.
* Tolerance to restarts and lengthy downtimes: handles the changes afterwards.
* Awareness of other Kopf-based operators:
* Configurable identities for different Kopf-based operators for the same resource kinds.
* Avoiding of double-processing due to cross-pod awareness of the same operator ("peering").
* Pausing of a deployed operator when a dev-mode operator runs outside of the cluster.
* Extra toolkits and integrations:
* Some limited support for object hierarchies with name/labels propagation.
* Friendly to any K8s client libraries (and is client agnostic).
* Startup/cleanup operator-level handlers.
* Liveness probing endpoints and rudimentary metrics exports.
* Basic testing toolkit for in-memory per-test operator running.
* Embeddable into other Python applications.
* Highly configurable (to some reasonable extent).

(*) _Small font: two files of the operator itself, plus some amount of
deployment files like RBAC roles, bindings, service accounts, network policies
— everything needed to deploy an application in your specific infrastructure._


## Examples

See [examples](https://github.com/nolar/kopf/tree/master/examples)
for the examples of the typical use-cases.

The minimalistic operator can look like this:
A minimalistic operator can look like this:

```python
import kopf

@kopf.on.create('zalando.org', 'v1', 'kopfexamples')
def create_fn(spec, meta, status, **kwargs):
print(f"And here we are! Creating: {spec}")
def create_fn(spec, name, meta, status, **kwargs):
print(f"And here we are! Created {name} with spec: {spec}")
```

The keyword arguments available to the handlers:
Numerous kwargs are available, such as `body`, `meta`, `spec`, `status`,
`name`, `namespace`, `retry`, `diff`, `old`, `new`, `logger`, etc:
see [Arguments](https://kopf.readthedocs.io/en/latest/kwargs/)

* `body` for the whole body of the handled objects.
* `spec` as an alias for `body['spec']`.
* `meta` as an alias for `body['metadata']`.
* `status` as an alias for `body['status']`.
* `patch` is a dict with the object changes to applied after the handler.
* `retry` (`int`) is the sequential number of retry of this handler.
* `started` (`datetime.datetime`) is the start time of the handler, in case of retries & errors.
* `runtime` (`datetime.timedelay`) is the duration of the handler run, in case of retries & errors.
* `diff` is a list of changes of the object (only for the update events).
* `old` is the old state of the object or a field (only for the update events).
* `new` is the new state of the object or a field (only for the update events).
* `logger` is a per-object logger, with the messages prefixed with the object's namespace/name.
* `event` is the raw event as received from the Kubernetes API.
* `cause` is the processed cause of the handler as detected by the framework (create/update/delete).
To run a non-exiting function for every resource as long as it exists:

`**kwargs` (or `**_` to stop lint warnings) is required for the forward
compatibility: the framework can add new keyword arguments in the future,
and the existing handlers should accept them.
```python
import time
import kopf

@kopf.daemon('zalando.org', 'v1', 'kopfexamples')
def my_daemon(spec, stopped, **kwargs):
while not stopped:
print(f"Object's spec: {spec}")
time.sleep(1)
```

Or the same with the timers:

```python
import kopf

@kopf.timer('zalando.org', 'v1', 'kopfexamples', interval=1)
def my_timer(spec, **kwargs):
print(f"Object's spec: {spec}")
```

That easy! For more features, see the [documentation](https://kopf.readthedocs.io/).


## Usage
Expand All @@ -84,7 +128,7 @@ into a docker image with CI/CD tool of your preference.
FROM python:3.7
ADD . /src
RUN pip install kopf
CMD kopf run /src/handlers.py
CMD kopf run /src/handlers.py --verbose
```

Where `handlers.py` is your Python script with the handlers
Expand Down

0 comments on commit 5288f1a

Please sign in to comment.