Intro
Для начала немного теории. Бессерверные функции - это гибкий вычислительный ресурс, который предоставляется по-запросу.
Apache OpenWhisk – это один из самых популярных открытых проектов реализующих архитектурный паттерн функция-как-сервис.
Если говорить об основных преимуществах бессерверной архитектуры:
Гибкая горизонтальная и вертикальная масштабируемость (scale-in, scale-out).
Отсутствие накладных расходов на поддержку, когда нет нагрузки.
Области применения
FaaS отлично подходит для решения задач в разных областях:
Аналитика: пакетная обработка данных, для которой запускаются тысячи бессерверных функций отправляющих запросы к разным API.
IoT
Бэкенды для мобильных приложений
Обработка видео файлов и изображений
AI
«Киллер фича» OpenWhisk это поддержка сразу нескольких языков программирования: Net, Go, Java, JavaScript, PHP, Python (Tensorflow and PyTorch), Ruby, Swift.
Возможность декомпозиции и распределения обязанностей между разными командами особенно важна для крупных компаний.
Альтернативные варианты
AWS Lambda
Azure Functions
IBM Cloud Functions – это Apache OpenWhisk, эти два проекта используют одну кодовую базу
Kubernetes-native платформы (Fission, Kubeless and Open-FaaS)
По сравнению с облачными сервисами OpenWhisk выигрывает в портативности – ваш код будет работать on-prem или в облаке.
Нет необходимости привязываться к какому-то определенному вендору.
Решения основанные на Kubernetes проигрывают в функциональности и производительности при высоких нагрузках.
Некоторые из этих решений используют модель «open core» – часть функционала доступна только в платной версии продукта.
Архитектура
Буквально пару слов об архитектуре OpenWhisk:
Nginx терминирует SSL
Для взаимодействия с кластером OpenWhisk, пользователь должен использовать специальный CLI – wsk
Controller (написан на Scala) сохраняет сущности OpenWhisk в специальное документарное хранилище CouchDB.
Для обмена данными между компонентом Invoker используется Kafka
-
Invoker запускает контейнеры Docker с нужным рантаймом (Java, Python, Go etc). По одному топику Kafka на инстанс Invoker. Для каждой функции запускается отдельный контейнер. При этом все компоненты OpenWhisk тоже работают в Docker контейнерах.
OpenWhisk может работать с отдельно стоящим функциями (actions).
С помощью триггеров реагировать на внешние сигналы, например на сообщения шине данных:
Более подробно с архитектурой OpenWhisk можно познакомится на сайте проекта, а мы побежали дальше.
Установка
Если верить разработчикам OpenWhisk, Docker стильно выигрывает по производительности по сравнению с инсталляцией в кластер Kubernetes:
https://rutube.ru/video/176bb55742eae383bd07dd6948bd1d26/?t=1149&r=plwd
Но для нас сейчас важнее удобство, чем скорость, поэтому будем использовать именно K8s.
К счастью существует Helm чарт, который поддерживают мейнтейнеры OpenWhisk:
Для работы OpenWhisk обязательно нужно настроить Ingress. Если это тестовый кластер, то можно использовать NodPort.
ingress.yaml:
whisk:
ingress:
type: NodePort
api_host_name: <IP_ADDRESS>
api_host_port: 31001
nginx:
httpsNodePort: 31001
mycluster.yaml:
affinity:
enabled: false
toleration:
enabled: false
invoker:
options: "-Dwhisk.kubernetes.user-pod-node-affinity.enabled=false"
containerFactory:
impl: "kubernetes"
На тестовом кластере можно создать label, чтобы OpenWhisk знал на каких нодах можно запускать invoker:
kubectl label nodes --all openwhisk-role=invoker
Для установки чарта:
git clone https://github.com/apache/openwhisk-deploy-kube.git
helm install openwhisk ./openwhisk-deploy-kube/helm/openwhisk -n openwhisk --create-namespace -f mycluster.yaml
Проверяем как прошла установка:
kubectl get pods --namespace openwhisk
NAME READY STATUS RESTARTS AGE
openwhisk-alarmprovider-84cdc4c966-xjjwp 1/1 Running 0 3m59s
openwhisk-apigateway-858b4b948d-v626q 1/1 Running 0 3m59s
openwhisk-controller-0 1/1 Running 0 3m59s
openwhisk-couchdb-f879f9c4f-rcjxg 1/1 Running 0 3m59s
openwhisk-gen-certs-f6tj2 0/1 Completed 0 3m59s
openwhisk-init-couchdb-k2bqn 0/1 Completed 0 3m59s
openwhisk-install-packages-wrpvc 1/1 Running 0 3m59s
openwhisk-invoker-0 1/1 Running 0 3m59s
openwhisk-kafka-0 1/1 Running 0 3m59s
openwhisk-kafkaprovider-6fc76d7b45-64qnb 1/1 Running 0 3m58s
openwhisk-nginx-74545f49c7-vdnbm 1/1 Running 0 3m59s
openwhisk-redis-656c76cfff-ts59t 1/1 Running 0 3m59s
openwhisk-wskadmin 1/1 Running 0 3m59s
openwhisk-zookeeper-0 1/1 Running 0 3m59s
wskopenwhisk-invoker-00-1-prewarm-nodejs14 1/1 Running 0 88s
wskopenwhisk-invoker-00-2-prewarm-nodejs14 1/1 Running 0 88s
wskopenwhisk-invoker-00-3-whisksystem-invokerhealthtestaction0 1/1 Running 0 88s
Теперь можно приступить к установке пользовательских компонентов.
OpenWhisk CLI
Для работы с actions и triggers используется утилита командной строки wsk.
Для установка на Mac можно использовать homebrew:
brew install wsk
для Linux надо скачать бинарный файл:
wget https://github.com/apache/openwhisk-cli/releases/download/1.2.0/OpenWhisk_CLI-1.2.0-linux-amd64.tgz
tar -xzvf OpenWhisk_CLI-1.2.0-linux-amd64.tgz
mv wsk /usr/local/bin/
Для того, чтобы wsk мог связаться с кластером необходимо указать адрес apiserver, порт и auth.
По-умолчанию wsk берет их из файла ~/.wskprops:
cat ~/.wskprops
APIHOST=<IP_ADDRESS>:<PORT>
AUTH=26fd5813-72c1-489c-ad9b-997799698bce:WSIUsVihGStkvDvEsx5eHHYvFEowKQczDNOX8bFT1rat6q7JFgizQTsqXhaqY5wN
NAMESPACE=owuser
При установке в Kubernetes значение auth можно найти с помощью следующей команды:
kubectl -n openwhisk -ti exec openwhisk-wskadmin -- wskadmin user create owuser
26fd5813-72c1-489c-ad9b-997799698bce:WSIUsVihGStkvDvEsx5eHHYvFEowKQczDNOX8bFT1rat6q7JFgizQTsqXhaqY5wN
kubectl -n openwhisk -ti exec openwhisk-wskadmin -- wskadmin user whois 26fd5813-72c1-489c-ad9b-997799698bce:WSIUsVihGStkvDvEsx5eHHYvFEowKQczDNOX8bFT1rat6q7JFgizQTsqXhaqY5wN
subject: owuser
namespace: owuser
Теперь можно преступать к работе – например вывести список с сущностями в целевом пространстве имен:
wsk -i list
Entities in namespace: default
packages
actions
triggers
rules
Флаг -i
нужен для того, чтобы отключить проверку сертификата.
Test
Для того, чтобы убедится, что установка прошла успешно, давайте создадим hello world.
hello.js:
function main(params) {
msg = "Hello, " + params.name + " from " + params.place;
return { greeting: msg };
}
Создаем action:
wsk -i action create hellojs hello.js
ok: created action hellojs
С помощью invoke запускаем нашу функцию и получаем результат:
wsk -i action invoke hellojs --result
{
"greeting": "Hello, undefined from undefined"
}
Теперь с параметрами:
wsk -i action invoke hellojs --result --param name Anton --param place Habr
{
"greeting": "Hello, Anton from Habr"
}
End
PS. В следующей части сделаем полноценное приложение с фронтендом и бэкендом, а OpenWhisk будет запускать интересные экшены.