# Kubernetes Operator Pythonic Framework (Kopf)
[![GitHub](https://img.shields.io/github/stars/nolar/kopf?style=flat&label=GitHub%E2%AD%90%EF%B8%8F)](https://github.com/nolar/kopf)
[![CI](https://github.com/nolar/kopf/actions/workflows/thorough.yaml/badge.svg)](https://github.com/nolar/kopf/actions/workflows/thorough.yaml)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/kopf.svg)](https://pypi.org/project/kopf/)
[![codecov](https://codecov.io/gh/nolar/kopf/branch/main/graph/badge.svg)](https://codecov.io/gh/nolar/kopf)
[![Coverage Status](https://coveralls.io/repos/github/nolar/kopf/badge.svg?branch=main)](https://coveralls.io/github/nolar/kopf?branch=main)
**Kopf** —Kubernetes Operator Pythonic Framework— is a framework and a library
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` in August 2020: but it is the same codebase,
the same packages, the same developer(s).
As of now, the project is in maintenance mode since approximately mid-2021:
Python, Kubernetes, CI tooling, dependencies are upgraded, new bugs are fixed,
new versions are released from time to time, but no new big features are added
— there is nothing to add to this project without exploding its scope
beyond the "operator framework" definition (ideas are welcome!).
## Documentation
* https://kopf.readthedocs.io/
## Features
* Simple, but powerful:
* A full-featured operator in just 2 files: a `Dockerfile` + a Python file (*).
* Handling functions registered via decorators with a 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.
* 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).
* Validating and mutating admission webhook (with dev-mode tunneling).
* Live in-memory indexing of resources or their excerpts.
* 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 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/main/examples)
for the examples of the typical use-cases.
A minimalistic operator can look like this:
```python
import kopf
@kopf.on.create('kopfexamples')
def create_fn(spec, name, meta, status, **kwargs):
print(f"And here we are! Created {name} with spec: {spec}")
```
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/)
To run a never-exiting function for every resource as long as it exists:
```python
import time
import kopf
@kopf.daemon('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('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
Python 3.8+ is required:
[CPython](https://www.python.org/) and [PyPy](https://www.pypy.org/)
are officially supported and tested; other Python implementations can work too.
We assume that when the operator is executed in the cluster, it must be packaged
into a docker image with a CI/CD tool of your preference.
```dockerfile
FROM python:3.12
ADD . /src
RUN pip install kopf
CMD kopf run /src/handlers.py --verbose
```
Where `handlers.py` is your Python script with the handlers
(see `examples/*/example.py` for the examples).
See `kopf run --help` for other ways of attaching the handlers.
## Contributing
Please read [CONTRIBUTING.md](https://github.com/nolar/kopf/blob/main/CONTRIBUTING.md)
for details on our process for submitting pull requests to us, and please ensure
you follow the [CODE_OF_CONDUCT.md](https://github.com/nolar/kopf/blob/main/CODE_OF_CONDUCT.md).
To install the environment for the local development,
read [DEVELOPMENT.md](https://github.com/nolar/kopf/blob/main/DEVELOPMENT.md).
## Versioning
We use [SemVer](http://semver.org/) for versioning. For the versions available,
see the [releases on this repository](https://github.com/nolar/kopf/releases).
## License
This project is licensed under the MIT License —
see the [LICENSE](https://github.com/nolar/kopf/blob/main/LICENSE) file for details.
## Acknowledgments
* Thanks to Zalando for starting this project in Zalando's Open-Source Incubator
in the first place.
* Thanks to [@side8](https://github.com/side8) and their [k8s-operator](https://github.com/side8/k8s-operator)
for inspiration.
Raw data
{
"_id": null,
"home_page": "https://github.com/nolar/kopf",
"name": "kopf",
"maintainer": "Sergey Vasilyev",
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": "nolar@nolar.info",
"keywords": "kubernetes, operator, framework, python, k8s",
"author": "Sergey Vasilyev",
"author_email": "nolar@nolar.info",
"download_url": "https://files.pythonhosted.org/packages/6c/06/aad293a9fdb4095aeb1fd022842a18ef86010a4a4240ab41c4cff90e940e/kopf-1.37.4.tar.gz",
"platform": null,
"description": "# Kubernetes Operator Pythonic Framework (Kopf)\n\n[![GitHub](https://img.shields.io/github/stars/nolar/kopf?style=flat&label=GitHub%E2%AD%90%EF%B8%8F)](https://github.com/nolar/kopf)\n[![CI](https://github.com/nolar/kopf/actions/workflows/thorough.yaml/badge.svg)](https://github.com/nolar/kopf/actions/workflows/thorough.yaml)\n[![Supported Python versions](https://img.shields.io/pypi/pyversions/kopf.svg)](https://pypi.org/project/kopf/)\n[![codecov](https://codecov.io/gh/nolar/kopf/branch/main/graph/badge.svg)](https://codecov.io/gh/nolar/kopf)\n[![Coverage Status](https://coveralls.io/repos/github/nolar/kopf/badge.svg?branch=main)](https://coveralls.io/github/nolar/kopf?branch=main)\n\n**Kopf** \u2014Kubernetes Operator Pythonic Framework\u2014 is a framework and a library\nto make Kubernetes operators development easier, just in a few lines of Python code.\n\nThe main goal is to bring the Domain-Driven Design to the infrastructure level,\nwith Kubernetes being an orchestrator/database of the domain objects (custom resources),\nand the operators containing the domain logic (with no or minimal infrastructure logic).\n\nThe project was originally started as `zalando-incubator/kopf` in March 2019,\nand then forked as `nolar/kopf` in August 2020: but it is the same codebase,\nthe same packages, the same developer(s).\n\nAs of now, the project is in maintenance mode since approximately mid-2021:\nPython, Kubernetes, CI tooling, dependencies are upgraded, new bugs are fixed,\nnew versions are released from time to time, but no new big features are added\n\u2014 there is nothing to add to this project without exploding its scope\nbeyond the \"operator framework\" definition (ideas are welcome!).\n\n\n## Documentation\n\n* https://kopf.readthedocs.io/\n\n\n## Features\n\n* Simple, but powerful:\n * A full-featured operator in just 2 files: a `Dockerfile` + a Python file (*).\n * Handling functions registered via decorators with a declarative approach.\n * No infrastructure boilerplate code with K8s API communication.\n * Both sync and async handlers, with sync ones being threaded under the hood.\n * Detailed documentation with examples.\n* Intuitive mapping of Python concepts to Kubernetes concepts and back:\n * Marshalling of resources' data to the handlers' kwargs.\n * Marshalling of handlers' results to the resources' statuses.\n * Publishing of logging messages as Kubernetes events linked to the resources.\n* Support anything that exists in K8s:\n * Custom K8s resources.\n * Builtin K8s resources (pods, namespaces, etc).\n * Multiple resource types in one operator.\n * Both cluster and namespaced operators.\n* All the ways of handling that a developer can wish for:\n * Low-level handlers for events received from K8s APIs \"as is\" (an equivalent of _informers_).\n * High-level handlers for detected causes of changes (creation, updates with diffs, deletion).\n * Handling of selected fields only instead of the whole objects (if needed).\n * Dynamically generated or conditional sub-handlers (an advanced feature).\n * Timers that tick as long as the resource exists, optionally with a delay since the last change.\n * Daemons that run as long as the resource exists (in threads or asyncio-tasks).\n * Validating and mutating admission webhook (with dev-mode tunneling).\n * Live in-memory indexing of resources or their excerpts.\n * Filtering with stealth mode (no logging): by arbitrary filtering functions,\n by labels/annotations with values, presence/absence, or dynamic callbacks.\n * In-memory all-purpose containers to store non-serializable objects for individual resources.\n* Eventual consistency of handling:\n * Retrying the handlers in case of arbitrary errors until they succeed.\n * Special exceptions to request a special retry or to never retry again.\n * Custom limits for the number of attempts or the time.\n * Implicit persistence of the progress that survives the operator restarts.\n * Tolerance to restarts and lengthy downtimes: handles the changes afterwards.\n* Awareness of other Kopf-based operators:\n * Configurable identities for different Kopf-based operators for the same resource kinds.\n * Avoiding double-processing due to cross-pod awareness of the same operator (\"peering\").\n * Pausing of a deployed operator when a dev-mode operator runs outside of the cluster.\n* Extra toolkits and integrations:\n * Some limited support for object hierarchies with name/labels propagation.\n * Friendly to any K8s client libraries (and is client agnostic).\n * Startup/cleanup operator-level handlers.\n * Liveness probing endpoints and rudimentary metrics exports.\n * Basic testing toolkit for in-memory per-test operator running.\n * Embeddable into other Python applications.\n* Highly configurable (to some reasonable extent).\n\n(*) _Small font: two files of the operator itself, plus some amount of\ndeployment files like RBAC roles, bindings, service accounts, network policies\n\u2014 everything needed to deploy an application in your specific infrastructure._\n\n\n## Examples\n\nSee [examples](https://github.com/nolar/kopf/tree/main/examples)\nfor the examples of the typical use-cases.\n\nA minimalistic operator can look like this:\n\n```python\nimport kopf\n\n@kopf.on.create('kopfexamples')\ndef create_fn(spec, name, meta, status, **kwargs):\n print(f\"And here we are! Created {name} with spec: {spec}\")\n```\n\nNumerous kwargs are available, such as `body`, `meta`, `spec`, `status`,\n`name`, `namespace`, `retry`, `diff`, `old`, `new`, `logger`, etc:\nsee [Arguments](https://kopf.readthedocs.io/en/latest/kwargs/)\n\nTo run a never-exiting function for every resource as long as it exists:\n\n```python\nimport time\nimport kopf\n\n@kopf.daemon('kopfexamples')\ndef my_daemon(spec, stopped, **kwargs):\n while not stopped:\n print(f\"Object's spec: {spec}\")\n time.sleep(1)\n```\n\nOr the same with the timers:\n\n```python\nimport kopf\n\n@kopf.timer('kopfexamples', interval=1)\ndef my_timer(spec, **kwargs):\n print(f\"Object's spec: {spec}\")\n```\n\nThat easy! For more features, see the [documentation](https://kopf.readthedocs.io/).\n\n\n## Usage\n\nPython 3.8+ is required:\n[CPython](https://www.python.org/) and [PyPy](https://www.pypy.org/)\nare officially supported and tested; other Python implementations can work too.\n\nWe assume that when the operator is executed in the cluster, it must be packaged\ninto a docker image with a CI/CD tool of your preference.\n\n```dockerfile\nFROM python:3.12\nADD . /src\nRUN pip install kopf\nCMD kopf run /src/handlers.py --verbose\n```\n\nWhere `handlers.py` is your Python script with the handlers\n(see `examples/*/example.py` for the examples).\n\nSee `kopf run --help` for other ways of attaching the handlers.\n\n\n## Contributing\n\nPlease read [CONTRIBUTING.md](https://github.com/nolar/kopf/blob/main/CONTRIBUTING.md)\nfor details on our process for submitting pull requests to us, and please ensure\nyou follow the [CODE_OF_CONDUCT.md](https://github.com/nolar/kopf/blob/main/CODE_OF_CONDUCT.md).\n\nTo install the environment for the local development,\nread [DEVELOPMENT.md](https://github.com/nolar/kopf/blob/main/DEVELOPMENT.md).\n\n\n## Versioning\n\nWe use [SemVer](http://semver.org/) for versioning. For the versions available,\nsee the [releases on this repository](https://github.com/nolar/kopf/releases).\n\n\n## License\n\nThis project is licensed under the MIT License \u2014\nsee the [LICENSE](https://github.com/nolar/kopf/blob/main/LICENSE) file for details.\n\n\n## Acknowledgments\n\n* Thanks to Zalando for starting this project in Zalando's Open-Source Incubator\n in the first place.\n* Thanks to [@side8](https://github.com/side8) and their [k8s-operator](https://github.com/side8/k8s-operator)\n for inspiration.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Kubernetes Operator Pythonic Framework (Kopf)",
"version": "1.37.4",
"project_urls": {
"Bug Tracker": "https://github.com/nolar/kopf/issues",
"Documentation": "https://kopf.readthedocs.io",
"Homepage": "https://github.com/nolar/kopf",
"Source Code": "https://github.com/nolar/kopf"
},
"split_keywords": [
"kubernetes",
" operator",
" framework",
" python",
" k8s"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "74d5781b596a76cea901565b5c6edfb4dc9ae762cf94b42baaf89887386b680f",
"md5": "c404c84082b8a250abc6489f620785fe",
"sha256": "0e0f9984eca5d50e4b5f1fd646bdbbd9f3cf164fab9ab86a437a5e69cde629d1"
},
"downloads": -1,
"filename": "kopf-1.37.4-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c404c84082b8a250abc6489f620785fe",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 208202,
"upload_time": "2024-12-13T22:08:42",
"upload_time_iso_8601": "2024-12-13T22:08:42.502559Z",
"url": "https://files.pythonhosted.org/packages/74/d5/781b596a76cea901565b5c6edfb4dc9ae762cf94b42baaf89887386b680f/kopf-1.37.4-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "6c06aad293a9fdb4095aeb1fd022842a18ef86010a4a4240ab41c4cff90e940e",
"md5": "7978acfd173fd29bdc144c6728b48328",
"sha256": "a940f7af4b31e345bfd052b14be330dd891173a90a2179a63d566e6f278bed63"
},
"downloads": -1,
"filename": "kopf-1.37.4.tar.gz",
"has_sig": false,
"md5_digest": "7978acfd173fd29bdc144c6728b48328",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 1191425,
"upload_time": "2024-12-13T22:08:46",
"upload_time_iso_8601": "2024-12-13T22:08:46.012864Z",
"url": "https://files.pythonhosted.org/packages/6c/06/aad293a9fdb4095aeb1fd022842a18ef86010a4a4240ab41c4cff90e940e/kopf-1.37.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-12-13 22:08:46",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "nolar",
"github_project": "kopf",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "kopf"
}