Knative – система, яка дозволяє використовувати Serverless модель розробки у Kubernetes. По суті, Knative можна уявляти собі як ще один рівень абстракції, який дозволяє девелоперам не поринати в деталі деплойменту, скелінгу та нетворкінгу у “vanilla” Kubernetes.
Розробка самого Knative була розпочта у Google за співучастю таких компаній, як IBM, Pivotal, Red Hat, та загалом має близько 50 компаній-контрібьюторів.
Зміст
What is: Serverless computing
Але спочатку, давайте розглянемо що таке Serverless взагалі.
Отже, Server та Less, це модель розробки, коли вам не потрібно перейматись менеджментом серверів – все це бере на себе cloud-провайдер, який надає вам послугу Serverless computing.
Тобто, зазвичай маємо в клауді:
- bare-metal сервери десь в дата-центрі
- на яких запускаються віртуальні машини
- на яких ми запускаємо контейнери
Serverless computing поверх цих шарів додає ще один, де ви можете запускати вашу функцію, тобто мінімальний deployable-юніт, не займаючись ані металом, ані віртуалками, ані контейнерами. Ви просто маєте код, який в пару кліків можна запустити в клауді, а всі задачі по менеджменту інфрастуктури бере на себе клауд-провайдер. Ви не маєте турбуватись ані про хай авайлабіліті, ні про failt-tolerance, ні про бекапи, ні про секьюріті-патчі, ні про бекапи, ні про моніторинг і логування того, що відбувається на рівні інфрастуктури. Ба більше – на рівні мережі вам не треба думати про лоад-балансінг та те, як розподіляти навантаження по вашому сервісу – ви просто приймаєте запити на API Gateway або налаштовуєте триггер на event, який триггерить вашу Функцію. Тобто, cloud provider предоставляє вам послугу Function-as-a-Service, FaaS.
Все це чудово підходить у випадках, коли проект тільки-но стартує, і у девелоперів нема достатнього досвіду та/або часу, щоб піднімати сервери та кластери, тобто – скорочується Time-to-Market, або коли проект тільки тестує свою модель роботи системи взагалі, щоб швидко та безболісно реалізувати свою архітектуру.
“Запусти, та радуйся!”
Крім того, в FaaS інша модель оплати за сервіс – замість того, щоб платити за запущені сервери не зважаючи на те, чи виконують вони якусь роботу, чи просто знаходяться у idle стейті, при використанні FaaS ви платите тільки за той час, коли ваша функція виконується – Pay-for-Use Services.
Отже, ви:
- створюєте функцію
- налаштовуєте івенти, за якими ця функця буде запускатися (все ще нічого не платите)
- при виникненні івента – він тригерить запуск функції (тут вже платите, допоки вона виконується)
- після завершення роботи функції – вона “схлопується”, і біллінг за неї зупиняється до наступного запуску
Серед провайдерів FaaS – Amazon Web Services з його AWS Lambda, Microsoft Azure та Azure Functions, Google Cloud та Cloud Functions, і IBM Cloud з його IBM Cloud Functions.
Детальніше про Serverless – у CNCF Serverless Whitepaper.
Serverless use cases
Serverless модель буде ідеальною для рішень, які можуть працювати асінхронно та не потребують збереження стану, тобто являються Stateless системами.
Наприклад, це може бути функція в AWS, котора при створенні нового ЕС2 в аккаунті буде автоматично додавати теги до неї, накшталт AWS: Lambda – копирование тегов EC2 на EBS, часть 2 – создание Lambda-функции, коли ми використовуємо CloudWatch, який при створенні ЕС2 створює event, який триггерить функцю, передаючи їй аргументом ID EC2-інстансу, для дисків якого треба додати теги: функція запускається по цьому триггеру, додає теги, та зупинятється до наступного виклику.
Self-hosted serverless
Для використання Serverless моделі, необов’язково прив’язуватись до FaaS-провайдеру, натомість можна запустити self-hosted сервіс наприклад в своєму Kubernetes-кластері, і таким чином уникнути vendor lock.
Серед таких рішень:
- Kubeless, Iron Functions, Space Cloud, OpenLambda, Funktion, OpenWhisk та Fn Project: наразі, більше мертві, ніж живі, хоча деякі досі мають оновлення
- Fission: має релізи, тобто розвивається, але займає тільки 2%
- OpenFaaS: використовується у 10% випадків
- Knative: наразі являється найбільш популярним (27%) та найбільше активно розвиваючимся проектом
Knative vs AWS Lambda
Але навіщо взагалі морочитись із запуском власного Serverless?
- маєте можливість обійти ліміти, задані провайдером – див. AWS Lambda quotas
- уникаєте vendor lock, тобто маєте можливість швидко переїхати до іншого провайдера або використовувати multi-cloud архітектуру для більшої надійності
- маєте більше можливостей для моніторингу, трейсінгу та роботи з логами, бо в Kubernetes ми можемо все, на відміну від AWS Lambda та її прив’язки до CloudWatch
Доречі, Knative має змогу запускати функції, розроблені для AWS Labmda завдяки Knative Lambda Runtimes.
Компоненти та архітектура Knative
Knative має два основні компоненти – Knative Serving та Knative Eventing.
Для контролю мережи, роутів та ревізій Knative використовує Istio (хоча може бути і інший, див. Configuring the ingress gateway).
Knative Serving
Knative Serving відповідає за деплоймент контейнеру, оновлення, мережу та автоскейлінг.
Роботу Knative Serving можна відобразити наступним чином:
Трафик від клієнта приходить на Ingress, та в залежності від запиту відправляється на конкретний Knative Service, який являє собою Kubernetes Service та Kubernetes Deployment.
В залежності від конфігурації конкретного Knative Service, трафік може бути розподіленний між різними ревізіями, тобто версіями самого application.
KPA – Knative Pod Autoscaler, перевіряє кількість запитів та при необхідності додає нові поди в Deployment. Якщо трафіка нема – то KPA скейлить поди в нуль, а коли з’являються нові запити від клієнтів – запускає поди та скейлить їх в залежності від кількості запитів, які треба обробити.
Основні типи ресурсів:
- Service:
service.serving.knative.dev
відповідає за весь цикл життя вашого workload (тобто, деплойменту та зв’язанних з ним ресурсів) – контролює створення залежних ресурсів, таких як роути, конфігурації, ревізії - Routes:
route.serving.knative.dev
відповідає за зв’язок між ендпоінтом та ревізіями - Configurations:
configuration.serving.knative.dev
відповідає за необхідний стан (desired state) деплойменту та створює revisions, на які буде потрапляти трафік - Revisions:
revision.serving.knative.dev
являє собою point-in-time snapshot коду та конфігурацї для кожної зміни у workload
Див. Resource Types.
Knative Eventing
Knative Eventing відповідає за асинхронний зв’язок розподіленних частин вашої системи. Замість того, щоб робити їх залежними друг від друга, вони можуть створювати events (event producers), які будуть отримані іншим компонентом системи (event consumers або subcsribers, або в термінології Knative – sinks), тобто реалізувати event-driven architecture.
Knative Eventing використовує стандартні запроси HTTP POST для відправлення та отримання таких івентів, які мають відповідати специфікації CloudEvents.
Knative Eventing дозволяє створити:
- Source to Sink: Source (event producers) відправляє івент (чи таки евент?) до Sink, який його обробляє. В ролі Source може бути PingSource, APIServerSource (Kubernetes API івенти), Apache Kafka, GitHub, тощо
- Channel and Subscription: створює event pipe, коли івент потрапивши до Channel відразу відправляється до subscriber
- Broker and Trigger: являє собою event mesh – івент, потрапляє до Broker, який має одного чи більше Trigger, котрі має фільтри, в залежності від яких отримється від Брокера ці events
Install Knative in Minikube
Компоненти Knative можна запустити за допомогою YAML-маніфестів (див. Install Knative Serving by using YAML та Install Knative Eventing by using YAML), використовуючи Knative Operator, або ж за допомогою Knative Quickstart plugin до Knative CLI.
Для знайомства нам підійде і quickstart плагін, тож використаємо його, а запускати будемо у Minikube.
Install Knative CLI
Див. Installing kn
.
Для Arch-based дистрибутивів – за допомогою pacman
із репозиторію:
[simterm]
$ sudo pacman -S knative-client
[/simterm]
Перевіряємо:
[simterm]
$ kn version Version: Build Date: Git Revision: Supported APIs: * Serving - serving.knative.dev/v1 (knative-serving v0.34.0) * Eventing - sources.knative.dev/v1 (knative-eventing v0.34.1) - eventing.knative.dev/v1 (knative-eventing v0.34.1)
[/simterm]
Запуск Knative з Quickstart plugin
Див. kn-plugin-quickstart.
Знаходимо останню версію на сторінці релізів, вибираємо потрібну версію, в моєму випадку це буде kn-quickstart-linux-amd64, та завантажуємо у каталог, який є в $PATH
:
[simterm]
$ wget -O /usr/local/bin/kn-quickstart https://github.com/knative-sandbox/kn-plugin-quickstart/releases/download/knative-v1.8.2/kn-quickstart-linux-amd64 $ chmod +x /usr/local/bin/kn-quickstart
[/simterm]
Перевіряємо (у CLI навіть є автокомпліт):
[simterm]
$ kn plugin list - kn-quickstart : /usr/local/bin/kn-quickstart
[/simterm]
Перевіряємо:
[simterm]
$ kn quickstart --help Get up and running with a local Knative environment Usage: kn-quickstart [command] ...
[/simterm]
Quickstart плагін замість Istio встановить Kourier, а також створить Minikube кластер та встановить Knative Serving з sslip.io в ролі DNS і Knative Eventing.
Запускаємо:
[simterm]
$ kn quickstart minikube Running Knative Quickstart using Minikube Minikube version is: v1.29.0 ... 🏄 Done! kubectl is now configured to use "knative" cluster and "default" namespace by default To finish setting up networking for minikube, run the following command in a separate terminal window: minikube tunnel --profile knative The tunnel command must be running in a terminal window any time when using the knative quickstart environment. Press the Enter key to continue ...
[/simterm]
В іншому терміналі створюємо minikube-тунель для доступу з хост-машини:
[simterm]
$ minikube tunnel --profile knative &
[/simterm]
Повертаємось до попереднього вікна:
[simterm]
... 🍿 Installing Knative Serving v1.8.5 ... ... 🕸 Installing Kourier networking layer v1.8.3 ... ... 🕸 Configuring Kourier for Minikube... ... 🔥 Installing Knative Eventing v1.8.8 ... ... 🚀 Knative install took: 3m23s 🎉 Now have some fun with Serverless and Event Driven Apps!
[/simterm]
Перевіряємо кластера Minikube:
[simterm]
$ minikube profile list |---------|-----------|---------|--------------|------|---------|---------|-------|--------| | Profile | VM Driver | Runtime | IP | Port | Version | Status | Nodes | Active | |---------|-----------|---------|--------------|------|---------|---------|-------|--------| | knative | docker | docker | 192.168.49.2 | 8443 | v1.24.3 | Running | 1 | | |---------|-----------|---------|--------------|------|---------|---------|-------|--------|
[/simterm]
Неймспейси в Kubernetes:
[simterm]
$ kubectl get ns NAME STATUS AGE default Active 7m30s knative-eventing Active 5m54s knative-serving Active 6m43s kourier-system Active 6m23s ...
[/simterm]
Поди в kourier-system
:
[simterm]
$ kk -n kourier-system get pod NAME READY STATUS RESTARTS AGE 3scale-kourier-gateway-7b89ff5c79-hwmpr 1/1 Running 0 7m26s
[/simterm]
Та в knative-eventing
:
[simterm]
$ kk -n knative-eventing get pod NAME READY STATUS RESTARTS AGE eventing-controller-5c94cfc645-8pxgk 1/1 Running 0 7m10s eventing-webhook-5554dc76bc-656p4 1/1 Running 0 7m10s imc-controller-86dbd688db-px5z4 1/1 Running 0 6m39s imc-dispatcher-5bfbdfcd85-wvpc7 1/1 Running 0 6m39s mt-broker-controller-78dcfd9768-ttn7t 1/1 Running 0 6m28s mt-broker-filter-687c575bd4-rpzk7 1/1 Running 0 6m28s mt-broker-ingress-59d566b54-8t4x7 1/1 Running 0 6m28s
[/simterm]
І в knative-serving
:
[simterm]
$ kk -n knative-serving get pod NAME READY STATUS RESTARTS AGE activator-66b65c899d-5kqsm 1/1 Running 0 8m17s autoscaler-54cb7cd8c6-xltb9 1/1 Running 0 8m17s controller-8686fd49f-976dk 1/1 Running 0 8m17s default-domain-mk8tf 0/1 Completed 0 7m34s domain-mapping-559c8cdcbb-fs7q4 1/1 Running 0 8m17s domainmapping-webhook-cbfc99f99-kqptw 1/1 Running 0 8m17s net-kourier-controller-54f9c959c6-xsgp8 1/1 Running 0 7m57s webhook-5c5c86fb8b-l24sh 1/1 Running 0 8m17s
[/simterm]
Тепер давайте подвимось, що Knative вміє.
Knative Functions
Functions дозволяє швидко розробляти функції без необхідності писати Dockerfile та взагалі знати Knative та Kubernetes.
Див. About Knative Functions.
Додаємо ще один плагін – kn-func
:
[simterm]
$ wget -O /usr/local/bin/kn-func https://github.com/knative/func/releases/download/knative-v1.9.3/func_linux_amd64 $ chmod +x /usr/local/bin/kn-func
[/simterm]
Перевіряємо:
[simterm]
$ kn plugin list - kn-func : /usr/local/bin/kn-func - kn-quickstart : /usr/local/bin/kn-quickstart
[/simterm]
Логінимось до Docker Registry (хоча якщо не зробити зараз – то Knative запросить логін під час деплою):
[simterm]
$ docker login
[/simterm]
func create
За допомогою func create
створимо функцію на Python, див. Creating a function:
[simterm]
$ kn func create -l python hello-world Created python function in /home/setevoy/Scripts/Knative/hello-world
[/simterm]
На робочій машині буде створено директорію з її кодом:
[simterm]
$ ll hello-world/ total 28 -rw-r--r-- 1 setevoy setevoy 28 Apr 5 12:36 Procfile -rw-r--r-- 1 setevoy setevoy 862 Apr 5 12:36 README.md -rwxr-xr-x 1 setevoy setevoy 55 Apr 5 12:36 app.sh -rw-r--r-- 1 setevoy setevoy 1763 Apr 5 12:36 func.py -rw-r--r-- 1 setevoy setevoy 390 Apr 5 12:36 func.yaml -rw-r--r-- 1 setevoy setevoy 28 Apr 5 12:36 requirements.txt -rw-r--r-- 1 setevoy setevoy 258 Apr 5 12:36 test_func.py
[/simterm]
У файлі func.yaml
описується її конфіг:
[simterm]
$ cat hello-world/func.yaml specVersion: 0.35.0 name: hello-world runtime: python registry: "" image: "" imageDigest: "" created: 2023-04-05T12:36:46.022291382+03:00 build: buildpacks: [] builder: "" buildEnvs: [] run: volumes: [] envs: [] deploy: namespace: "" remote: false annotations: {} options: {} labels: [] healthEndpoints: liveness: /health/liveness readiness: /health/readiness
[/simterm]
А в func.py
– сам код, який буде запускатись:
[simterm]
$ cat hello-world/func.py from parliament import Context from flask import Request import json # parse request body, json data or URL query parameters def payload_print(req: Request) -> str: ...
[/simterm]
func run
func run
дозволяє перевірити, як функція буде працювати без необхідності її деплою до Knative. Для цього Knative CLI створить образ за допомогою вашого container runtime, та запустить його. Див. Running a function.
Запускаємо, вказуючи шлях до коду:
[simterm]
$ kn func run --path hello-world/ 🙌 Function image built: docker.io/setevoy/hello-world:latest Function already built. Use --build to force a rebuild. Function started on port 8080
[/simterm]
Перевіряємо Docker-контейнери:
[simterm]
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3869fa00ac51 setevoy/hello-world:latest "/cnb/process/web" 52 seconds ago Up 50 seconds 127.0.0.1:8080->8080/tcp sweet_vaughan
[/simterm]
Та пробуємо curl
:
[simterm]
$ curl localhost:8080 {}
[/simterm]
В аутпуті func run
:
[simterm]
Received request GET http://localhost:8080/ localhost:8080 Host: localhost:8080 User-Agent: curl/8.0.1 Accept: */* URL Query String: {}
[/simterm]
Або можна перевірити за допомогою func invoke
:
[simterm]
$ kn func invoke --path hello-world/ Received response {"message": "Hello World"}
[/simterm]
І в самій функцї:
[simterm]
Received request POST http://localhost:8080/ localhost:8080 Host: localhost:8080 User-Agent: Go-http-client/1.1 Content-Length: 25 Content-Type: application/json Accept-Encoding: gzip Request body: {"message": "Hello World"}
[/simterm]
func deploy
func deploy
створить образ, запушить його до registry, та задеплоїть у Kubernetes як Knative Service.
Якшо в коді зробити зміни, або просто виконати func build
– то в Knative для функції буде створено нову ревізію, на яку буде переключений відповідний route
:
[simterm]
$ kn func deploy --build --path hello-world/ --registry docker.io/setevoy 🙌 Function image built: docker.io/setevoy/hello-world:latest ✅ Function updated in namespace "default" and exposed at URL: http://hello-world.default.10.106.17.160.sslip.io
[/simterm]
Перевіряємо под в default namespace:
[simterm]
$ kk get pod NAME READY STATUS RESTARTS AGE hello-world-00003-deployment-74dc7fcdd-7p6ql 2/2 Running 0 9s
[/simterm]
Kubernetes Service:
[simterm]
$ kk get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE example-broker-kne-trigger-kn-channel ExternalName <none> imc-dispatcher.knative-eventing.svc.cluster.local 80/TCP 33m hello-world ExternalName <none> kourier-internal.kourier-system.svc.cluster.local 80/TCP 3m50s hello-world-00001 ClusterIP 10.109.117.53 <none> 80/TCP,443/TCP 4m1s hello-world-00001-private ClusterIP 10.105.142.206 <none> 80/TCP,443/TCP,9090/TCP,9091/TCP,8022/TCP,8012/TCP 4m1s hello-world-00002 ClusterIP 10.107.71.130 <none> 80/TCP,443/TCP 2m58s hello-world-00002-private ClusterIP 10.108.40.73 <none> 80/TCP,443/TCP,9090/TCP,9091/TCP,8022/TCP,8012/TCP 2m58s hello-world-00003 ClusterIP 10.103.142.53 <none> 80/TCP,443/TCP 2m37s hello-world-00003-private ClusterIP 10.110.95.58 <none> 80/TCP,443/TCP,9090/TCP,9091/TCP,8022/TCP,8012/TCP 2m37s
[/simterm]
Або за допомогою Knative CLI:
[simterm]
$ kn service list NAME URL LATEST AGE CONDITIONS READY REASON hello-world http://hello-world.default.10.106.17.160.sslip.io hello-world-00003 4m41s 3 OK / 3 True
[/simterm]
Або можна за kubectl
отримати ресурс kvcs
:
[simterm]
$ kubectl get ksvc NAME URL LATESTCREATED LATESTREADY READY REASON hello http://hello.default.10.106.17.160.sslip.io hello-00001 hello-00001 True hello-world http://hello-world.default.10.106.17.160.sslip.io hello-world-00003 hello-world-00003 True
[/simterm]
Визиваємо нашу функцію:
[simterm]
$ kn func invoke --path hello-world/ Received response {"message": "Hello World"}
[/simterm]
І через хвилину відповідний Pod буде вбито, тобто Deployment заскейлиться в нуль:
[simterm]
$ kk get pod NAME READY STATUS RESTARTS AGE hello-world-00003-deployment-74dc7fcdd-7p6ql 2/2 Terminating 0 79s
[/simterm]
Knative Serving
Functions – чудово, але ж ми начебто інженери, і нам цікаво щось більш наближене до Kubernetes, тож давайте глянемо на Knative Service.
Як вже говорилось, Knative Service – це “повний workload”, включаючи Kubernetes Service, Kubernetes Deployment, Knative Pod Autoscaler та відповідні роути і конфіги. Див. Deploying a Knative Service.
Тут використаємо YAML маніфест (хоча можно і kn service create
), в якому описано образ, з якого буде створено под:
apiVersion: serving.knative.dev/v1 kind: Service metadata: name: hello spec: template: spec: containers: - image: gcr.io/knative-samples/helloworld-go ports: - containerPort: 8080 env: - name: TARGET value: "World"
Деплоїмо до Kubernetes:
[simterm]
$ kubectl apply -f knative-hello-go-svc.yaml service.serving.knative.dev/hello created
[/simterm]
Перевіряємо Knative Service:
[simterm]
$ kn service list NAME URL LATEST AGE CONDITIONS READY REASON hello http://hello.default.10.106.17.160.sslip.io hello-00001 70s 3 OK / 3 True
[/simterm]
Пробуємо з curl
:
[simterm]
$ curl http://hello.default.10.106.17.160.sslip.io Hello World!
[/simterm]
Глянемо поди:
[simterm]
$ kk get pod NAME READY STATUS RESTARTS AGE hello-00001-deployment-5897f54974-wdhq8 2/2 Running 0 10s
[/simterm]
Та Kubernetes Deployments:
[simterm]
$ kk get deploy NAME READY UP-TO-DATE AVAILABLE AGE hello-00001-deployment 1/1 1 1 19m hello-world-00001-deployment 0/0 0 0 26m hello-world-00002-deployment 0/0 0 0 25m hello-world-00003-deployment 0/0 0 0 24m
[/simterm]
Autoscaling
Knative Serving використовує власний Knative Pod Autoscaler (KPA), хоча можна замість нього створити “класичний” Horizontal Pod Autoscaler (HPA).
KPA підтримує scale to zero, але не вміє в CPU-based autoscaling. Крім того, у KPA можемо використовувати concurrency або requests per second метрики для скейлінгу.
HPA ж навпаки – вміє CPU-based autoscaling (і багато іншого), але не знає як скейлити в нуль, а для concurrency або RPS йому потрібні додаткові налаштування (див. Kubernetes: HorizontalPodAutoscaler – обзор и примеры).
Ми вже маємо KPA, які були створені при func deploy
та під час створення нашого Knative Service:
[simterm]
$ kk get kpa NAME DESIREDSCALE ACTUALSCALE READY REASON hello-00001 0 0 False NoTraffic hello-world-00001 0 0 False NoTraffic hello-world-00002 0 0 False NoTraffic hello-world-00003 0 0 False NoTraffic
[/simterm]
Запустимо curl
в 10 потоків:
[simterm]
$ seq 1 10 | xargs -n1 -P 10 curl http://hello.default.10.106.17.160.sslip.io
[/simterm]
А в іншому вікні термінала глянемо на kubectl get pod --watch
:
[simterm]
$ kk get pod -w NAME READY STATUS RESTARTS AGE hello-00001-deployment-5897f54974-9lxwl 0/2 ContainerCreating 0 1s hello-00001-deployment-5897f54974-9lxwl 1/2 Running 0 2s hello-00001-deployment-5897f54974-9lxwl 2/2 Running 0 2s
[/simterm]
“Воу, воно скейлиться!” 🙂
Knative Revisions
Knative завдяки Istio (або Kourier чи Kong) вміє розподіляти трафік між різними версіями (revisions) системи, що дозволяє виконувати blue/green або canary deployments.
Див. Traffic splitting.
В нашому Knative Service ми задавали змінну оточення $TARGET
зі значенням World – давайте замінимо його на Knative:
[simterm]
$ kn service update hello --env TARGET=Knative Updating Service 'hello' in namespace 'default': 0.025s The Configuration is still working to reflect the latest desired specification. 2.397s Traffic is not yet migrated to the latest revision. 2.441s Ingress has not yet been reconciled. 2.456s Waiting for load balancer to be ready 2.631s Ready to serve. Service 'hello' updated to latest revision 'hello-00002' is available at URL: http://hello.default.10.106.17.160.sslip.io
[/simterm]
Перевіряємо ревізії:
[simterm]
$ kn revision list NAME SERVICE TRAFFIC TAGS GENERATION AGE CONDITIONS READY REASON hello-00002 hello 100% 2 20s 4 OK / 4 True hello-00001 hello 1 24m 3 OK / 4 True
[/simterm]
Та пробуємо звернутись до ендпоінту:
[simterm]
$ curl http://hello.default.10.106.17.160.sslip.io Hello Knative!
[/simterm]
Тепер спробуємо поділити трафік – 50 відсотків відправити на попередню ревізію, а 50% – на нову:
[simterm]
$ kn service update hello --traffic hello-00001=50 --traffic @latest=50
[/simterm]
Глянемо revisions
зараз:
[simterm]
$ kn revision list NAME SERVICE TRAFFIC TAGS GENERATION AGE CONDITIONS READY REASON hello-00002 hello 50% 2 115s 4 OK / 4 True hello-00001 hello 50% 1 26m 4 OK / 4 True
[/simterm]
Та знов пробуємо curl
, повторюємо кілька раз:
[simterm]
$ curl http://hello.default.10.106.17.160.sslip.io Hello Knative! $ curl http://hello.default.10.106.17.160.sslip.io Hello World! $ curl http://hello.default.10.106.17.160.sslip.io Hello Knative! $ curl http://hello.default.10.106.17.160.sslip.io Hello World!
[/simterm]
Nice!
Knative Eventing
Knative Eventing – це набор сервісів та ресурсів, які дозволяють нам побудувати event-driven applications, коли Функції викликаються якимось евентом. Для цього можемо підключити sources, які ці події будуть генерувати, та sinks, тобто “споживачі”, які на ці події реагують.
У подальшій документації по Quickstart є приклад роботи з Broker та Trigger за допомогою cloudevents-player, але як на мене, там не дуже-то демонструються можливості Knative Eventing, тож виберемо трошки the hard way.
Як вже писалось, Knative підтримує три типи реалізації event-driven системи – Source to Sink, Channel and Subscription та Broker and Trigger.
Source to Sink
Source to Sink – сама базова модель, створюється за допомогою ресурсів Source та Sink, де Source – це Event Producer, а Sink – ресурс, який можна визвати або адресувати йому повідомлення.
Серед прикладів Sources – APIServerSource (Kubernetes API server), GitHub та GitLab, RabbitMQ та інші, див. Event sources.
В ролі Sink може бути Knative Service, Channel або Broker (тобто, “раковина”, куди ми “зливаємо” наші івенти). Хоча при побудові саме Source to Sink моделі, в ролі sink має бути саме Knative Service – про Channel та Broker поговоримо далі.
Channel and Subscription
Channel та Subscription являє собой even pipe (як pipe в bash, коли ми через |
перенаправляємо stdout одніє програми у stdin іншої).
Тут Channel – це інтерфейс між event source та subscriber цього каналу. При цьому channel являє собою тип sink, так як він може зберігати івенти, щоб потім віддати їх своїм subscribers.
Knative підтримує три типи каналів:
- In-memory Channel
- Apache Kafka Channel
- Google Cloud Platform Pub-sub Channel
In-memory Channel – тип за-замовченням, і не має змоги відновити івенти або зберігати їх постійно – для цього використовуйте типи накшталт Apache Kafka Channel.
Далі, Subscription – відповідає за з’єднання Channel з відповідним Knative Service – Сервіси підписуються на Канал через Subscription, та починають отримувати з Каналу повідомлення.
Broker and Trigger
Broker та Trigger являють собою event mesh модель, дозволяючи передавати події необхідним сервісам.
Тут Broker збирає події з різних sources предоставляючи вхідний шлюз дня них, а Trigger по суті є Subscription, але з можливістью фільтрування того, які саме івенти він буде отримувати.
Приклад створення Source to Sink
Створимо Knative Service, який буде нашим sink, тобто отримувачем:
[simterm]
$ kn service create knative-hello --concurrency-target=1 --image=quay.io/redhattraining/kbe-knative-hello:0.0.1 ... Service 'knative-hello' created to latest revision 'knative-hello-00001' is available at URL: http://knative-hello.default.10.106.17.160.sslip.io
[/simterm]
concurrency-target
тут вказує, що наш Service може обробляти тільки один запит одночасно. Якщо їх буде більше – то відповідний KPA створить додаткові поди.
Створюємо Event Source, наприклад – PingSource
, який кожну хвилину буде слати повідомлення в вигляді JSON до нашого knative-hello
Service:
[simterm]
$ kn source ping create knative-hello-ping-source --schedule "* * * * *" --data '{"message": "Hello from KBE!"}' --sink ksvc:knative-hello Ping source 'knative-hello-ping-source' created in namespace 'default'.
[/simterm]
Перевіряємо:
[simterm]
$ kn source list NAME TYPE RESOURCE SINK READY knative-hello-ping-source PingSource pingsources.sources.knative.dev ksvc:knative-hello True
[/simterm]
І глянемо логи поду з Service knative-hello
:
[simterm]
$ kubectl logs -f knative-hello-00001-deployment-864756c67d-sk76m ... 2023-04-06 10:23:00,329 INFO [eventing-hello] (executor-thread-1) ce-id=bd1093a9-9ab7-4b79-8aef-8f238c29c764 2023-04-06 10:23:00,331 INFO [eventing-hello] (executor-thread-1) ce-source=/apis/v1/namespaces/default/pingsources/knative-hello-ping-source 2023-04-06 10:23:00,331 INFO [eventing-hello] (executor-thread-1) ce-specversion=1.0 2023-04-06 10:23:00,331 INFO [eventing-hello] (executor-thread-1) ce-time=2023-04-06T10:23:00.320053265Z 2023-04-06 10:23:00,332 INFO [eventing-hello] (executor-thread-1) ce-type=dev.knative.sources.ping 2023-04-06 10:23:00,332 INFO [eventing-hello] (executor-thread-1) content-type=null 2023-04-06 10:23:00,332 INFO [eventing-hello] (executor-thread-1) content-length=30 2023-04-06 10:23:00,333 INFO [eventing-hello] (executor-thread-1) POST:{"message": "Hello from KBE!"}
[/simterm]
Наразі це все, що хотілося дізнатись про Knative.
Виглядає в цілому досить цікаво, але можуть бути з автоскейлінгом та Istio, бо Istio сам по собі може бути тим ще гемороєм. Хоча на поточному проекті Knative у нас вже в production, та особливих проблем з ним поки не бачили.
Посилання по темі
- What is serverless?
- What is Function-as-a-Service (FaaS)?
- What is Knative Serving? (A Colorful Guide)
- Developing Knative Kubernetes
- Overview of self-hosted serverless frameworks for Kubernetes: OpenFaaS, Knative, OpenWhisk, Fission
- Running Serverless Workloads on Kubernetes with Knative
- Running Serverless Functions on Kubernetes
- A step-by-step guide to Knative eventing
- Deploy AWS lambda function to Kubernetes using Knative and Triggermesh KLR